6fff87a1faa39432a9e11a7501354d81420d727e
[mw/milkymist.git] / software / demo / shell.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <console.h>
22 #include <uart.h>
23 #include <blockdev.h>
24 #include <fatfs.h>
25 #include <system.h>
26 #include <math.h>
27 #include <irq.h>
28 #include <board.h>
29 #include <hw/pfpu.h>
30 #include <hw/tmu.h>
31 #include <hw/sysctl.h>
32 #include <hw/gpio.h>
33 #include <hw/interrupts.h>
34 #include <hw/minimac.h>
35 #include <hw/bt656cap.h>
36 #include <hw/rc5.h>
37
38 #include <hal/vga.h>
39 #include <hal/snd.h>
40 #include <hal/tmu.h>
41 #include <hal/time.h>
42 #include <hal/brd.h>
43 #include <hal/vin.h>
44
45 #include "line.h"
46 #include "wave.h"
47 #include "rpipe.h"
48 #include "cpustats.h"
49 #include "memstats.h"
50 #include "shell.h"
51 #include "renderer.h"
52
53 #define NUMBER_OF_BYTES_ON_A_LINE 16
54 static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
55 {
56         char *data = (char *)ptr;
57         int line_bytes = 0, i = 0;
58
59         putsnonl("Memory dump:");
60         while(count > 0){
61                 line_bytes =
62                         (count > NUMBER_OF_BYTES_ON_A_LINE)?
63                                 NUMBER_OF_BYTES_ON_A_LINE : count;
64
65                 printf("\n0x%08x  ", addr);
66                 for(i=0;i<line_bytes;i++)
67                         printf("%02x ", *(unsigned char *)(data+i));
68
69                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
70                         printf("   ");
71
72                 printf(" ");
73
74                 for(i=0;i<line_bytes;i++) {
75                         if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
76                                 printf(".");
77                         else
78                                 printf("%c", *(data+i));
79                 }
80
81                 for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
82                         printf(" ");
83
84                 data += (char)line_bytes;
85                 count -= line_bytes;
86                 addr += line_bytes;
87         }
88         printf("\n");
89 }
90
91 static void mr(char *startaddr, char *len)
92 {
93         char *c;
94         unsigned *addr;
95         unsigned length;
96
97         if(*startaddr == 0) {
98                 printf("mr <address> [length]\n");
99                 return;
100         }
101         addr = (unsigned *)strtoul(startaddr, &c, 0);
102         if(*c != 0) {
103                 printf("incorrect address\n");
104                 return;
105         }
106         if(*len == 0) {
107                 length = 1;
108         } else {
109                 length = strtoul(len, &c, 0);
110                 if(*c != 0) {
111                         printf("incorrect length\n");
112                         return;
113                 }
114         }
115
116         dump_bytes(addr, length, (unsigned)addr);
117 }
118
119 static void mw(char *addr, char *value, char *count)
120 {
121         char *c;
122         unsigned *addr2;
123         unsigned value2;
124         unsigned count2;
125         unsigned i;
126
127         if((*addr == 0) || (*value == 0)) {
128                 printf("mw <address> <value>\n");
129                 return;
130         }
131         addr2 = (unsigned *)strtoul(addr, &c, 0);
132         if(*c != 0) {
133                 printf("incorrect address\n");
134                 return;
135         }
136         value2 = strtoul(value, &c, 0);
137         if(*c != 0) {
138                 printf("incorrect value\n");
139                 return;
140         }
141         if(*count == 0) {
142                 count2 = 1;
143         } else {
144                 count2 = strtoul(count, &c, 0);
145                 if(*c != 0) {
146                         printf("incorrect count\n");
147                         return;
148                 }
149         }
150         for(i=0;i<count2;i++) *addr2++ = value2;
151 }
152
153 static int lscb(const char *filename, const char *longname, void *param)
154 {
155         printf("%12s [%s]\n", filename, longname);
156         return 1;
157 }
158
159 static void ls()
160 {
161         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
162         fatfs_list_files(lscb, NULL);
163         fatfs_done();
164 }
165
166 static void edid()
167 {
168         char buf[256];
169
170         if(!vga_read_edid(buf)) {
171                 printf("Failed to read EDID\n");
172                 return;
173         }
174         dump_bytes((unsigned int *)buf, 256, 0);
175 }
176
177 static void render(const char *filename)
178 {
179         char buffer[8192];
180         int size;
181
182         if(*filename == 0) {
183                 printf("render <filename>\n");
184                 return;
185         }
186
187         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
188         if(!fatfs_load(filename, buffer, sizeof(buffer), &size)) return;
189         fatfs_done();
190         buffer[size] = 0;
191
192         renderer_start(buffer);
193 }
194
195 static void stats()
196 {
197         int hours, mins, secs;
198         struct timestamp ts;
199         unsigned int amat;
200         unsigned int netbw;
201         unsigned int occupancy;
202
203         time_get(&ts);
204         secs = ts.sec;
205         mins = secs/60;
206         secs -= mins*60;
207         hours = mins/60;
208         mins -= hours*60;
209         printf("Uptime: %02d:%02d:%02d  FPS: %d  CPU:%3d%%\n", hours, mins, secs,
210                 rpipe_fps(),
211                 cpustats_load());
212
213         amat = memstat_amat();
214         netbw = memstat_net_bandwidth();
215         occupancy = memstat_occupancy();
216         if(occupancy != 0) {
217                 printf("Net memory bandwidth : %d Mbps\n", netbw);
218                 printf("Memory bus occupancy : %d%%\n", occupancy);
219                 printf("Avg. mem. access time: %d.%02d cycles\n", amat/100, amat%100);
220         }
221 }
222
223 static void help()
224 {
225         puts("Milkymist demo firmware\n");
226         puts("Available commands:");
227         puts("ls         - list files on the memory card");
228         puts("render     - start rendering a patch");
229         puts("irender    - input patch equations interactively");
230         puts("stop       - stop renderer");
231         puts("stats      - print system stats");
232         puts("reboot     - system reset");
233 }
234
235 static void cpucfg()
236 {
237         unsigned long cpu_cfg;
238         
239         __asm__ volatile(
240                 "rcsr %0, cfg\n\t"
241                 : "=r"(cpu_cfg)
242         );
243         printf("CPU config word: 0x%08x\n", cpu_cfg);
244         printf("Options: ");
245         if(cpu_cfg & 0x001) printf("M ");
246         if(cpu_cfg & 0x002) printf("D ");
247         if(cpu_cfg & 0x004) printf("S ");
248         if(cpu_cfg & 0x008) printf("X ");
249         if(cpu_cfg & 0x010) printf("U ");
250         if(cpu_cfg & 0x020) printf("CC ");
251         if(cpu_cfg & 0x040) printf("DC ");
252         if(cpu_cfg & 0x080) printf("IC ");
253         if(cpu_cfg & 0x100) printf("G ");
254         if(cpu_cfg & 0x200) printf("H ");
255         if(cpu_cfg & 0x400) printf("R ");
256         if(cpu_cfg & 0x800) printf("J ");
257         printf("\n");
258         printf("IRQs: %d\n", (cpu_cfg >> 12) & 0x3F);
259         printf("Breakpoints: %d\n", (cpu_cfg >> 18) & 0x0F);
260         printf("Watchpoints: %d\n", (cpu_cfg >> 22) & 0x0F);
261         printf("CPU revision: %d\n", cpu_cfg >> 26);
262 }
263
264 static void loadpic(const char *filename)
265 {
266         int size;
267         
268         if(*filename == 0) {
269                 printf("loadpic <filename>\n");
270                 return;
271         }
272
273         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
274         if(!fatfs_load(filename, (void *)vga_backbuffer, vga_hres*vga_vres*2, &size)) return;
275         fatfs_done();
276
277         vga_swap_buffers();
278 }
279
280 static void checker()
281 {
282         int x, y;
283
284         for(y=0;y<vga_vres;y++)
285                 for(x=0;x<vga_hres;x++)
286                         if((x/4+y/4) & 1)
287                                 vga_backbuffer[y*vga_hres+x] = 0x0000;
288                         else
289                                 vga_backbuffer[y*vga_hres+x] = 0xffff;
290         vga_swap_buffers();
291 }
292
293 /*
294  * Low-level PFPU test, bypassing driver.
295  * This test should only be run when the driver task queue
296  * is empty.
297  */
298 static struct tmu_vertex mesh[128][128] __attribute__((aligned(8)));
299 static void pfputest()
300 {
301         unsigned int *pfpu_regs = (unsigned int *)CSR_PFPU_DREGBASE;
302         unsigned int *pfpu_code = (unsigned int *)CSR_PFPU_CODEBASE;
303         int x, y;
304         int timeout;
305         unsigned int oldmask;
306
307         /* Do not let the driver get our interrupt */
308         oldmask = irq_getmask();
309         irq_setmask(oldmask & (~IRQ_PFPU));
310
311         for(y=0;y<128;y++)
312                 for(x=0;x<128;x++) {
313                         mesh[y][x].x = 0xdeadbeef;
314                         mesh[y][x].y = 0xdeadbeef;
315                 }
316
317         CSR_PFPU_MESHBASE = (unsigned int)&mesh;
318         //CSR_PFPU_HMESHLAST = 6;
319         //CSR_PFPU_VMESHLAST = 9;
320
321         CSR_PFPU_HMESHLAST = 11;
322         CSR_PFPU_VMESHLAST = 9;
323
324         pfpu_regs[3] = 0x41300000;
325         pfpu_regs[4] = 0x41100000;
326
327         pfpu_code[ 0] = 0x00000300;
328         pfpu_code[ 1] = 0x00040300;
329         pfpu_code[ 2] = 0x00000000;
330         pfpu_code[ 3] = 0x00000003;
331         pfpu_code[ 4] = 0x00000004;
332         pfpu_code[ 5] = 0x000c2080;
333         pfpu_code[ 6] = 0x00000000;
334         pfpu_code[ 7] = 0x00000000;
335         pfpu_code[ 8] = 0x00000000;
336         pfpu_code[ 9] = 0x00000005;
337         pfpu_code[10] = 0x00142b80;
338
339         CSR_PFPU_CTL = PFPU_CTL_START;
340         printf("Waiting for PFPU...\n");
341         timeout = 30;
342         do {
343                 printf("%08x vertices:%d collisions:%d strays:%d last:%08x pc:%04x\n",
344                         CSR_PFPU_CTL, CSR_PFPU_VERTICES, CSR_PFPU_COLLISIONS, CSR_PFPU_STRAYWRITES, CSR_PFPU_LASTDMA, 4*CSR_PFPU_PC);
345         } while((timeout--) && (CSR_PFPU_CTL & PFPU_CTL_BUSY));
346         if(timeout > 0)
347                 printf("OK\n");
348         else
349                 printf("Timeout\n");
350
351         asm volatile( /* Invalidate Level-1 data cache */
352                 "wcsr DCC, r0\n"
353                 "nop\n"
354         );
355
356         printf("Result:\n");
357         for(y=0;y<10;y++) {
358                 for(x=0;x<12;x++)
359                         printf("%08x ", mesh[y][x].x);
360                 printf("\n");
361         }
362         printf("\n");
363         for(y=0;y<10;y++) {
364                 for(x=0;x<12;x++)
365                         printf("%08x ", mesh[y][x].y);
366                 printf("\n");
367         }
368
369         printf("Program:\n");
370         for(x=0;x<11;x++)
371                 printf("%08x ", pfpu_code[x]);
372         printf("\n");
373
374         CSR_PFPU_CTL = 0; /* Ack interrupt */
375         irq_ack(IRQ_PFPU);
376         irq_setmask(oldmask);
377 }
378
379 static void tmutest_callback(struct tmu_td *td)
380 {
381         int *complete;
382         complete = (int *)td->user;
383         *complete = 1;
384 }
385
386 static void tmutest()
387 {
388         int x, y;
389         static struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
390         struct tmu_td td;
391         volatile int complete;
392
393         for(y=0;y<=32;y++)
394                 for(x=0;x<=32;x++) {
395                         srcmesh[y][x].x = (10*x) << TMU_FIXEDPOINT_SHIFT;
396                         srcmesh[y][x].y = (7*y) << TMU_FIXEDPOINT_SHIFT;
397                 }
398
399         td.flags = 0;
400         td.hmeshlast = 32;
401         td.vmeshlast = 32;
402         td.brightness = TMU_BRIGHTNESS_MAX;
403         td.chromakey = 0;
404         td.vertices = &srcmesh[0][0];
405         td.texfbuf = vga_frontbuffer;
406         td.texhres = vga_hres;
407         td.texvres = vga_vres;
408         td.texhmask = TMU_MASK_FULL;
409         td.texvmask = TMU_MASK_FULL;
410         td.dstfbuf = vga_backbuffer;
411         td.dsthres = vga_hres;
412         td.dstvres = vga_vres;
413         td.dsthoffset = 0;
414         td.dstvoffset = 0;
415         td.dstsquarew = vga_hres/32;
416         td.dstsquareh = vga_vres/32;
417         td.alpha = TMU_ALPHA_MAX;
418         
419         td.callback = tmutest_callback;
420         td.user = (void *)&complete;
421
422         complete = 0;
423         flush_bridge_cache();
424         tmu_submit_task(&td);
425         while(!complete);
426         vga_swap_buffers();
427 }
428
429 static void tmubench()
430 {
431         unsigned int oldmask;
432         int i;
433         int zoom;
434         int x, y;
435         static struct tmu_vertex srcmesh[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
436         static unsigned short int texture[512*512] __attribute__((aligned(16)));
437         struct tmu_td td;
438         volatile int complete;
439         unsigned int t;
440         int hits, reqs;
441
442         /* Disable slowout */
443         oldmask = irq_getmask();
444         irq_setmask(oldmask & (~IRQ_TIMER1));
445         uart_force_sync(1);
446         
447         for(i=0;i<512*512;i++)
448                 texture[i] = i;
449         flush_bridge_cache();
450
451         for(zoom=0;zoom<16*64*2;zoom++) {
452                 for(y=0;y<=32;y++)
453                         for(x=0;x<=32;x++) {
454                                 srcmesh[y][x].x = zoom*x;
455                                 srcmesh[y][x].y = zoom*y;
456                         }
457
458                 td.flags = 0;
459                 td.hmeshlast = 32;
460                 td.vmeshlast = 32;
461                 td.brightness = TMU_BRIGHTNESS_MAX;
462                 td.chromakey = 0;
463                 td.vertices = &srcmesh[0][0];
464                 td.texfbuf = texture;
465                 td.texhres = 512;
466                 td.texvres = 512;
467                 td.texhmask = 0x7FFF;
468                 td.texvmask = 0x7FFF;
469                 td.dstfbuf = vga_backbuffer;
470                 td.dsthres = vga_hres;
471                 td.dstvres = vga_vres;
472                 td.dsthoffset = 0;
473                 td.dstvoffset = 0;
474                 td.dstsquarew = vga_hres/32;
475                 td.dstsquareh = vga_vres/32;
476                 td.alpha = TMU_ALPHA_MAX;
477
478                 td.callback = tmutest_callback;
479                 td.user = (void *)&complete;
480
481                 complete = 0;
482                 CSR_TIMER1_CONTROL = 0;
483                 CSR_TIMER1_COUNTER = 0;
484                 CSR_TIMER1_COMPARE = 0xffffffff;
485                 CSR_TIMER1_CONTROL = TIMER_ENABLE;
486                 tmu_submit_task(&td);
487                 while(!complete);
488                 t = CSR_TIMER1_COUNTER;
489                 hits = CSR_TMU_HIT_A + CSR_TMU_HIT_B + CSR_TMU_HIT_C + CSR_TMU_HIT_D;
490                 reqs = CSR_TMU_REQ_A + CSR_TMU_REQ_B + CSR_TMU_REQ_C + CSR_TMU_REQ_D;
491                 printf("%d,%d,%d\n", t, hits, reqs);
492                 vga_swap_buffers();
493         }
494
495         irq_ack(IRQ_TIMER1);
496         irq_setmask(oldmask);
497         uart_force_sync(0);
498 }
499
500 static short audio_buffer1[SND_MAX_NSAMPLES*2];
501 static short audio_buffer2[SND_MAX_NSAMPLES*2];
502 static short audio_buffer3[SND_MAX_NSAMPLES*2];
503 static short audio_buffer4[SND_MAX_NSAMPLES*2];
504
505 static void record_callback(short *buffer, void *user)
506 {
507         snd_play_refill(buffer);
508 }
509
510 static void play_callback(short *buffer, void *user)
511 {
512         snd_record_refill(buffer);
513 }
514
515 static void echo()
516 {
517         if(snd_play_active()) {
518                 snd_record_stop();
519                 snd_play_stop();
520                 printf("Digital Echo demo stopped\n");
521         } else {
522                 int i;
523
524                 snd_play_empty();
525                 for(i=0;i<AC97_MAX_DMASIZE/2;i++) {
526                         audio_buffer1[i] = 0;
527                         audio_buffer2[i] = 0;
528                 }
529                 snd_play_refill(audio_buffer1);
530                 snd_play_refill(audio_buffer2);
531                 snd_play_start(play_callback, SND_MAX_NSAMPLES, NULL);
532
533                 snd_record_empty();
534                 snd_record_refill(audio_buffer3);
535                 snd_record_refill(audio_buffer4);
536                 snd_record_start(record_callback, SND_MAX_NSAMPLES, NULL);
537                 printf("Digital Echo demo started\n");
538         }
539 }
540
541 static void readv(char *addr)
542 {
543         unsigned char a;
544         char *c;
545
546         if(*addr == 0) {
547                 printf("readv <address>\n");
548                 return;
549         }
550         a = strtoul(addr, &c, 0);
551         if(*c != 0) {
552                 printf("incorrect address\n");
553                 return;
554         }
555
556         printf("%02x\n", vin_read_reg(a));
557 }
558
559 static void writev(char *addr, char *value)
560 {
561         unsigned char a, v;
562         char *c;
563
564         if((*addr == 0)||(*value == 0)) {
565                 printf("writev <address> <value>\n");
566                 return;
567         }
568         a = strtoul(addr, &c, 0);
569         if(*c != 0) {
570                 printf("incorrect address\n");
571                 return;
572         }
573         v = strtoul(value, &c, 0);
574         if(*c != 0) {
575                 printf("incorrect value\n");
576                 return;
577         }
578
579         vin_write_reg(a, v);
580 }
581
582 static short vbuffer[720*288] __attribute__((aligned(32)));
583
584 static void testv()
585 {
586         
587         int x, y;
588         
589         irq_ack(IRQ_VIDEOIN);
590         CSR_BT656CAP_BASE = (unsigned int)vbuffer;
591         CSR_BT656CAP_FILTERSTATUS = BT656CAP_FILTERSTATUS_FIELD1;
592         printf("wait1 %d\n", CSR_TIMER0_COUNTER);
593         while(!irq_pending() && IRQ_VIDEOIN);
594         irq_ack(IRQ_VIDEOIN);
595         printf("wait2 %d\n", CSR_TIMER0_COUNTER);
596         while(!irq_pending() && IRQ_VIDEOIN);
597         irq_ack(IRQ_VIDEOIN);
598         CSR_BT656CAP_FILTERSTATUS = 0;
599         printf("wait3 %d\n", CSR_TIMER0_COUNTER);
600         while(CSR_BT656CAP_FILTERSTATUS & BT656CAP_FILTERSTATUS_INFRAME);
601         printf("done %d\n", CSR_TIMER0_COUNTER);
602         printf("nbursts=%d/%d\n", CSR_BT656CAP_DONEBURSTS, CSR_BT656CAP_MAXBURSTS);
603         flush_bridge_cache();
604         for(y=0;y<288;y++)
605                 for(x=0;x<640;x++)
606                         vga_frontbuffer[640*y+x] = vbuffer[720*y+x];
607         flush_bridge_cache();
608 }
609
610 static void irtest()
611 {
612         unsigned int r;
613         
614         irq_ack(IRQ_IR);
615         while(!readchar_nonblock()) {
616                 if(irq_pending() & IRQ_IR) {
617                         r = CSR_RC5_RX;
618                         irq_ack(IRQ_IR);
619                         printf("%04x - fld:%d ctl:%d sys:%d cmd:%d\n", r,
620                                 (r & 0x1000) >> 12,
621                                 (r & 0x0800) >> 11,
622                                 (r & 0x07c0) >> 6,
623                                 r & 0x003f);
624                         
625                 }
626         }
627 }
628
629 static char *get_token(char **str)
630 {
631         char *c, *d;
632
633         c = (char *)strchr(*str, ' ');
634         if(c == NULL) {
635                 d = *str;
636                 *str = *str+strlen(*str);
637                 return d;
638         }
639         *c = 0;
640         d = *str;
641         *str = c+1;
642         return d;
643 }
644
645 static int irender;
646
647 static void do_command(char *c)
648 {
649         if(irender) {
650                 if(*c == 0) {
651                         irender = 0;
652                         renderer_idone();
653                 } else
654                         renderer_iinput(c);
655         } else {
656                 char *command, *param1, *param2, *param3;
657
658                 command = get_token(&c);
659                 param1 = get_token(&c);
660                 param2 = get_token(&c);
661                 param3 = get_token(&c);
662
663                 if(strcmp(command, "mr") == 0) mr(param1, param2);
664                 else if(strcmp(command, "mw") == 0) mw(param1, param2, param3);
665                 else if(strcmp(command, "ls") == 0) ls();
666                 else if(strcmp(command, "flush") == 0) flush_bridge_cache();
667                 else if(strcmp(command, "edid") == 0) edid();
668                 else if(strcmp(command, "render") == 0) render(param1);
669                 else if(strcmp(command, "irender") == 0) {
670                         renderer_istart();
671                         irender = 1;
672                 } else if(strcmp(command, "stop") == 0) renderer_stop();
673                 else if(strcmp(command, "stats") == 0) stats();
674                 else if(strcmp(command, "reboot") == 0) reboot();
675                 else if(strcmp(command, "help") == 0) help();
676
677                 /* Test functions and hacks */
678                 else if(strcmp(command, "cpucfg") == 0) cpucfg();
679                 else if(strcmp(command, "loadpic") == 0) loadpic(param1);
680                 else if(strcmp(command, "checker") == 0) checker();
681                 else if(strcmp(command, "pfputest") == 0) pfputest();
682                 else if(strcmp(command, "tmutest") == 0) tmutest();
683                 else if(strcmp(command, "tmubench") == 0) tmubench();
684                 else if(strcmp(command, "echo") == 0) echo();
685                 else if(strcmp(command, "testv") == 0) testv();
686                 else if(strcmp(command, "readv") == 0) readv(param1);
687                 else if(strcmp(command, "writev") == 0) writev(param1, param2);
688                 else if(strcmp(command, "irtest") == 0) irtest();
689
690                 else if(strcmp(command, "") != 0) printf("Command not found: '%s'\n", command);
691         }
692 }
693
694 static char command_buffer[512];
695 static unsigned int command_index;
696
697 static void prompt()
698 {
699         if(irender)
700                 putsnonl("\e[1mpatch% \e[0m");
701         else
702                 putsnonl("\e[1m% \e[0m");
703 }
704
705 void shell_init()
706 {
707         prompt();
708         command_index = 0;
709         irender = 0;
710 }
711
712 void shell_input(char c)
713 {
714         cpustats_enter();
715         switch(c) {
716                 case 0x7f:
717                 case 0x08:
718                         if(command_index > 0) {
719                                 command_index--;
720                                 putsnonl("\x08 \x08");
721                         }
722                         break;
723                 case '\r':
724                 case '\n':
725                         command_buffer[command_index] = 0x00;
726                         putsnonl("\n");
727                         command_index = 0;
728                         do_command(command_buffer);
729                         prompt();
730                         break;
731                 default:
732                         if(command_index < (sizeof(command_buffer)-1)) {
733                                 writechar(c);
734                                 command_buffer[command_index] = c;
735                                 command_index++;
736                         }
737                         break;
738         }
739         cpustats_leave();
740 }