Enable USBGecko output in the exception handler
[libogc.git] / libogc / console.c
blobb4f73391a96d61cc71f3635bf20b1eece09f954e
1 #include <stdlib.h>
2 #include <string.h>
3 #include <reent.h>
4 #include <errno.h>
5 #include <unistd.h>
7 #include "asm.h"
8 #include "processor.h"
9 #include "color.h"
10 #include "cache.h"
11 #include "video.h"
12 #include "system.h"
14 #include "console.h"
15 #include "consol.h"
16 #include "usbgecko.h"
18 #include <stdio.h>
19 #include <sys/iosupport.h>
21 static ssize_t __console_write(struct _reent *r,int fd,const char *ptr,size_t len);
22 static ssize_t __gecko_read(struct _reent *r, int fd, char *ptr, size_t len);
24 static const devoptab_t dotab_stdio = {
25 "stdout", // device name
26 0, // size of file structure
27 NULL, // device open
28 NULL, // device close
29 __console_write, // device write
30 __gecko_read, // device read
31 NULL, // device seek
32 NULL, // device fstat
33 NULL, // device stat
34 NULL, // device link
35 NULL, // device unlink
36 NULL, // device chdir
37 NULL, // device rename
38 NULL, // device mkdir
39 0, // dirStateSize
40 NULL, // device diropen_r
41 NULL, // device dirreset_r
42 NULL, // device dirnext_r
43 NULL, // device dirclose_r
44 NULL, // device statvfs_r
45 NULL, // device ftrunctate_r
46 NULL, // device fsync_r
47 NULL, // deviceData;
50 //color table
51 static const unsigned int color_table[] =
53 0x00800080, // 30 normal black
54 0x246A24BE, // 31 normal red
55 0x4856484B, // 32 normal green
56 0x6D416D8A, // 33 normal yellow
57 0x0DBE0D75, // 34 normal blue
58 0x32A932B4, // 35 normal magenta
59 0x56955641, // 36 normal cyan
60 0xC580C580, // 37 normal white
61 0x7B807B80, // 30 bright black
62 0x4C544CFF, // 31 bright red
63 0x95299512, // 32 bright green
64 0xE200E294, // 33 bright yellow
65 0x1CFF1C6B, // 34 bright blue
66 0x69D669ED, // 35 bright magenta
67 0xB2ABB200, // 36 bright cyan
68 0xFF80FF80, // 37 bright white
71 static u32 do_xfb_copy = FALSE;
72 static struct _console_data_s stdcon;
73 static struct _console_data_s *curr_con = NULL;
74 static void *_console_buffer = NULL;
76 static s32 __gecko_status = -1;
77 static u32 __gecko_safe = 0;
79 extern u8 console_font_8x16[];
81 static void __console_vipostcb(u32 retraceCnt)
83 u32 ycnt,xcnt, fb_stride;
84 u32 *fb,*ptr;
86 do_xfb_copy = TRUE;
88 ptr = curr_con->destbuffer;
89 fb = VIDEO_GetCurrentFramebuffer()+(curr_con->target_y*curr_con->tgt_stride) + curr_con->target_x*VI_DISPLAY_PIX_SZ;
90 fb_stride = curr_con->tgt_stride/4 - (curr_con->con_xres/VI_DISPLAY_PIX_SZ);
92 for(ycnt=curr_con->con_yres;ycnt>0;ycnt--)
94 for(xcnt=curr_con->con_xres;xcnt>0;xcnt-=VI_DISPLAY_PIX_SZ)
96 *fb++ = *ptr++;
98 fb += fb_stride;
101 do_xfb_copy = FALSE;
104 static void __console_drawc(int c)
106 console_data_s *con;
107 int ay;
108 unsigned int *ptr;
109 unsigned char *pbits;
110 unsigned char bits;
111 unsigned int color;
112 unsigned int fgcolor, bgcolor;
113 unsigned int nextline;
115 if(do_xfb_copy==TRUE) return;
116 if(!curr_con) return;
117 con = curr_con;
119 ptr = (unsigned int*)(con->destbuffer + ( con->con_stride * con->cursor_row * FONT_YSIZE ) + ((con->cursor_col * FONT_XSIZE / 2) * 4));
120 pbits = &con->font[c * FONT_YSIZE];
121 nextline = con->con_stride/4 - 4;
122 fgcolor = con->foreground;
123 bgcolor = con->background;
125 for (ay = 0; ay < FONT_YSIZE; ay++)
127 /* hard coded loop unrolling ! */
128 /* this depends on FONT_XSIZE = 8*/
129 #if FONT_XSIZE == 8
130 bits = *pbits++;
132 /* bits 1 & 2 */
133 if ( bits & 0x80)
134 color = fgcolor & 0xFFFF00FF;
135 else
136 color = bgcolor & 0xFFFF00FF;
137 if (bits & 0x40)
138 color |= fgcolor & 0x0000FF00;
139 else
140 color |= bgcolor & 0x0000FF00;
141 *ptr++ = color;
143 /* bits 3 & 4 */
144 if ( bits & 0x20)
145 color = fgcolor & 0xFFFF00FF;
146 else
147 color = bgcolor & 0xFFFF00FF;
148 if (bits & 0x10)
149 color |= fgcolor & 0x0000FF00;
150 else
151 color |= bgcolor & 0x0000FF00;
152 *ptr++ = color;
154 /* bits 5 & 6 */
155 if ( bits & 0x08)
156 color = fgcolor & 0xFFFF00FF;
157 else
158 color = bgcolor & 0xFFFF00FF;
159 if (bits & 0x04)
160 color |= fgcolor & 0x0000FF00;
161 else
162 color |= bgcolor & 0x0000FF00;
163 *ptr++ = color;
165 /* bits 7 & 8 */
166 if ( bits & 0x02)
167 color = fgcolor & 0xFFFF00FF;
168 else
169 color = bgcolor & 0xFFFF00FF;
170 if (bits & 0x01)
171 color |= fgcolor & 0x0000FF00;
172 else
173 color |= bgcolor & 0x0000FF00;
174 *ptr++ = color;
176 /* next line */
177 ptr += nextline;
178 #else
179 #endif
183 static void __console_clear_line( int line, int from, int to ) {
184 console_data_s *con;
185 unsigned int c;
186 unsigned int *p;
187 unsigned int x_pixels;
188 unsigned int px_per_col = FONT_XSIZE/2;
189 unsigned int line_height = FONT_YSIZE;
190 unsigned int line_width;
192 if( !(con = curr_con) ) return;
193 // For some reason there are xres/2 pixels per screen width
194 x_pixels = con->con_xres / 2;
196 line_width = (to - from)*px_per_col;
197 p = (unsigned int*)con->destbuffer;
199 // Move pointer to the current line and column offset
200 p += line*(FONT_YSIZE*x_pixels) + from*px_per_col;
202 // Clears 1 line of pixels at a time, line_height times
203 while( line_height-- ) {
204 c = line_width;
205 while( c-- )
206 *p++ = con->background;
207 p -= line_width;
208 p += x_pixels;
212 static void __console_clear(void)
214 console_data_s *con;
215 unsigned int c;
216 unsigned int *p;
218 if( !(con = curr_con) ) return;
220 c = (con->con_xres*con->con_yres)/2;
221 p = (unsigned int*)con->destbuffer;
223 while(c--)
224 *p++ = con->background;
226 con->cursor_row = 0;
227 con->cursor_col = 0;
228 con->saved_row = 0;
229 con->saved_col = 0;
232 static void __console_clear_from_cursor() {
233 console_data_s *con;
234 int cur_row;
236 if( !(con = curr_con) ) return;
237 cur_row = con->cursor_row;
239 __console_clear_line( cur_row, con->cursor_col, con->con_cols );
241 while( cur_row++ < con->con_rows )
242 __console_clear_line( cur_row, 0, con->con_cols );
246 static void __console_clear_to_cursor() {
247 console_data_s *con;
248 int cur_row;
250 if( !(con = curr_con) ) return;
251 cur_row = con->cursor_row;
253 __console_clear_line( cur_row, 0, con->cursor_col );
255 while( cur_row-- )
256 __console_clear_line( cur_row, 0, con->con_cols );
259 void __console_init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride)
261 unsigned int level;
262 console_data_s *con = &stdcon;
264 _CPU_ISR_Disable(level);
266 con->destbuffer = framebuffer;
267 con->con_xres = xres;
268 con->con_yres = yres;
269 con->con_cols = xres / FONT_XSIZE;
270 con->con_rows = yres / FONT_YSIZE;
271 con->con_stride = con->tgt_stride = stride;
272 con->target_x = xstart;
273 con->target_y = ystart;
275 con->font = console_font_8x16;
277 con->foreground = COLOR_WHITE;
278 con->background = COLOR_BLACK;
280 curr_con = con;
282 __console_clear();
284 devoptab_list[STD_OUT] = &dotab_stdio;
285 devoptab_list[STD_ERR] = &dotab_stdio;
286 _CPU_ISR_Restore(level);
288 setvbuf(stdout, NULL , _IONBF, 0);
289 setvbuf(stderr, NULL , _IONBF, 0);
292 void __console_init_ex(void *conbuffer,int tgt_xstart,int tgt_ystart,int tgt_stride,int con_xres,int con_yres,int con_stride)
294 unsigned int level;
295 console_data_s *con = &stdcon;
297 _CPU_ISR_Disable(level);
299 con->destbuffer = conbuffer;
300 con->target_x = tgt_xstart;
301 con->target_y = tgt_ystart;
302 con->con_xres = con_xres;
303 con->con_yres = con_yres;
304 con->tgt_stride = tgt_stride;
305 con->con_stride = con_stride;
306 con->con_cols = con_xres / FONT_XSIZE;
307 con->con_rows = con_yres / FONT_YSIZE;
308 con->cursor_row = 0;
309 con->cursor_col = 0;
310 con->saved_row = 0;
311 con->saved_col = 0;
313 con->font = console_font_8x16;
315 con->foreground = COLOR_WHITE;
316 con->background = COLOR_BLACK;
318 curr_con = con;
320 __console_clear();
322 devoptab_list[STD_OUT] = &dotab_stdio;
323 devoptab_list[STD_ERR] = &dotab_stdio;
325 VIDEO_SetPostRetraceCallback(__console_vipostcb);
327 _CPU_ISR_Restore(level);
329 setvbuf(stdout, NULL , _IONBF, 0);
330 setvbuf(stderr, NULL , _IONBF, 0);
333 static int __console_parse_escsequence(char *pchr)
335 char chr;
336 console_data_s *con;
337 int i;
338 int parameters[3];
339 int para;
341 if(!curr_con) return -1;
342 con = curr_con;
344 /* set default value */
345 para = 0;
346 parameters[0] = 0;
347 parameters[1] = 0;
348 parameters[2] = 0;
350 /* scan parameters */
351 i = 0;
352 chr = *pchr;
353 while( (para < 3) && (chr >= '0') && (chr <= '9') )
355 while( (chr >= '0') && (chr <= '9') )
357 /* parse parameter */
358 parameters[para] *= 10;
359 parameters[para] += chr - '0';
360 pchr++;
361 i++;
362 chr = *pchr;
364 para++;
366 if( *pchr == ';' )
368 /* skip parameter delimiter */
369 pchr++;
370 i++;
372 chr = *pchr;
375 /* get final character */
376 chr = *pchr++;
377 i++;
378 switch(chr)
380 /////////////////////////////////////////
381 // Cursor directional movement
382 /////////////////////////////////////////
383 case 'A':
385 curr_con->cursor_row -= parameters[0];
386 if(curr_con->cursor_row < 0) curr_con->cursor_row = 0;
387 break;
389 case 'B':
391 curr_con->cursor_row += parameters[0];
392 if(curr_con->cursor_row >= curr_con->con_rows) curr_con->cursor_row = curr_con->con_rows - 1;
393 break;
395 case 'C':
397 curr_con->cursor_col += parameters[0];
398 if(curr_con->cursor_col >= curr_con->con_cols) curr_con->cursor_col = curr_con->con_cols - 1;
399 break;
401 case 'D':
403 curr_con->cursor_col -= parameters[0];
404 if(curr_con->cursor_col < 0) curr_con->cursor_col = 0;
405 break;
407 /////////////////////////////////////////
408 // Cursor position movement
409 /////////////////////////////////////////
410 case 'H':
411 case 'f':
413 curr_con->cursor_col = parameters[1];
414 curr_con->cursor_row = parameters[0];
415 if(curr_con->cursor_row >= curr_con->con_rows) curr_con->cursor_row = curr_con->con_rows - 1;
416 if(curr_con->cursor_col >= curr_con->con_cols) curr_con->cursor_col = curr_con->con_cols - 1;
417 break;
419 /////////////////////////////////////////
420 // Screen clear
421 /////////////////////////////////////////
422 case 'J':
424 if( parameters[0] == 0 )
425 __console_clear_from_cursor();
426 if( parameters[0] == 1 )
427 __console_clear_to_cursor();
428 if( parameters[0] == 2 )
429 __console_clear();
431 break;
433 /////////////////////////////////////////
434 // Line clear
435 /////////////////////////////////////////
436 case 'K':
438 if( parameters[0] == 0 )
439 __console_clear_line( curr_con->cursor_row, curr_con->cursor_col, curr_con->con_cols );
440 if( parameters[0] == 1 )
441 __console_clear_line( curr_con->cursor_row, 0, curr_con->cursor_col );
442 if( parameters[0] == 2 )
443 __console_clear_line( curr_con->cursor_row, 0, curr_con->con_cols);
445 break;
447 /////////////////////////////////////////
448 // Save cursor position
449 /////////////////////////////////////////
450 case 's':
452 con->saved_col = con->cursor_col;
453 con->saved_row = con->cursor_row;
454 break;
456 /////////////////////////////////////////
457 // Load cursor position
458 /////////////////////////////////////////
459 case 'u':
460 con->cursor_col = con->saved_col;
461 con->cursor_row = con->saved_row;
462 break;
463 /////////////////////////////////////////
464 // SGR Select Graphic Rendition
465 /////////////////////////////////////////
466 case 'm':
468 // handle 30-37,39 for foreground color changes
469 if( (parameters[0] >= 30) && (parameters[0] <= 39) )
471 parameters[0] -= 30;
473 //39 is the reset code
474 if(parameters[0] == 9){
475 parameters[0] = 15;
477 else if(parameters[0] > 7){
478 parameters[0] = 7;
481 if(parameters[1] == 1)
483 // Intensity: Bold makes color bright
484 parameters[0] += 8;
486 con->foreground = color_table[parameters[0]];
488 // handle 40-47 for background color changes
489 else if( (parameters[0] >= 40) && (parameters[0] <= 47) )
491 parameters[0] -= 40;
493 if(parameters[1] == 1)
495 // Intensity: Bold makes color bright
496 parameters[0] += 8;
498 con->background = color_table[parameters[0]];
500 break;
504 return(i);
507 static ssize_t __console_write(struct _reent *r,int fd,const char *ptr,size_t len)
509 size_t i = 0;
510 char *tmp = (char*)ptr;
511 console_data_s *con;
512 char chr;
514 if(__gecko_status>=0) {
515 if(__gecko_safe)
516 usb_sendbuffer_safe(__gecko_status,ptr,len);
517 else
518 usb_sendbuffer(__gecko_status,ptr,len);
521 if(!curr_con) return -1;
522 con = curr_con;
523 if(!tmp || len<=0) return -1;
525 i = 0;
526 while(*tmp!='\0' && i<len)
528 chr = *tmp++;
529 i++;
530 if ( (chr == 0x1b) && (*tmp == '[') )
532 /* escape sequence found */
533 int k;
535 tmp++;
536 i++;
537 k = __console_parse_escsequence(tmp);
538 tmp += k;
539 i += k;
541 else
543 switch(chr)
545 case '\n':
546 con->cursor_row++;
547 con->cursor_col = 0;
548 break;
549 case '\r':
550 con->cursor_col = 0;
551 break;
552 case '\b':
553 con->cursor_col--;
554 if(con->cursor_col < 0)
556 con->cursor_col = 0;
558 break;
559 case '\f':
560 con->cursor_row++;
561 break;
562 case '\t':
563 if(con->cursor_col%TAB_SIZE) con->cursor_col += (con->cursor_col%TAB_SIZE);
564 else con->cursor_col += TAB_SIZE;
565 break;
566 default:
567 __console_drawc(chr);
568 con->cursor_col++;
570 if( con->cursor_col >= con->con_cols)
572 /* if right border reached wrap around */
573 con->cursor_row++;
574 con->cursor_col = 0;
579 if( con->cursor_row >= con->con_rows)
581 /* if bottom border reached scroll */
582 memcpy(con->destbuffer,
583 con->destbuffer+con->con_stride*(FONT_YSIZE*FONT_YFACTOR+FONT_YGAP),
584 con->con_stride*con->con_yres-FONT_YSIZE);
586 unsigned int cnt = (con->con_stride * (FONT_YSIZE * FONT_YFACTOR + FONT_YGAP))/4;
587 unsigned int *ptr = (unsigned int*)(con->destbuffer + con->con_stride * (con->con_yres - FONT_YSIZE));
588 while(cnt--)
589 *ptr++ = con->background;
590 con->cursor_row--;
594 return i;
597 void CON_Init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride)
599 __console_init(framebuffer,xstart,ystart,xres,yres,stride);
602 s32 CON_InitEx(GXRModeObj *rmode, s32 conXOrigin,s32 conYOrigin,s32 conWidth,s32 conHeight)
604 VIDEO_SetPostRetraceCallback(NULL);
605 if(_console_buffer)
606 free(_console_buffer);
608 _console_buffer = malloc(conWidth*conHeight*VI_DISPLAY_PIX_SZ);
609 if(!_console_buffer) return -1;
611 __console_init_ex(_console_buffer,conXOrigin,conYOrigin,rmode->fbWidth*VI_DISPLAY_PIX_SZ,conWidth,conHeight,conWidth*VI_DISPLAY_PIX_SZ);
613 return 0;
616 void CON_GetMetrics(int *cols, int *rows)
618 if(curr_con) {
619 *cols = curr_con->con_cols;
620 *rows = curr_con->con_rows;
624 void CON_GetPosition(int *col, int *row)
626 if(curr_con) {
627 *col = curr_con->cursor_col;
628 *row = curr_con->cursor_row;
632 static ssize_t __gecko_read(struct _reent *r, int fd, char *ptr, size_t len) {
633 char *p;
634 size_t l, c;
636 if(__gecko_status < 0) {
637 r->_errno = EINVAL;
638 return -1;
641 p = ptr;
642 l = len;
643 while (l) {
644 if(__gecko_safe)
645 c = usb_recvbuffer_safe(__gecko_status, p, l);
646 else
647 c = usb_recvbuffer(__gecko_status, p, l);
649 p += c;
650 l -= c;
652 if (c < 1)
653 usleep(50 * 1000);
656 return len - l;
659 void CON_EnableGecko(int channel,int safe)
661 if(channel && (channel>1 || !usb_isgeckoalive(channel))) channel = -1;
663 __gecko_status = channel;
664 __gecko_safe = safe;
666 if(__gecko_status!=-1) {
667 devoptab_list[STD_IN] = &dotab_stdio;
668 devoptab_list[STD_OUT] = &dotab_stdio;
669 devoptab_list[STD_ERR] = &dotab_stdio;
671 setvbuf(stdin, NULL , _IONBF, 0);
673 // line buffered output for threaded apps when only using the usbgecko
674 if(!curr_con) {
675 setvbuf(stdout, NULL, _IOLBF, 0);
676 setvbuf(stderr, NULL, _IOLBF, 0);