Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: serial.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | #include "serial_4v.h" | |
22 | ||
23 | ||
24 | static const char *serial_4v_help = "\ | |
25 | tip based SAM N2 console module (for Legion's virtual console device)\n\ | |
26 | Sysconf format is :\n\ | |
27 | sysconf serial_4v <instance_name> base=<start_addr> size=<map size> [log[=<filename>]] [pop] [fg=<color>] [bg=<color>] [font=<font>] [dnkxoe] [raw] [-a] [T=<title>] [e=<command>]\n\ | |
28 | 'base' is the start address of memory mapped address, of the device CSRs\n\ | |
29 | 'size' is the size of the CSR space\n\ | |
30 | 'log' enables logging of console o/p to a file. The default log file is <instance_name>.log\n\ | |
31 | 'raw' - optional boolean parameter, if specified enables unbuffered logging of console o/p, if logging is enabled\n\ | |
32 | The log file is opened in append mode if -a is not specified\n\ | |
33 | 'pop' is boolean arg which if present will open an xterm window for console o/p\n\ | |
34 | 'e, e, command\' is optional argument to set command instead of /bin/tip\n\ | |
35 | 'T, T, title\' is optional argument to set xterm title instead of instance name\n\ | |
36 | 'fg, bg, font, T' are optional arguments to set foreground, background and font of the xterm window\n\ | |
37 | 'dnkxoe' - do not kill xterm on exit, default - window killed\n\ | |
38 | For UI help type <instance name>\n\ | |
39 | For module specific info type \"modinfo <instance name>\""; | |
40 | ||
41 | Module *Module::create(const char *_modname, const char *_instance_name){ | |
42 | return new serial4v(_modname, _instance_name); | |
43 | } | |
44 | const char * serial4v::get_help(){ | |
45 | return Module::get_help_string(); | |
46 | } | |
47 | ||
48 | const char * | |
49 | Module::get_help_string(){ | |
50 | return serial_4v_help; | |
51 | } | |
52 | ||
53 | serial4v::serial4v(const char * modname,const char * instance_name) | |
54 | : | |
55 | Module(modname,instance_name), | |
56 | title(0) | |
57 | { | |
58 | log = false; | |
59 | start_pa = -1; | |
60 | end_pa = 0; | |
61 | size = 0; | |
62 | logfile = 0; | |
63 | pop = false; | |
64 | portConName = 0; | |
65 | portCon = -1; | |
66 | pthread_mutex_init(&mutty,0); | |
67 | scratch = 0; | |
68 | line_status = DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD; | |
69 | in.count = in.head = in.tail = 0; | |
70 | in.size = MaxBuf; | |
71 | ||
72 | font = strdup("-dec-terminal-medium-r-normal-*-14-140-*-75-c-80-iso8859-1"); | |
73 | bg = strdup("grey90"); | |
74 | fg = strdup("black"); | |
75 | exec = strdup("/bin/tip"); | |
76 | kill_xterm_on_exit = true; | |
77 | raw =false; | |
78 | append = true; | |
79 | ||
80 | mmi_register_instance_cmd(getInstance(),serial_4v_help,serial_4v_ui_cmd); | |
81 | } | |
82 | ||
83 | bool serial4v::parse_arg(const char * arg){ | |
84 | if(!strcmp("pop",arg)){ | |
85 | pop = true; | |
86 | return true; | |
87 | }else if(!strcmp("dnkxoe",arg)){ | |
88 | kill_xterm_on_exit = false; | |
89 | return true; | |
90 | }else if(!strcmp("raw",arg)){ | |
91 | raw = true; | |
92 | return true; | |
93 | }else if(!strcmp("-a",arg)){ | |
94 | append = false; | |
95 | return true; | |
96 | }else if(!strncmp("log",arg,3)){ | |
97 | log = true; | |
98 | if(arg[3] == '='){ | |
99 | logfile = strdup(arg+4); | |
100 | debug_more("%s: console log enabled. Log file %s",getName(),logfile); | |
101 | }else | |
102 | debug_more("%s: console log enabled. Log file %s.log",getName(),getName()); | |
103 | return true; | |
104 | }else if(argval("base",arg,&start_pa)){ | |
105 | debug_more("%s: base_pa %llx\n",getName(), start_pa); | |
106 | return true; | |
107 | }else if(argval("size",arg,&size)){ | |
108 | debug_more("%s: size %llx, end_pa %llx\n",getName(), size, start_pa + size - 1); | |
109 | return true; | |
110 | }else if(argval("bg",arg,&bg)){ | |
111 | debug_more("%s: bg - %s\n",getName(), bg); | |
112 | return true; | |
113 | }else if(argval("fg",arg,&fg)){ | |
114 | debug_more("%s: fg - %s\n",getName(), fg); | |
115 | return true; | |
116 | }else if(argval("font",arg,&font)){ | |
117 | debug_more("%s: font - %s\n",getName(), font); | |
118 | return true; | |
119 | }else if(argval("T",arg,&title)){ | |
120 | debug_more("%s: T - %s\n",getName(), title); | |
121 | return true; | |
122 | }else if(argval("e",arg,&exec)){ | |
123 | debug_more("%s: e - %s\n",getName(), exec); | |
124 | return true; | |
125 | }else | |
126 | return false; | |
127 | } | |
128 | ||
129 | ||
130 | bool serial4v::check_args(){ | |
131 | ||
132 | if(start_pa == -1){ | |
133 | debug_err("%s:must specify start address\n",getName()); | |
134 | return false; | |
135 | }else if(size == 0){ | |
136 | debug_err("%s:must specify size of address mapping\n",getName()); | |
137 | return false; | |
138 | }else | |
139 | return true; | |
140 | } | |
141 | ||
142 | void serial4v::init_done(){ | |
143 | ||
144 | if (!title) | |
145 | { | |
146 | title = (const char*)malloc(strlen(getName() + 1)); | |
147 | strcpy((char*)title,getName()); | |
148 | } | |
149 | Console = new console(); | |
150 | ||
151 | if(fg) Console->setFg(fg); | |
152 | if(bg) Console->setBg(bg); | |
153 | if(font) Console->setFont(font); | |
154 | if(exec) Console->setExec(exec); | |
155 | if(title) Console->setTitle(title); | |
156 | ||
157 | portCon = Console->getTerminal((char*)title,10000,getConsoleIp, this, &portConName, pop); | |
158 | fprintf(stderr,"%s : to connect to console: tip %s\n",getName(),portConName); | |
159 | Console->setId(getName()); | |
160 | ||
161 | ||
162 | ||
163 | if(log){ | |
164 | if(!logfile){ | |
165 | char * logname = (char*)malloc( strlen( getName() ) + strlen(".log") + 1 ); | |
166 | strcpy(logname,getName()); | |
167 | strcat(logname,".log"); | |
168 | logfile = strdup(logname); | |
169 | free(logname); | |
170 | } | |
171 | Console->log(portCon,true,logfile,raw,append); | |
172 | } | |
173 | if(mmi_map_physio(start_pa, size, (void *) this, serial4v_physio_access) != 0) { | |
174 | debug_err("%s fatal error: unaable to map IO space\n"); | |
175 | exit(1); | |
176 | } | |
177 | } | |
178 | ||
179 | ||
180 | void serial4v::getConsoleIp(void *data,unsigned char *ip, int port){ | |
181 | serial4v * self = (serial4v *)data; | |
182 | ||
183 | pthread_mutex_lock(&self->mutty); | |
184 | ||
185 | if(self->in.count < self->in.size){ | |
186 | self->in.bufp[self->in.tail] = *ip; | |
187 | self->in.tail++; | |
188 | if(self->in.tail >= self->in.size) | |
189 | self->in.tail = 0; | |
190 | self->in.count++; | |
191 | self->line_status |= DS_LSTAT_DATA_READY; | |
192 | }else{ | |
193 | if(!(self->line_status & DS_LSTAT_OVERRUN)) | |
194 | self->debug_err("%s: buffer overrun",self->getName()); | |
195 | self->line_status |= DS_LSTAT_OVERRUN; | |
196 | } | |
197 | pthread_mutex_unlock(&self->mutty); | |
198 | } | |
199 | ||
200 | ||
201 | ||
202 | void serial4v::serial4v_ld (uint64_t paddr, uint64_t *buf, int size){ | |
203 | ds_reg_t reg; | |
204 | uint64_t val; | |
205 | ||
206 | reg = (ds_reg_t) (paddr & 0xfff) ; | |
207 | val = 0; | |
208 | switch (reg) { | |
209 | case DS_Input: | |
210 | pthread_mutex_lock(&mutty); | |
211 | if (in.count == 0) { | |
212 | val = 0; | |
213 | line_status &= ~DS_LSTAT_DATA_READY; | |
214 | }else{ | |
215 | val = in.bufp[in.head]; | |
216 | in.head ++; | |
217 | if (in.head >= in.size) | |
218 | in.head = 0; | |
219 | in.count --; | |
220 | if (in.count == 0) | |
221 | line_status &= ~DS_LSTAT_DATA_READY; | |
222 | } | |
223 | pthread_mutex_unlock(&mutty); | |
224 | break; | |
225 | case DS_IntEnable: | |
226 | break; | |
227 | case DS_IntIdent: | |
228 | break; | |
229 | case DS_LineCtrl: | |
230 | break; | |
231 | case DS_ModemCtrl: | |
232 | break; | |
233 | case DS_LineStatus: | |
234 | pthread_mutex_lock(&mutty); | |
235 | val = line_status; | |
236 | pthread_mutex_unlock(&mutty); | |
237 | break; | |
238 | case DS_ModemStatus: | |
239 | break; | |
240 | case DS_Scratch: | |
241 | scratch = val & 0xff; | |
242 | break; | |
243 | case DS_DivLo: | |
244 | break; | |
245 | case DS_DivHi: | |
246 | break; | |
247 | default: | |
248 | debug_err("%s: rd access to unimplemented register 0x%x\n",getName()); | |
249 | val = 0; | |
250 | break; | |
251 | } | |
252 | *buf = val; | |
253 | return; | |
254 | } | |
255 | ||
256 | ||
257 | void serial4v::serial4v_st(uint64_t pa, uint64_t *buf, int sz){ | |
258 | ds_reg_t reg; | |
259 | uint64_t val; | |
260 | reg = (ds_reg_t) (pa & 0xfff); | |
261 | val = *buf; | |
262 | ||
263 | assert(sz == 1); | |
264 | ||
265 | if (val > 0xff) | |
266 | debug_err("%s:writing 0x%llx to console. Truncate to 8 bits\n",getName()); | |
267 | ||
268 | val &= 0xff; | |
269 | ||
270 | switch (reg) { | |
271 | case DS_Output: | |
272 | { | |
273 | uint8_t chr = *buf; | |
274 | Console->writeTerminal(portCon, &chr, 1); | |
275 | break; | |
276 | } | |
277 | case DS_IntEnable: | |
278 | break; | |
279 | case DS_FIFOCtrl: | |
280 | break; | |
281 | case DS_LineCtrl: | |
282 | break; | |
283 | case DS_ModemCtrl: | |
284 | break; | |
285 | case DS_LineStatus: | |
286 | pthread_mutex_lock(&mutty); | |
287 | line_status = (val & 0xff) | DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD; | |
288 | pthread_mutex_unlock(&mutty); | |
289 | break; | |
290 | case DS_ModemStatus: | |
291 | break; | |
292 | case DS_Scratch: | |
293 | scratch = val & 0xff; | |
294 | break; | |
295 | case DS_DivLo: | |
296 | break; | |
297 | case DS_DivHi: | |
298 | break; | |
299 | default: | |
300 | debug_err("%s: wr access to unimplemented register 0x%x\n",getName()); | |
301 | break; | |
302 | } | |
303 | return; | |
304 | } | |
305 | ||
306 | ||
307 | int serial4v::serial4v_physio_access(uint32_t cpuid, void* obj, uint64_t paddr, | |
308 | mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask){ | |
309 | serial4v* s = (serial4v*) obj; | |
310 | ||
311 | if(wr) | |
312 | s->serial4v_st(paddr,buf,size); | |
313 | else | |
314 | s->serial4v_ld(paddr,buf,size); | |
315 | return 0; | |
316 | } | |
317 | ||
318 | int serial_4v_ui_cmd(void * obj, int argc, char * argv[]){ | |
319 | serial4v * i = (serial4v *)obj; | |
320 | i->handle_ui(argc, argv); | |
321 | return 0; | |
322 | } | |
323 | ||
324 | void serial4v::handle_ui(int argc, char * argv[]){ | |
325 | if(argc == 1){ | |
326 | ui_cmd_usage(); | |
327 | return; | |
328 | }else if(!strcmp(argv[1],"send")){ | |
329 | if(argv[2]){ | |
330 | const int bufSize = 1024 * 10; | |
331 | char buf[bufSize]; | |
332 | buf[0] = '\0'; | |
333 | // no error checking for command string to be longer than 10KB | |
334 | for(int i = 2; i < argc; i++){ | |
335 | strcat(buf,argv[i]); | |
336 | strcat(buf," "); | |
337 | } | |
338 | buf[strlen(buf) - 1] = '\n'; | |
339 | ||
340 | for(int i = 0; i < strlen(buf); i++) | |
341 | getConsoleIp((void*)this,(uint8_t *)(buf + i),-1); | |
342 | }else{ | |
343 | char buf[2]; | |
344 | buf[0] = '\n'; | |
345 | buf[1] = '\0'; | |
346 | for(int i = 0; i < strlen(buf); i++) | |
347 | getConsoleIp((void*)this,(uint8_t *)(buf + i),-1); | |
348 | } | |
349 | }else if(!strcmp(argv[1],"sendfile")){ | |
350 | FILE * fp; | |
351 | if(argv[2]){ | |
352 | fp = fopen(argv[2],"r"); | |
353 | if(fp){ | |
354 | uint8_t chr; | |
355 | while(fread(&chr,1,1,fp)) | |
356 | getConsoleIp((void*)this,&chr,-1); | |
357 | } | |
358 | else | |
359 | fprintf(stderr,"%s restore: error opening file <%s>\n",getName(),argv[2]); | |
360 | }else | |
361 | fprintf(stderr,"%s sendfile: no filename specified\n",getName()); | |
362 | }else if(!strcmp(argv[1],"dump")){ | |
363 | FILE * fp = stderr; | |
364 | if(argv[2]){ | |
365 | fp = fopen(argv[2],"w"); | |
366 | if(!fp){ | |
367 | fprintf(stderr,"%s dump: error opening file <%s>\n",getName(),argv[2]); | |
368 | fp = stderr; | |
369 | } | |
370 | } | |
371 | dump(fp); | |
372 | if(fp != stderr) | |
373 | fclose(fp); | |
374 | }else if(!strcmp(argv[1],"restore")){ | |
375 | FILE * fp; | |
376 | if(argv[2]){ | |
377 | fp = fopen(argv[2],"r"); | |
378 | if(fp){ | |
379 | restore(fp); | |
380 | fclose(fp); | |
381 | }else | |
382 | fprintf(stderr,"%s restore: error opening file <%s>\n",getName(),argv[2]); | |
383 | }else | |
384 | fprintf(stderr,"%s restore: no restore filename specified\n",getName()); | |
385 | }else if(!strcmp(argv[1],"debug")){ | |
386 | if(argv[2]){ | |
387 | debug_level = atoi(argv[2]); | |
388 | fprintf(stderr,"%s: set debug level to %d\n",getName(),debug_level); | |
389 | }else | |
390 | fprintf(stderr,"%s: current debug level %d\n",getName(),debug_level); | |
391 | }else if(!strcmp(argv[1],"pop")){ | |
392 | Console->pop_term(portCon); | |
393 | }else if(!strcmp(argv[1],"kill")){ | |
394 | Console->kill_term(portCon); | |
395 | }else if(!strcmp(argv[1],"fg")){ | |
396 | if(fg) free((void*)fg); | |
397 | if(argv[2]){ | |
398 | fg = strdup(argv[2]); | |
399 | Console->setFg(fg); | |
400 | }else | |
401 | fprintf(stderr," fg : %s\n", fg); | |
402 | }else if(!strcmp(argv[1],"bg")){ | |
403 | if(bg) free((void*)bg); | |
404 | if(argv[2]){ | |
405 | bg = strdup(argv[2]); | |
406 | Console->setBg(bg); | |
407 | }else | |
408 | fprintf(stderr," bg : %s\n", bg); | |
409 | }else if(!strcmp(argv[1],"font")){ | |
410 | if(font) free((void*)font); | |
411 | if(argv[2]){ | |
412 | font = strdup(argv[2]); | |
413 | Console->setFont(font); | |
414 | }else | |
415 | fprintf(stderr," font : %s\n", font); | |
416 | }else if(!strcmp(argv[1],"T")){ | |
417 | if(title) free((void*)title); | |
418 | if(argv[2]){ | |
419 | title = strdup(argv[2]); | |
420 | Console->setTitle(title); | |
421 | }else | |
422 | fprintf(stderr," title : %s\n", title); | |
423 | }else if(!strcmp(argv[1],"e")){ | |
424 | if(exec) free((void*)exec); | |
425 | if(argv[2]){ | |
426 | exec = strdup(argv[2]); | |
427 | Console->setExec(exec); | |
428 | }else | |
429 | fprintf(stderr," exec : %s\n", exec); | |
430 | }else | |
431 | debug_err("%s: unsupported UI command <%s>\n",getName(),argv[1]); | |
432 | return; | |
433 | } |