diff options
Diffstat (limited to 'src/kernel/chr_drv')
-rw-r--r-- | src/kernel/chr_drv/Makefile | 67 | ||||
-rw-r--r-- | src/kernel/chr_drv/console.c | 710 | ||||
-rw-r--r-- | src/kernel/chr_drv/kb.S | 588 | ||||
-rw-r--r-- | src/kernel/chr_drv/rs_io.s | 147 | ||||
-rw-r--r-- | src/kernel/chr_drv/serial.c | 59 | ||||
-rw-r--r-- | src/kernel/chr_drv/tty_io.c | 350 | ||||
-rw-r--r-- | src/kernel/chr_drv/tty_ioctl.c | 204 |
7 files changed, 2125 insertions, 0 deletions
diff --git a/src/kernel/chr_drv/Makefile b/src/kernel/chr_drv/Makefile new file mode 100644 index 0000000..3dd5449 --- /dev/null +++ b/src/kernel/chr_drv/Makefile | |||
@@ -0,0 +1,67 @@ | |||
1 | # | ||
2 | # Makefile for the FREAX-kernel character device drivers. | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | include ../../Makefile.header | ||
10 | |||
11 | CFLAGS += -I../../include | ||
12 | CPP += -I../../include | ||
13 | |||
14 | .c.s: | ||
15 | @$(CC) $(CFLAGS) \ | ||
16 | -S -o $*.s $< | ||
17 | .s.o: | ||
18 | @$(AS) -o $*.o $< | ||
19 | .c.o: | ||
20 | @$(CC) $(CFLAGS) \ | ||
21 | -c -o $*.o $< | ||
22 | |||
23 | OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o \ | ||
24 | tty_ioctl.o | ||
25 | |||
26 | chr_drv.a: $(OBJS) | ||
27 | @$(AR) rcs chr_drv.a $(OBJS) | ||
28 | sync | ||
29 | |||
30 | keyboard.s: kb.S ../../include/linux/config.h | ||
31 | @$(CPP) kb.S -o keyboard.s | ||
32 | |||
33 | clean: | ||
34 | @rm -f core *.o *.a tmp_make keyboard.s | ||
35 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
36 | |||
37 | dep: | ||
38 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
39 | @(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ | ||
40 | $(CPP) -M $$i;done) >> tmp_make | ||
41 | @cp tmp_make Makefile | ||
42 | |||
43 | ### Dependencies: | ||
44 | console.s console.o: console.c ../../include/linux/sched.h \ | ||
45 | ../../include/linux/head.h ../../include/linux/fs.h \ | ||
46 | ../../include/sys/types.h ../../include/linux/mm.h \ | ||
47 | ../../include/signal.h ../../include/linux/tty.h \ | ||
48 | ../../include/termios.h ../../include/asm/io.h \ | ||
49 | ../../include/asm/system.h | ||
50 | serial.s serial.o: serial.c ../../include/linux/tty.h ../../include/termios.h \ | ||
51 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
52 | ../../include/linux/fs.h ../../include/sys/types.h \ | ||
53 | ../../include/linux/mm.h ../../include/signal.h \ | ||
54 | ../../include/asm/system.h ../../include/asm/io.h | ||
55 | tty_io.s tty_io.o: tty_io.c ../../include/ctype.h ../../include/errno.h \ | ||
56 | ../../include/signal.h ../../include/sys/types.h \ | ||
57 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
58 | ../../include/linux/fs.h ../../include/linux/mm.h \ | ||
59 | ../../include/linux/tty.h ../../include/termios.h \ | ||
60 | ../../include/asm/segment.h ../../include/asm/system.h | ||
61 | tty_ioctl.s tty_ioctl.o: tty_ioctl.c ../../include/errno.h ../../include/termios.h \ | ||
62 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
63 | ../../include/linux/fs.h ../../include/sys/types.h \ | ||
64 | ../../include/linux/mm.h ../../include/signal.h \ | ||
65 | ../../include/linux/kernel.h ../../include/linux/tty.h \ | ||
66 | ../../include/asm/io.h ../../include/asm/segment.h \ | ||
67 | ../../include/asm/system.h | ||
diff --git a/src/kernel/chr_drv/console.c b/src/kernel/chr_drv/console.c new file mode 100644 index 0000000..2529569 --- /dev/null +++ b/src/kernel/chr_drv/console.c | |||
@@ -0,0 +1,710 @@ | |||
1 | /* | ||
2 | * linux/kernel/console.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * console.c | ||
9 | * | ||
10 | * This module implements the console io functions | ||
11 | * 'void con_init(void)' | ||
12 | * 'void con_write(struct tty_queue * queue)' | ||
13 | * Hopefully this will be a rather complete VT102 implementation. | ||
14 | * | ||
15 | * Beeping thanks to John T Kohl. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * NOTE!!! We sometimes disable and enable interrupts for a short while | ||
20 | * (to put a word in video IO), but this will work even for keyboard | ||
21 | * interrupts. We know interrupts aren't enabled when getting a keyboard | ||
22 | * interrupt, as we use trap-gates. Hopefully all is well. | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * Code to check for different video-cards mostly by Galen Hunt, | ||
27 | * <g-hunt@ee.utah.edu> | ||
28 | */ | ||
29 | |||
30 | #include <linux/sched.h> | ||
31 | #include <linux/tty.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/system.h> | ||
34 | |||
35 | /* | ||
36 | * These are set up by the setup-routine at boot-time: | ||
37 | */ | ||
38 | |||
39 | #define ORIG_X (*(unsigned char *)0x90000) | ||
40 | #define ORIG_Y (*(unsigned char *)0x90001) | ||
41 | #define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) | ||
42 | #define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) | ||
43 | #define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) | ||
44 | #define ORIG_VIDEO_LINES (25) | ||
45 | #define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) | ||
46 | #define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) | ||
47 | #define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) | ||
48 | |||
49 | #define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ | ||
50 | #define VIDEO_TYPE_CGA 0x11 /* CGA Display */ | ||
51 | #define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ | ||
52 | #define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ | ||
53 | |||
54 | #define NPAR 16 | ||
55 | |||
56 | extern void keyboard_interrupt(void); | ||
57 | |||
58 | static unsigned char video_type; /* Type of display being used */ | ||
59 | static unsigned long video_num_columns; /* Number of text columns */ | ||
60 | static unsigned long video_size_row; /* Bytes per row */ | ||
61 | static unsigned long video_num_lines; /* Number of test lines */ | ||
62 | static unsigned char video_page; /* Initial video page */ | ||
63 | static unsigned long video_mem_start; /* Start of video RAM */ | ||
64 | static unsigned long video_mem_end; /* End of video RAM (sort of) */ | ||
65 | static unsigned short video_port_reg; /* Video register select port */ | ||
66 | static unsigned short video_port_val; /* Video register value port */ | ||
67 | static unsigned short video_erase_char; /* Char+Attrib to erase with */ | ||
68 | |||
69 | static unsigned long origin; /* Used for EGA/VGA fast scroll */ | ||
70 | static unsigned long scr_end; /* Used for EGA/VGA fast scroll */ | ||
71 | static unsigned long pos; | ||
72 | static unsigned long x,y; | ||
73 | static unsigned long top,bottom; | ||
74 | static unsigned long state=0; | ||
75 | static unsigned long npar,par[NPAR]; | ||
76 | static unsigned long ques=0; | ||
77 | static unsigned char attr=0x07; | ||
78 | |||
79 | static void sysbeep(void); | ||
80 | |||
81 | /* | ||
82 | * this is what the terminal answers to a ESC-Z or csi0c | ||
83 | * query (= vt100 response). | ||
84 | */ | ||
85 | #define RESPONSE "\033[?1;2c" | ||
86 | |||
87 | /* NOTE! gotoxy thinks x==video_num_columns is ok */ | ||
88 | static inline void gotoxy(unsigned int new_x,unsigned int new_y) | ||
89 | { | ||
90 | if (new_x > video_num_columns || new_y >= video_num_lines) | ||
91 | return; | ||
92 | x=new_x; | ||
93 | y=new_y; | ||
94 | pos=origin + y*video_size_row + (x<<1); | ||
95 | } | ||
96 | |||
97 | static inline void set_origin(void) | ||
98 | { | ||
99 | cli(); | ||
100 | outb_p(12, video_port_reg); | ||
101 | outb_p(0xff&((origin-video_mem_start)>>9), video_port_val); | ||
102 | outb_p(13, video_port_reg); | ||
103 | outb_p(0xff&((origin-video_mem_start)>>1), video_port_val); | ||
104 | sti(); | ||
105 | } | ||
106 | |||
107 | static void scrup(void) | ||
108 | { | ||
109 | if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) | ||
110 | { | ||
111 | if (!top && bottom == video_num_lines) { | ||
112 | origin += video_size_row; | ||
113 | pos += video_size_row; | ||
114 | scr_end += video_size_row; | ||
115 | if (scr_end > video_mem_end) { | ||
116 | __asm__("cld\n\t" | ||
117 | "rep\n\t" | ||
118 | "movsl\n\t" | ||
119 | "movl video_num_columns,%1\n\t" | ||
120 | "rep\n\t" | ||
121 | "stosw" | ||
122 | ::"a" (video_erase_char), | ||
123 | "c" ((video_num_lines-1)*video_num_columns>>1), | ||
124 | "D" (video_mem_start), | ||
125 | "S" (origin) | ||
126 | ); | ||
127 | scr_end -= origin-video_mem_start; | ||
128 | pos -= origin-video_mem_start; | ||
129 | origin = video_mem_start; | ||
130 | } else { | ||
131 | __asm__("cld\n\t" | ||
132 | "rep\n\t" | ||
133 | "stosw" | ||
134 | ::"a" (video_erase_char), | ||
135 | "c" (video_num_columns), | ||
136 | "D" (scr_end-video_size_row) | ||
137 | ); | ||
138 | } | ||
139 | set_origin(); | ||
140 | } else { | ||
141 | __asm__("cld\n\t" | ||
142 | "rep\n\t" | ||
143 | "movsl\n\t" | ||
144 | "movl video_num_columns,%%ecx\n\t" | ||
145 | "rep\n\t" | ||
146 | "stosw" | ||
147 | ::"a" (video_erase_char), | ||
148 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
149 | "D" (origin+video_size_row*top), | ||
150 | "S" (origin+video_size_row*(top+1)) | ||
151 | ); | ||
152 | } | ||
153 | } | ||
154 | else /* Not EGA/VGA */ | ||
155 | { | ||
156 | __asm__("cld\n\t" | ||
157 | "rep\n\t" | ||
158 | "movsl\n\t" | ||
159 | "movl video_num_columns,%%ecx\n\t" | ||
160 | "rep\n\t" | ||
161 | "stosw" | ||
162 | ::"a" (video_erase_char), | ||
163 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
164 | "D" (origin+video_size_row*top), | ||
165 | "S" (origin+video_size_row*(top+1)) | ||
166 | ); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static void scrdown(void) | ||
171 | { | ||
172 | if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) | ||
173 | { | ||
174 | __asm__("std\n\t" | ||
175 | "rep\n\t" | ||
176 | "movsl\n\t" | ||
177 | "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ | ||
178 | "movl video_num_columns,%%ecx\n\t" | ||
179 | "rep\n\t" | ||
180 | "stosw" | ||
181 | ::"a" (video_erase_char), | ||
182 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
183 | "D" (origin+video_size_row*bottom-4), | ||
184 | "S" (origin+video_size_row*(bottom-1)-4) | ||
185 | ); | ||
186 | } | ||
187 | else /* Not EGA/VGA */ | ||
188 | { | ||
189 | __asm__("std\n\t" | ||
190 | "rep\n\t" | ||
191 | "movsl\n\t" | ||
192 | "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ | ||
193 | "movl video_num_columns,%%ecx\n\t" | ||
194 | "rep\n\t" | ||
195 | "stosw" | ||
196 | ::"a" (video_erase_char), | ||
197 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
198 | "D" (origin+video_size_row*bottom-4), | ||
199 | "S" (origin+video_size_row*(bottom-1)-4) | ||
200 | ); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static void lf(void) | ||
205 | { | ||
206 | if (y+1<bottom) { | ||
207 | y++; | ||
208 | pos += video_size_row; | ||
209 | return; | ||
210 | } | ||
211 | scrup(); | ||
212 | } | ||
213 | |||
214 | static void ri(void) | ||
215 | { | ||
216 | if (y>top) { | ||
217 | y--; | ||
218 | pos -= video_size_row; | ||
219 | return; | ||
220 | } | ||
221 | scrdown(); | ||
222 | } | ||
223 | |||
224 | static void cr(void) | ||
225 | { | ||
226 | pos -= x<<1; | ||
227 | x=0; | ||
228 | } | ||
229 | |||
230 | static void del(void) | ||
231 | { | ||
232 | if (x) { | ||
233 | pos -= 2; | ||
234 | x--; | ||
235 | *(unsigned short *)pos = video_erase_char; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static void csi_J(int par) | ||
240 | { | ||
241 | long count; | ||
242 | long start; | ||
243 | |||
244 | switch (par) { | ||
245 | case 0: /* erase from cursor to end of display */ | ||
246 | count = (scr_end-pos)>>1; | ||
247 | start = pos; | ||
248 | break; | ||
249 | case 1: /* erase from start to cursor */ | ||
250 | count = (pos-origin)>>1; | ||
251 | start = origin; | ||
252 | break; | ||
253 | case 2: /* erase whole display */ | ||
254 | count = video_num_columns * video_num_lines; | ||
255 | start = origin; | ||
256 | break; | ||
257 | default: | ||
258 | return; | ||
259 | } | ||
260 | __asm__("cld\n\t" | ||
261 | "rep\n\t" | ||
262 | "stosw\n\t" | ||
263 | ::"c" (count), | ||
264 | "D" (start),"a" (video_erase_char) | ||
265 | ); | ||
266 | } | ||
267 | |||
268 | static void csi_K(int par) | ||
269 | { | ||
270 | long count; | ||
271 | long start; | ||
272 | |||
273 | switch (par) { | ||
274 | case 0: /* erase from cursor to end of line */ | ||
275 | if (x>=video_num_columns) | ||
276 | return; | ||
277 | count = video_num_columns-x; | ||
278 | start = pos; | ||
279 | break; | ||
280 | case 1: /* erase from start of line to cursor */ | ||
281 | start = pos - (x<<1); | ||
282 | count = (x<video_num_columns)?x:video_num_columns; | ||
283 | break; | ||
284 | case 2: /* erase whole line */ | ||
285 | start = pos - (x<<1); | ||
286 | count = video_num_columns; | ||
287 | break; | ||
288 | default: | ||
289 | return; | ||
290 | } | ||
291 | __asm__("cld\n\t" | ||
292 | "rep\n\t" | ||
293 | "stosw\n\t" | ||
294 | ::"c" (count), | ||
295 | "D" (start),"a" (video_erase_char) | ||
296 | ); | ||
297 | } | ||
298 | |||
299 | void csi_m(void) | ||
300 | { | ||
301 | int i; | ||
302 | |||
303 | for (i=0;i<=npar;i++) | ||
304 | switch (par[i]) { | ||
305 | case 0:attr=0x07;break; | ||
306 | case 1:attr=0x0f;break; | ||
307 | case 4:attr=0x0f;break; | ||
308 | case 7:attr=0x70;break; | ||
309 | case 27:attr=0x07;break; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | static inline void set_cursor(void) | ||
314 | { | ||
315 | cli(); | ||
316 | outb_p(14, video_port_reg); | ||
317 | outb_p(0xff&((pos-video_mem_start)>>9), video_port_val); | ||
318 | outb_p(15, video_port_reg); | ||
319 | outb_p(0xff&((pos-video_mem_start)>>1), video_port_val); | ||
320 | sti(); | ||
321 | } | ||
322 | |||
323 | static void respond(struct tty_struct * tty) | ||
324 | { | ||
325 | char * p = RESPONSE; | ||
326 | |||
327 | cli(); | ||
328 | while (*p) { | ||
329 | PUTCH(*p,tty->read_q); | ||
330 | p++; | ||
331 | } | ||
332 | sti(); | ||
333 | copy_to_cooked(tty); | ||
334 | } | ||
335 | |||
336 | static void insert_char(void) | ||
337 | { | ||
338 | int i=x; | ||
339 | unsigned short tmp, old = video_erase_char; | ||
340 | unsigned short * p = (unsigned short *) pos; | ||
341 | |||
342 | while (i++<video_num_columns) { | ||
343 | tmp=*p; | ||
344 | *p=old; | ||
345 | old=tmp; | ||
346 | p++; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static void insert_line(void) | ||
351 | { | ||
352 | int oldtop,oldbottom; | ||
353 | |||
354 | oldtop=top; | ||
355 | oldbottom=bottom; | ||
356 | top=y; | ||
357 | bottom = video_num_lines; | ||
358 | scrdown(); | ||
359 | top=oldtop; | ||
360 | bottom=oldbottom; | ||
361 | } | ||
362 | |||
363 | static void delete_char(void) | ||
364 | { | ||
365 | int i; | ||
366 | unsigned short * p = (unsigned short *) pos; | ||
367 | |||
368 | if (x>=video_num_columns) | ||
369 | return; | ||
370 | i = x; | ||
371 | while (++i < video_num_columns) { | ||
372 | *p = *(p+1); | ||
373 | p++; | ||
374 | } | ||
375 | *p = video_erase_char; | ||
376 | } | ||
377 | |||
378 | static void delete_line(void) | ||
379 | { | ||
380 | int oldtop,oldbottom; | ||
381 | |||
382 | oldtop=top; | ||
383 | oldbottom=bottom; | ||
384 | top=y; | ||
385 | bottom = video_num_lines; | ||
386 | scrup(); | ||
387 | top=oldtop; | ||
388 | bottom=oldbottom; | ||
389 | } | ||
390 | |||
391 | static void csi_at(unsigned int nr) | ||
392 | { | ||
393 | if (nr > video_num_columns) | ||
394 | nr = video_num_columns; | ||
395 | else if (!nr) | ||
396 | nr = 1; | ||
397 | while (nr--) | ||
398 | insert_char(); | ||
399 | } | ||
400 | |||
401 | static void csi_L(unsigned int nr) | ||
402 | { | ||
403 | if (nr > video_num_lines) | ||
404 | nr = video_num_lines; | ||
405 | else if (!nr) | ||
406 | nr = 1; | ||
407 | while (nr--) | ||
408 | insert_line(); | ||
409 | } | ||
410 | |||
411 | static void csi_P(unsigned int nr) | ||
412 | { | ||
413 | if (nr > video_num_columns) | ||
414 | nr = video_num_columns; | ||
415 | else if (!nr) | ||
416 | nr = 1; | ||
417 | while (nr--) | ||
418 | delete_char(); | ||
419 | } | ||
420 | |||
421 | static void csi_M(unsigned int nr) | ||
422 | { | ||
423 | if (nr > video_num_lines) | ||
424 | nr = video_num_lines; | ||
425 | else if (!nr) | ||
426 | nr=1; | ||
427 | while (nr--) | ||
428 | delete_line(); | ||
429 | } | ||
430 | |||
431 | static int saved_x=0; | ||
432 | static int saved_y=0; | ||
433 | |||
434 | static void save_cur(void) | ||
435 | { | ||
436 | saved_x=x; | ||
437 | saved_y=y; | ||
438 | } | ||
439 | |||
440 | static void restore_cur(void) | ||
441 | { | ||
442 | gotoxy(saved_x, saved_y); | ||
443 | } | ||
444 | |||
445 | void con_write(struct tty_struct * tty) | ||
446 | { | ||
447 | int nr; | ||
448 | char c; | ||
449 | |||
450 | nr = CHARS(tty->write_q); | ||
451 | while (nr--) { | ||
452 | GETCH(tty->write_q,c); | ||
453 | switch(state) { | ||
454 | case 0: | ||
455 | if (c>31 && c<127) { | ||
456 | if (x>=video_num_columns) { | ||
457 | x -= video_num_columns; | ||
458 | pos -= video_size_row; | ||
459 | lf(); | ||
460 | } | ||
461 | __asm__("movb attr,%%ah\n\t" | ||
462 | "movw %%ax,%1\n\t" | ||
463 | ::"a" (c),"m" (*(short *)pos) | ||
464 | ); | ||
465 | pos += 2; | ||
466 | x++; | ||
467 | } else if (c==27) | ||
468 | state=1; | ||
469 | else if (c==10 || c==11 || c==12) | ||
470 | lf(); | ||
471 | else if (c==13) | ||
472 | cr(); | ||
473 | else if (c==ERASE_CHAR(tty)) | ||
474 | del(); | ||
475 | else if (c==8) { | ||
476 | if (x) { | ||
477 | x--; | ||
478 | pos -= 2; | ||
479 | } | ||
480 | } else if (c==9) { | ||
481 | c=8-(x&7); | ||
482 | x += c; | ||
483 | pos += c<<1; | ||
484 | if (x>video_num_columns) { | ||
485 | x -= video_num_columns; | ||
486 | pos -= video_size_row; | ||
487 | lf(); | ||
488 | } | ||
489 | c=9; | ||
490 | } else if (c==7) | ||
491 | sysbeep(); | ||
492 | break; | ||
493 | case 1: | ||
494 | state=0; | ||
495 | if (c=='[') | ||
496 | state=2; | ||
497 | else if (c=='E') | ||
498 | gotoxy(0,y+1); | ||
499 | else if (c=='M') | ||
500 | ri(); | ||
501 | else if (c=='D') | ||
502 | lf(); | ||
503 | else if (c=='Z') | ||
504 | respond(tty); | ||
505 | else if (x=='7') | ||
506 | save_cur(); | ||
507 | else if (x=='8') | ||
508 | restore_cur(); | ||
509 | break; | ||
510 | case 2: | ||
511 | for(npar=0;npar<NPAR;npar++) | ||
512 | par[npar]=0; | ||
513 | npar=0; | ||
514 | state=3; | ||
515 | if ((ques=(c=='?'))) | ||
516 | break; | ||
517 | case 3: | ||
518 | if (c==';' && npar<NPAR-1) { | ||
519 | npar++; | ||
520 | break; | ||
521 | } else if (c>='0' && c<='9') { | ||
522 | par[npar]=10*par[npar]+c-'0'; | ||
523 | break; | ||
524 | } else state=4; | ||
525 | case 4: | ||
526 | state=0; | ||
527 | switch(c) { | ||
528 | case 'G': case '`': | ||
529 | if (par[0]) par[0]--; | ||
530 | gotoxy(par[0],y); | ||
531 | break; | ||
532 | case 'A': | ||
533 | if (!par[0]) par[0]++; | ||
534 | gotoxy(x,y-par[0]); | ||
535 | break; | ||
536 | case 'B': case 'e': | ||
537 | if (!par[0]) par[0]++; | ||
538 | gotoxy(x,y+par[0]); | ||
539 | break; | ||
540 | case 'C': case 'a': | ||
541 | if (!par[0]) par[0]++; | ||
542 | gotoxy(x+par[0],y); | ||
543 | break; | ||
544 | case 'D': | ||
545 | if (!par[0]) par[0]++; | ||
546 | gotoxy(x-par[0],y); | ||
547 | break; | ||
548 | case 'E': | ||
549 | if (!par[0]) par[0]++; | ||
550 | gotoxy(0,y+par[0]); | ||
551 | break; | ||
552 | case 'F': | ||
553 | if (!par[0]) par[0]++; | ||
554 | gotoxy(0,y-par[0]); | ||
555 | break; | ||
556 | case 'd': | ||
557 | if (par[0]) par[0]--; | ||
558 | gotoxy(x,par[0]); | ||
559 | break; | ||
560 | case 'H': case 'f': | ||
561 | if (par[0]) par[0]--; | ||
562 | if (par[1]) par[1]--; | ||
563 | gotoxy(par[1],par[0]); | ||
564 | break; | ||
565 | case 'J': | ||
566 | csi_J(par[0]); | ||
567 | break; | ||
568 | case 'K': | ||
569 | csi_K(par[0]); | ||
570 | break; | ||
571 | case 'L': | ||
572 | csi_L(par[0]); | ||
573 | break; | ||
574 | case 'M': | ||
575 | csi_M(par[0]); | ||
576 | break; | ||
577 | case 'P': | ||
578 | csi_P(par[0]); | ||
579 | break; | ||
580 | case '@': | ||
581 | csi_at(par[0]); | ||
582 | break; | ||
583 | case 'm': | ||
584 | csi_m(); | ||
585 | break; | ||
586 | case 'r': | ||
587 | if (par[0]) par[0]--; | ||
588 | if (!par[1]) par[1] = video_num_lines; | ||
589 | if (par[0] < par[1] && | ||
590 | par[1] <= video_num_lines) { | ||
591 | top=par[0]; | ||
592 | bottom=par[1]; | ||
593 | } | ||
594 | break; | ||
595 | case 's': | ||
596 | save_cur(); | ||
597 | break; | ||
598 | case 'u': | ||
599 | restore_cur(); | ||
600 | break; | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | set_cursor(); | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * void con_init(void); | ||
609 | * | ||
610 | * This routine initalizes console interrupts, and does nothing | ||
611 | * else. If you want the screen to clear, call tty_write with | ||
612 | * the appropriate escape-sequece. | ||
613 | * | ||
614 | * Reads the information preserved by setup.s to determine the current display | ||
615 | * type and sets everything accordingly. | ||
616 | */ | ||
617 | void con_init(void) | ||
618 | { | ||
619 | register unsigned char a; | ||
620 | char *display_desc = "????"; | ||
621 | char *display_ptr; | ||
622 | |||
623 | video_num_columns = ORIG_VIDEO_COLS; | ||
624 | video_size_row = video_num_columns * 2; | ||
625 | video_num_lines = ORIG_VIDEO_LINES; | ||
626 | video_page = ORIG_VIDEO_PAGE; | ||
627 | video_erase_char = 0x0720; | ||
628 | |||
629 | if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ | ||
630 | { | ||
631 | video_mem_start = 0xb0000; | ||
632 | video_port_reg = 0x3b4; | ||
633 | video_port_val = 0x3b5; | ||
634 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) | ||
635 | { | ||
636 | video_type = VIDEO_TYPE_EGAM; | ||
637 | video_mem_end = 0xb8000; | ||
638 | display_desc = "EGAm"; | ||
639 | } | ||
640 | else | ||
641 | { | ||
642 | video_type = VIDEO_TYPE_MDA; | ||
643 | video_mem_end = 0xb2000; | ||
644 | display_desc = "*MDA"; | ||
645 | } | ||
646 | } | ||
647 | else /* If not, it is color. */ | ||
648 | { | ||
649 | video_mem_start = 0xb8000; | ||
650 | video_port_reg = 0x3d4; | ||
651 | video_port_val = 0x3d5; | ||
652 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) | ||
653 | { | ||
654 | video_type = VIDEO_TYPE_EGAC; | ||
655 | video_mem_end = 0xbc000; | ||
656 | display_desc = "EGAc"; | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | video_type = VIDEO_TYPE_CGA; | ||
661 | video_mem_end = 0xba000; | ||
662 | display_desc = "*CGA"; | ||
663 | } | ||
664 | } | ||
665 | |||
666 | /* Let the user known what kind of display driver we are using */ | ||
667 | |||
668 | display_ptr = ((char *)video_mem_start) + video_size_row - 8; | ||
669 | while (*display_desc) | ||
670 | { | ||
671 | *display_ptr++ = *display_desc++; | ||
672 | display_ptr++; | ||
673 | } | ||
674 | |||
675 | /* Initialize the variables used for scrolling (mostly EGA/VGA) */ | ||
676 | |||
677 | origin = video_mem_start; | ||
678 | scr_end = video_mem_start + video_num_lines * video_size_row; | ||
679 | top = 0; | ||
680 | bottom = video_num_lines; | ||
681 | |||
682 | gotoxy(ORIG_X,ORIG_Y); | ||
683 | set_trap_gate(0x21,&keyboard_interrupt); | ||
684 | outb_p(inb_p(0x21)&0xfd,0x21); | ||
685 | a=inb_p(0x61); | ||
686 | outb_p(a|0x80,0x61); | ||
687 | outb(a,0x61); | ||
688 | } | ||
689 | /* from bsd-net-2: */ | ||
690 | |||
691 | void sysbeepstop(void) | ||
692 | { | ||
693 | /* disable counter 2 */ | ||
694 | outb(inb_p(0x61)&0xFC, 0x61); | ||
695 | } | ||
696 | |||
697 | int beepcount = 0; | ||
698 | |||
699 | static void sysbeep(void) | ||
700 | { | ||
701 | /* enable counter 2 */ | ||
702 | outb_p(inb_p(0x61)|3, 0x61); | ||
703 | /* set command for counter 2, 2 byte write */ | ||
704 | outb_p(0xB6, 0x43); | ||
705 | /* send 0x637 for 750 HZ */ | ||
706 | outb_p(0x37, 0x42); | ||
707 | outb(0x06, 0x42); | ||
708 | /* 1/8 second */ | ||
709 | beepcount = HZ/8; | ||
710 | } | ||
diff --git a/src/kernel/chr_drv/kb.S b/src/kernel/chr_drv/kb.S new file mode 100644 index 0000000..ffd28cf --- /dev/null +++ b/src/kernel/chr_drv/kb.S | |||
@@ -0,0 +1,588 @@ | |||
1 | /* | ||
2 | * linux/kernel/keyboard.S | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Thanks to Alfred Leung for US keyboard patches | ||
9 | * Wolfgang Thiel for German keyboard patches | ||
10 | * Marc Corsini for the French keyboard | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | |||
15 | .text | ||
16 | .globl keyboard_interrupt | ||
17 | |||
18 | /* | ||
19 | * these are for the keyboard read functions | ||
20 | */ | ||
21 | size = 1024 /* must be a power of two ! And MUST be the same | ||
22 | as in tty_io.c !!!! */ | ||
23 | head = 4 | ||
24 | tail = 8 | ||
25 | proc_list = 12 | ||
26 | buf = 16 | ||
27 | |||
28 | mode: .byte 0 /* caps, alt, ctrl and shift mode */ | ||
29 | leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */ | ||
30 | e0: .byte 0 | ||
31 | |||
32 | /* | ||
33 | * con_int is the real interrupt routine that reads the | ||
34 | * keyboard scan-code and converts it into the appropriate | ||
35 | * ascii character(s). | ||
36 | */ | ||
37 | keyboard_interrupt: | ||
38 | pushl %eax | ||
39 | pushl %ebx | ||
40 | pushl %ecx | ||
41 | pushl %edx | ||
42 | push %ds | ||
43 | push %es | ||
44 | movl $0x10,%eax | ||
45 | mov %ax,%ds | ||
46 | mov %ax,%es | ||
47 | xor %al,%al /* %eax is scan code */ | ||
48 | inb $0x60,%al | ||
49 | cmpb $0xe0,%al | ||
50 | je set_e0 | ||
51 | cmpb $0xe1,%al | ||
52 | je set_e1 | ||
53 | call *key_table(,%eax,4) | ||
54 | movb $0,e0 | ||
55 | e0_e1: inb $0x61,%al | ||
56 | jmp 1f | ||
57 | 1: jmp 1f | ||
58 | 1: orb $0x80,%al | ||
59 | jmp 1f | ||
60 | 1: jmp 1f | ||
61 | 1: outb %al,$0x61 | ||
62 | jmp 1f | ||
63 | 1: jmp 1f | ||
64 | 1: andb $0x7F,%al | ||
65 | outb %al,$0x61 | ||
66 | movb $0x20,%al | ||
67 | outb %al,$0x20 | ||
68 | pushl $0 | ||
69 | call do_tty_interrupt | ||
70 | addl $4,%esp | ||
71 | pop %es | ||
72 | pop %ds | ||
73 | popl %edx | ||
74 | popl %ecx | ||
75 | popl %ebx | ||
76 | popl %eax | ||
77 | iret | ||
78 | set_e0: movb $1,e0 | ||
79 | jmp e0_e1 | ||
80 | set_e1: movb $2,e0 | ||
81 | jmp e0_e1 | ||
82 | |||
83 | /* | ||
84 | * This routine fills the buffer with max 8 bytes, taken from | ||
85 | * %ebx:%eax. (%edx is high). The bytes are written in the | ||
86 | * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero. | ||
87 | */ | ||
88 | put_queue: | ||
89 | pushl %ecx | ||
90 | pushl %edx | ||
91 | movl table_list,%edx # read-queue for console | ||
92 | movl head(%edx),%ecx | ||
93 | 1: movb %al,buf(%edx,%ecx) | ||
94 | incl %ecx | ||
95 | andl $size-1,%ecx | ||
96 | cmpl tail(%edx),%ecx # buffer full - discard everything | ||
97 | je 3f | ||
98 | shrdl $8,%ebx,%eax | ||
99 | je 2f | ||
100 | shrl $8,%ebx | ||
101 | jmp 1b | ||
102 | 2: movl %ecx,head(%edx) | ||
103 | movl proc_list(%edx),%ecx | ||
104 | testl %ecx,%ecx | ||
105 | je 3f | ||
106 | movl $0,(%ecx) | ||
107 | 3: popl %edx | ||
108 | popl %ecx | ||
109 | ret | ||
110 | |||
111 | ctrl: movb $0x04,%al | ||
112 | jmp 1f | ||
113 | alt: movb $0x10,%al | ||
114 | 1: cmpb $0,e0 | ||
115 | je 2f | ||
116 | addb %al,%al | ||
117 | 2: orb %al,mode | ||
118 | ret | ||
119 | unctrl: movb $0x04,%al | ||
120 | jmp 1f | ||
121 | unalt: movb $0x10,%al | ||
122 | 1: cmpb $0,e0 | ||
123 | je 2f | ||
124 | addb %al,%al | ||
125 | 2: notb %al | ||
126 | andb %al,mode | ||
127 | ret | ||
128 | |||
129 | lshift: | ||
130 | orb $0x01,mode | ||
131 | ret | ||
132 | unlshift: | ||
133 | andb $0xfe,mode | ||
134 | ret | ||
135 | rshift: | ||
136 | orb $0x02,mode | ||
137 | ret | ||
138 | unrshift: | ||
139 | andb $0xfd,mode | ||
140 | ret | ||
141 | |||
142 | caps: testb $0x80,mode | ||
143 | jne 1f | ||
144 | xorb $4,leds | ||
145 | xorb $0x40,mode | ||
146 | orb $0x80,mode | ||
147 | set_leds: | ||
148 | call kb_wait | ||
149 | movb $0xed,%al /* set leds command */ | ||
150 | outb %al,$0x60 | ||
151 | call kb_wait | ||
152 | movb leds,%al | ||
153 | outb %al,$0x60 | ||
154 | ret | ||
155 | uncaps: andb $0x7f,mode | ||
156 | ret | ||
157 | scroll: | ||
158 | xorb $1,leds | ||
159 | jmp set_leds | ||
160 | num: xorb $2,leds | ||
161 | jmp set_leds | ||
162 | |||
163 | /* | ||
164 | * curosr-key/numeric keypad cursor keys are handled here. | ||
165 | * checking for numeric keypad etc. | ||
166 | */ | ||
167 | cursor: | ||
168 | subb $0x47,%al | ||
169 | jb 1f | ||
170 | cmpb $12,%al | ||
171 | ja 1f | ||
172 | jne cur2 /* check for ctrl-alt-del */ | ||
173 | testb $0x0c,mode | ||
174 | je cur2 | ||
175 | testb $0x30,mode | ||
176 | jne reboot | ||
177 | cur2: cmpb $0x01,e0 /* e0 forces cursor movement */ | ||
178 | je cur | ||
179 | testb $0x02,leds /* not num-lock forces cursor */ | ||
180 | je cur | ||
181 | testb $0x03,mode /* shift forces cursor */ | ||
182 | jne cur | ||
183 | xorl %ebx,%ebx | ||
184 | movb num_table(%eax),%al | ||
185 | jmp put_queue | ||
186 | 1: ret | ||
187 | |||
188 | cur: movb cur_table(%eax),%al | ||
189 | cmpb $'9,%al | ||
190 | ja ok_cur | ||
191 | movb $'~,%ah | ||
192 | ok_cur: shll $16,%eax | ||
193 | movw $0x5b1b,%ax | ||
194 | xorl %ebx,%ebx | ||
195 | jmp put_queue | ||
196 | |||
197 | #if defined(KBD_FR) | ||
198 | num_table: | ||
199 | .ascii "789 456 1230." | ||
200 | #else | ||
201 | num_table: | ||
202 | .ascii "789 456 1230," | ||
203 | #endif | ||
204 | cur_table: | ||
205 | .ascii "HA5 DGC YB623" | ||
206 | |||
207 | /* | ||
208 | * this routine handles function keys | ||
209 | */ | ||
210 | func: | ||
211 | pushl %eax | ||
212 | pushl %ecx | ||
213 | pushl %edx | ||
214 | call show_stat | ||
215 | popl %edx | ||
216 | popl %ecx | ||
217 | popl %eax | ||
218 | subb $0x3B,%al | ||
219 | jb end_func | ||
220 | cmpb $9,%al | ||
221 | jbe ok_func | ||
222 | subb $18,%al | ||
223 | cmpb $10,%al | ||
224 | jb end_func | ||
225 | cmpb $11,%al | ||
226 | ja end_func | ||
227 | ok_func: | ||
228 | cmpl $4,%ecx /* check that there is enough room */ | ||
229 | jl end_func | ||
230 | movl func_table(,%eax,4),%eax | ||
231 | xorl %ebx,%ebx | ||
232 | jmp put_queue | ||
233 | end_func: | ||
234 | ret | ||
235 | |||
236 | /* | ||
237 | * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. | ||
238 | */ | ||
239 | func_table: | ||
240 | .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b | ||
241 | .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b | ||
242 | .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b | ||
243 | |||
244 | #if defined(KBD_FINNISH) | ||
245 | key_map: | ||
246 | .byte 0,27 | ||
247 | .ascii "1234567890+'" | ||
248 | .byte 127,9 | ||
249 | .ascii "qwertyuiop}" | ||
250 | .byte 0,13,0 | ||
251 | .ascii "asdfghjkl|{" | ||
252 | .byte 0,0 | ||
253 | .ascii "'zxcvbnm,.-" | ||
254 | .byte 0,'*,0,32 /* 36-39 */ | ||
255 | .fill 16,1,0 /* 3A-49 */ | ||
256 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
257 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
258 | .byte '< | ||
259 | .fill 10,1,0 | ||
260 | |||
261 | shift_map: | ||
262 | .byte 0,27 | ||
263 | .ascii "!\"#$%&/()=?`" | ||
264 | .byte 127,9 | ||
265 | .ascii "QWERTYUIOP]^" | ||
266 | .byte 13,0 | ||
267 | .ascii "ASDFGHJKL\\[" | ||
268 | .byte 0,0 | ||
269 | .ascii "*ZXCVBNM;:_" | ||
270 | .byte 0,'*,0,32 /* 36-39 */ | ||
271 | .fill 16,1,0 /* 3A-49 */ | ||
272 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
273 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
274 | .byte '> | ||
275 | .fill 10,1,0 | ||
276 | |||
277 | alt_map: | ||
278 | .byte 0,0 | ||
279 | .ascii "\0@\0$\0\0{[]}\\\0" | ||
280 | .byte 0,0 | ||
281 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
282 | .byte '~,13,0 | ||
283 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
284 | .byte 0,0 | ||
285 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
286 | .byte 0,0,0,0 /* 36-39 */ | ||
287 | .fill 16,1,0 /* 3A-49 */ | ||
288 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
289 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
290 | .byte '| | ||
291 | .fill 10,1,0 | ||
292 | |||
293 | #elif defined(KBD_US) | ||
294 | |||
295 | key_map: | ||
296 | .byte 0,27 | ||
297 | .ascii "1234567890-=" | ||
298 | .byte 127,9 | ||
299 | .ascii "qwertyuiop[]" | ||
300 | .byte 13,0 | ||
301 | .ascii "asdfghjkl;'" | ||
302 | .byte '`,0 | ||
303 | .ascii "\\zxcvbnm,./" | ||
304 | .byte 0,'*,0,32 /* 36-39 */ | ||
305 | .fill 16,1,0 /* 3A-49 */ | ||
306 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
307 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
308 | .byte '< | ||
309 | .fill 10,1,0 | ||
310 | |||
311 | |||
312 | shift_map: | ||
313 | .byte 0,27 | ||
314 | .ascii "!@#$%^&*()_+" | ||
315 | .byte 127,9 | ||
316 | .ascii "QWERTYUIOP{}" | ||
317 | .byte 13,0 | ||
318 | .ascii "ASDFGHJKL:\"" | ||
319 | .byte '~,0 | ||
320 | .ascii "|ZXCVBNM<>?" | ||
321 | .byte 0,'*,0,32 /* 36-39 */ | ||
322 | .fill 16,1,0 /* 3A-49 */ | ||
323 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
324 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
325 | .byte '> | ||
326 | .fill 10,1,0 | ||
327 | |||
328 | alt_map: | ||
329 | .byte 0,0 | ||
330 | .ascii "\0@\0$\0\0{[]}\\\0" | ||
331 | .byte 0,0 | ||
332 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
333 | .byte '~,13,0 | ||
334 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
335 | .byte 0,0 | ||
336 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
337 | .byte 0,0,0,0 /* 36-39 */ | ||
338 | .fill 16,1,0 /* 3A-49 */ | ||
339 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
340 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
341 | .byte '| | ||
342 | .fill 10,1,0 | ||
343 | |||
344 | #elif defined(KBD_GR) | ||
345 | |||
346 | key_map: | ||
347 | .byte 0,27 | ||
348 | .ascii "1234567890\\'" | ||
349 | .byte 127,9 | ||
350 | .ascii "qwertzuiop@+" | ||
351 | .byte 13,0 | ||
352 | .ascii "asdfghjkl[]^" | ||
353 | .byte 0,'# | ||
354 | .ascii "yxcvbnm,.-" | ||
355 | .byte 0,'*,0,32 /* 36-39 */ | ||
356 | .fill 16,1,0 /* 3A-49 */ | ||
357 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
358 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
359 | .byte '< | ||
360 | .fill 10,1,0 | ||
361 | |||
362 | |||
363 | shift_map: | ||
364 | .byte 0,27 | ||
365 | .ascii "!\"#$%&/()=?`" | ||
366 | .byte 127,9 | ||
367 | .ascii "QWERTZUIOP\\*" | ||
368 | .byte 13,0 | ||
369 | .ascii "ASDFGHJKL{}~" | ||
370 | .byte 0,'' | ||
371 | .ascii "YXCVBNM;:_" | ||
372 | .byte 0,'*,0,32 /* 36-39 */ | ||
373 | .fill 16,1,0 /* 3A-49 */ | ||
374 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
375 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
376 | .byte '> | ||
377 | .fill 10,1,0 | ||
378 | |||
379 | alt_map: | ||
380 | .byte 0,0 | ||
381 | .ascii "\0@\0$\0\0{[]}\\\0" | ||
382 | .byte 0,0 | ||
383 | .byte '@,0,0,0,0,0,0,0,0,0,0 | ||
384 | .byte '~,13,0 | ||
385 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
386 | .byte 0,0 | ||
387 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
388 | .byte 0,0,0,0 /* 36-39 */ | ||
389 | .fill 16,1,0 /* 3A-49 */ | ||
390 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
391 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
392 | .byte '| | ||
393 | .fill 10,1,0 | ||
394 | |||
395 | |||
396 | #elif defined(KBD_FR) | ||
397 | |||
398 | key_map: | ||
399 | .byte 0,27 | ||
400 | .ascii "&{\"'(-}_/@)=" | ||
401 | .byte 127,9 | ||
402 | .ascii "azertyuiop^$" | ||
403 | .byte 13,0 | ||
404 | .ascii "qsdfghjklm|" | ||
405 | .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */ | ||
406 | .ascii "wxcvbn,;:!" | ||
407 | .byte 0,'*,0,32 /* 36-39 */ | ||
408 | .fill 16,1,0 /* 3A-49 */ | ||
409 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
410 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
411 | .byte '< | ||
412 | .fill 10,1,0 | ||
413 | |||
414 | shift_map: | ||
415 | .byte 0,27 | ||
416 | .ascii "1234567890]+" | ||
417 | .byte 127,9 | ||
418 | .ascii "AZERTYUIOP<>" | ||
419 | .byte 13,0 | ||
420 | .ascii "QSDFGHJKLM%" | ||
421 | .byte '~,0,'# | ||
422 | .ascii "WXCVBN?./\\" | ||
423 | .byte 0,'*,0,32 /* 36-39 */ | ||
424 | .fill 16,1,0 /* 3A-49 */ | ||
425 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
426 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
427 | .byte '> | ||
428 | .fill 10,1,0 | ||
429 | |||
430 | alt_map: | ||
431 | .byte 0,0 | ||
432 | .ascii "\0~#{[|`\\^@]}" | ||
433 | .byte 0,0 | ||
434 | .byte '@,0,0,0,0,0,0,0,0,0,0 | ||
435 | .byte '~,13,0 | ||
436 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
437 | .byte 0,0 | ||
438 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
439 | .byte 0,0,0,0 /* 36-39 */ | ||
440 | .fill 16,1,0 /* 3A-49 */ | ||
441 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
442 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
443 | .byte '| | ||
444 | .fill 10,1,0 | ||
445 | |||
446 | #else | ||
447 | #error "KBD-type not defined" | ||
448 | #endif | ||
449 | /* | ||
450 | * do_self handles "normal" keys, ie keys that don't change meaning | ||
451 | * and which have just one character returns. | ||
452 | */ | ||
453 | do_self: | ||
454 | lea alt_map,%ebx | ||
455 | testb $0x20,mode /* alt-gr */ | ||
456 | jne 1f | ||
457 | lea shift_map,%ebx | ||
458 | testb $0x03,mode | ||
459 | jne 1f | ||
460 | lea key_map,%ebx | ||
461 | 1: movb (%ebx,%eax),%al | ||
462 | orb %al,%al | ||
463 | je none | ||
464 | testb $0x4c,mode /* ctrl or caps */ | ||
465 | je 2f | ||
466 | cmpb $'a,%al | ||
467 | jb 2f | ||
468 | cmpb $'},%al | ||
469 | ja 2f | ||
470 | subb $32,%al | ||
471 | 2: testb $0x0c,mode /* ctrl */ | ||
472 | je 3f | ||
473 | cmpb $64,%al | ||
474 | jb 3f | ||
475 | cmpb $64+32,%al | ||
476 | jae 3f | ||
477 | subb $64,%al | ||
478 | 3: testb $0x10,mode /* left alt */ | ||
479 | je 4f | ||
480 | orb $0x80,%al | ||
481 | 4: andl $0xff,%eax | ||
482 | xorl %ebx,%ebx | ||
483 | call put_queue | ||
484 | none: ret | ||
485 | |||
486 | /* | ||
487 | * minus has a routine of it's own, as a 'E0h' before | ||
488 | * the scan code for minus means that the numeric keypad | ||
489 | * slash was pushed. | ||
490 | */ | ||
491 | minus: cmpb $1,e0 | ||
492 | jne do_self | ||
493 | movl $'/,%eax | ||
494 | xorl %ebx,%ebx | ||
495 | jmp put_queue | ||
496 | |||
497 | /* | ||
498 | * This table decides which routine to call when a scan-code has been | ||
499 | * gotten. Most routines just call do_self, or none, depending if | ||
500 | * they are make or break. | ||
501 | */ | ||
502 | key_table: | ||
503 | .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */ | ||
504 | .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */ | ||
505 | .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */ | ||
506 | .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */ | ||
507 | .long do_self,do_self,do_self,do_self /* 10-13 q w e r */ | ||
508 | .long do_self,do_self,do_self,do_self /* 14-17 t y u i */ | ||
509 | .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */ | ||
510 | .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */ | ||
511 | .long do_self,do_self,do_self,do_self /* 20-23 d f g h */ | ||
512 | .long do_self,do_self,do_self,do_self /* 24-27 j k l | */ | ||
513 | .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */ | ||
514 | .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */ | ||
515 | .long do_self,do_self,do_self,do_self /* 30-33 b n m , */ | ||
516 | .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */ | ||
517 | .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */ | ||
518 | .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */ | ||
519 | .long func,func,func,func /* 40-43 f6 f7 f8 f9 */ | ||
520 | .long func,num,scroll,cursor /* 44-47 f10 num scr home */ | ||
521 | .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */ | ||
522 | .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */ | ||
523 | .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */ | ||
524 | .long none,none,do_self,func /* 54-57 sysreq ? < f11 */ | ||
525 | .long func,none,none,none /* 58-5B f12 ? ? ? */ | ||
526 | .long none,none,none,none /* 5C-5F ? ? ? ? */ | ||
527 | .long none,none,none,none /* 60-63 ? ? ? ? */ | ||
528 | .long none,none,none,none /* 64-67 ? ? ? ? */ | ||
529 | .long none,none,none,none /* 68-6B ? ? ? ? */ | ||
530 | .long none,none,none,none /* 6C-6F ? ? ? ? */ | ||
531 | .long none,none,none,none /* 70-73 ? ? ? ? */ | ||
532 | .long none,none,none,none /* 74-77 ? ? ? ? */ | ||
533 | .long none,none,none,none /* 78-7B ? ? ? ? */ | ||
534 | .long none,none,none,none /* 7C-7F ? ? ? ? */ | ||
535 | .long none,none,none,none /* 80-83 ? br br br */ | ||
536 | .long none,none,none,none /* 84-87 br br br br */ | ||
537 | .long none,none,none,none /* 88-8B br br br br */ | ||
538 | .long none,none,none,none /* 8C-8F br br br br */ | ||
539 | .long none,none,none,none /* 90-93 br br br br */ | ||
540 | .long none,none,none,none /* 94-97 br br br br */ | ||
541 | .long none,none,none,none /* 98-9B br br br br */ | ||
542 | .long none,unctrl,none,none /* 9C-9F br unctrl br br */ | ||
543 | .long none,none,none,none /* A0-A3 br br br br */ | ||
544 | .long none,none,none,none /* A4-A7 br br br br */ | ||
545 | .long none,none,unlshift,none /* A8-AB br br unlshift br */ | ||
546 | .long none,none,none,none /* AC-AF br br br br */ | ||
547 | .long none,none,none,none /* B0-B3 br br br br */ | ||
548 | .long none,none,unrshift,none /* B4-B7 br br unrshift br */ | ||
549 | .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */ | ||
550 | .long none,none,none,none /* BC-BF br br br br */ | ||
551 | .long none,none,none,none /* C0-C3 br br br br */ | ||
552 | .long none,none,none,none /* C4-C7 br br br br */ | ||
553 | .long none,none,none,none /* C8-CB br br br br */ | ||
554 | .long none,none,none,none /* CC-CF br br br br */ | ||
555 | .long none,none,none,none /* D0-D3 br br br br */ | ||
556 | .long none,none,none,none /* D4-D7 br br br br */ | ||
557 | .long none,none,none,none /* D8-DB br ? ? ? */ | ||
558 | .long none,none,none,none /* DC-DF ? ? ? ? */ | ||
559 | .long none,none,none,none /* E0-E3 e0 e1 ? ? */ | ||
560 | .long none,none,none,none /* E4-E7 ? ? ? ? */ | ||
561 | .long none,none,none,none /* E8-EB ? ? ? ? */ | ||
562 | .long none,none,none,none /* EC-EF ? ? ? ? */ | ||
563 | .long none,none,none,none /* F0-F3 ? ? ? ? */ | ||
564 | .long none,none,none,none /* F4-F7 ? ? ? ? */ | ||
565 | .long none,none,none,none /* F8-FB ? ? ? ? */ | ||
566 | .long none,none,none,none /* FC-FF ? ? ? ? */ | ||
567 | |||
568 | /* | ||
569 | * kb_wait waits for the keyboard controller buffer to empty. | ||
570 | * there is no timeout - if the buffer doesn't empty, we hang. | ||
571 | */ | ||
572 | kb_wait: | ||
573 | pushl %eax | ||
574 | 1: inb $0x64,%al | ||
575 | testb $0x02,%al | ||
576 | jne 1b | ||
577 | popl %eax | ||
578 | ret | ||
579 | /* | ||
580 | * This routine reboots the machine by asking the keyboard | ||
581 | * controller to pulse the reset-line low. | ||
582 | */ | ||
583 | reboot: | ||
584 | call kb_wait | ||
585 | movw $0x1234,0x472 /* don't do memory check */ | ||
586 | movb $0xfc,%al /* pulse reset and A20 low */ | ||
587 | outb %al,$0x64 | ||
588 | die: jmp die | ||
diff --git a/src/kernel/chr_drv/rs_io.s b/src/kernel/chr_drv/rs_io.s new file mode 100644 index 0000000..6788658 --- /dev/null +++ b/src/kernel/chr_drv/rs_io.s | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * linux/kernel/rs_io.s | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * rs_io.s | ||
9 | * | ||
10 | * This module implements the rs232 io interrupts. | ||
11 | */ | ||
12 | |||
13 | .text | ||
14 | .globl rs1_interrupt,rs2_interrupt | ||
15 | |||
16 | size = 1024 /* must be power of two ! | ||
17 | and must match the value | ||
18 | in tty_io.c!!! */ | ||
19 | |||
20 | /* these are the offsets into the read/write buffer structures */ | ||
21 | rs_addr = 0 | ||
22 | head = 4 | ||
23 | tail = 8 | ||
24 | proc_list = 12 | ||
25 | buf = 16 | ||
26 | |||
27 | startup = 256 /* chars left in write queue when we restart it */ | ||
28 | |||
29 | /* | ||
30 | * These are the actual interrupt routines. They look where | ||
31 | * the interrupt is coming from, and take appropriate action. | ||
32 | */ | ||
33 | .align 2 | ||
34 | rs1_interrupt: | ||
35 | pushl $table_list+8 | ||
36 | jmp rs_int | ||
37 | .align 2 | ||
38 | rs2_interrupt: | ||
39 | pushl $table_list+16 | ||
40 | rs_int: | ||
41 | pushl %edx | ||
42 | pushl %ecx | ||
43 | pushl %ebx | ||
44 | pushl %eax | ||
45 | push %es | ||
46 | push %ds /* as this is an interrupt, we cannot */ | ||
47 | pushl $0x10 /* know that bs is ok. Load it */ | ||
48 | pop %ds | ||
49 | pushl $0x10 | ||
50 | pop %es | ||
51 | movl 24(%esp),%edx | ||
52 | movl (%edx),%edx | ||
53 | movl rs_addr(%edx),%edx | ||
54 | addl $2,%edx /* interrupt ident. reg */ | ||
55 | rep_int: | ||
56 | xorl %eax,%eax | ||
57 | inb %dx,%al | ||
58 | testb $1,%al | ||
59 | jne end | ||
60 | cmpb $6,%al /* this shouldn't happen, but ... */ | ||
61 | ja end | ||
62 | movl 24(%esp),%ecx | ||
63 | pushl %edx | ||
64 | subl $2,%edx | ||
65 | call *jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */ | ||
66 | popl %edx | ||
67 | jmp rep_int | ||
68 | end: movb $0x20,%al | ||
69 | outb %al,$0x20 /* EOI */ | ||
70 | pop %ds | ||
71 | pop %es | ||
72 | popl %eax | ||
73 | popl %ebx | ||
74 | popl %ecx | ||
75 | popl %edx | ||
76 | addl $4,%esp # jump over _table_list entry | ||
77 | iret | ||
78 | |||
79 | jmp_table: | ||
80 | .long modem_status,write_char,read_char,line_status | ||
81 | |||
82 | .align 2 | ||
83 | modem_status: | ||
84 | addl $6,%edx /* clear intr by reading modem status reg */ | ||
85 | inb %dx,%al | ||
86 | ret | ||
87 | |||
88 | .align 2 | ||
89 | line_status: | ||
90 | addl $5,%edx /* clear intr by reading line status reg. */ | ||
91 | inb %dx,%al | ||
92 | ret | ||
93 | |||
94 | .align 2 | ||
95 | read_char: | ||
96 | inb %dx,%al | ||
97 | movl %ecx,%edx | ||
98 | subl $table_list,%edx | ||
99 | shrl $3,%edx | ||
100 | movl (%ecx),%ecx # read-queue | ||
101 | movl head(%ecx),%ebx | ||
102 | movb %al,buf(%ecx,%ebx) | ||
103 | incl %ebx | ||
104 | andl $size-1,%ebx | ||
105 | cmpl tail(%ecx),%ebx | ||
106 | je 1f | ||
107 | movl %ebx,head(%ecx) | ||
108 | 1: pushl %edx | ||
109 | call do_tty_interrupt | ||
110 | addl $4,%esp | ||
111 | ret | ||
112 | |||
113 | .align 2 | ||
114 | write_char: | ||
115 | movl 4(%ecx),%ecx # write-queue | ||
116 | movl head(%ecx),%ebx | ||
117 | subl tail(%ecx),%ebx | ||
118 | andl $size-1,%ebx # nr chars in queue | ||
119 | je write_buffer_empty | ||
120 | cmpl $startup,%ebx | ||
121 | ja 1f | ||
122 | movl proc_list(%ecx),%ebx # wake up sleeping process | ||
123 | testl %ebx,%ebx # is there any? | ||
124 | je 1f | ||
125 | movl $0,(%ebx) | ||
126 | 1: movl tail(%ecx),%ebx | ||
127 | movb buf(%ecx,%ebx),%al | ||
128 | outb %al,%dx | ||
129 | incl %ebx | ||
130 | andl $size-1,%ebx | ||
131 | movl %ebx,tail(%ecx) | ||
132 | cmpl head(%ecx),%ebx | ||
133 | je write_buffer_empty | ||
134 | ret | ||
135 | .align 2 | ||
136 | write_buffer_empty: | ||
137 | movl proc_list(%ecx),%ebx # wake up sleeping process | ||
138 | testl %ebx,%ebx # is there any? | ||
139 | je 1f | ||
140 | movl $0,(%ebx) | ||
141 | 1: incl %edx | ||
142 | inb %dx,%al | ||
143 | jmp 1f | ||
144 | 1: jmp 1f | ||
145 | 1: andb $0xd,%al /* disable transmit interrupt */ | ||
146 | outb %al,%dx | ||
147 | ret | ||
diff --git a/src/kernel/chr_drv/serial.c b/src/kernel/chr_drv/serial.c new file mode 100644 index 0000000..aba25df --- /dev/null +++ b/src/kernel/chr_drv/serial.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * linux/kernel/serial.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * serial.c | ||
9 | * | ||
10 | * This module implements the rs232 io functions | ||
11 | * void rs_write(struct tty_struct * queue); | ||
12 | * void rs_init(void); | ||
13 | * and all interrupts pertaining to serial IO. | ||
14 | */ | ||
15 | |||
16 | #include <linux/tty.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <asm/system.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | #define WAKEUP_CHARS (TTY_BUF_SIZE/4) | ||
22 | |||
23 | extern void rs1_interrupt(void); | ||
24 | extern void rs2_interrupt(void); | ||
25 | |||
26 | static void init(int port) | ||
27 | { | ||
28 | outb_p(0x80,port+3); /* set DLAB of line control reg */ | ||
29 | outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ | ||
30 | outb_p(0x00,port+1); /* MS of divisor */ | ||
31 | outb_p(0x03,port+3); /* reset DLAB */ | ||
32 | outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */ | ||
33 | outb_p(0x0d,port+1); /* enable all intrs but writes */ | ||
34 | (void)inb(port); /* read data port to reset things (?) */ | ||
35 | } | ||
36 | |||
37 | void rs_init(void) | ||
38 | { | ||
39 | set_intr_gate(0x24,rs1_interrupt); | ||
40 | set_intr_gate(0x23,rs2_interrupt); | ||
41 | init(tty_table[1].read_q.data); | ||
42 | init(tty_table[2].read_q.data); | ||
43 | outb(inb_p(0x21)&0xE7,0x21); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * This routine gets called when tty_write has put something into | ||
48 | * the write_queue. It must check wheter the queue is empty, and | ||
49 | * set the interrupt register accordingly | ||
50 | * | ||
51 | * void _rs_write(struct tty_struct * tty); | ||
52 | */ | ||
53 | void rs_write(struct tty_struct * tty) | ||
54 | { | ||
55 | cli(); | ||
56 | if (!EMPTY(tty->write_q)) | ||
57 | outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1); | ||
58 | sti(); | ||
59 | } | ||
diff --git a/src/kernel/chr_drv/tty_io.c b/src/kernel/chr_drv/tty_io.c new file mode 100644 index 0000000..ed14fa8 --- /dev/null +++ b/src/kernel/chr_drv/tty_io.c | |||
@@ -0,0 +1,350 @@ | |||
1 | /* | ||
2 | * linux/kernel/tty_io.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles | ||
9 | * or rs-channels. It also implements echoing, cooked mode etc. | ||
10 | * | ||
11 | * Kill-line thanks to John T Kohl. | ||
12 | */ | ||
13 | #include <ctype.h> | ||
14 | #include <errno.h> | ||
15 | #include <signal.h> | ||
16 | |||
17 | #define ALRMMASK (1<<(SIGALRM-1)) | ||
18 | #define KILLMASK (1<<(SIGKILL-1)) | ||
19 | #define INTMASK (1<<(SIGINT-1)) | ||
20 | #define QUITMASK (1<<(SIGQUIT-1)) | ||
21 | #define TSTPMASK (1<<(SIGTSTP-1)) | ||
22 | |||
23 | #include <linux/sched.h> | ||
24 | #include <linux/tty.h> | ||
25 | #include <asm/segment.h> | ||
26 | #include <asm/system.h> | ||
27 | |||
28 | #define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f) | ||
29 | #define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f) | ||
30 | #define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f) | ||
31 | |||
32 | #define L_CANON(tty) _L_FLAG((tty),ICANON) | ||
33 | #define L_ISIG(tty) _L_FLAG((tty),ISIG) | ||
34 | #define L_ECHO(tty) _L_FLAG((tty),ECHO) | ||
35 | #define L_ECHOE(tty) _L_FLAG((tty),ECHOE) | ||
36 | #define L_ECHOK(tty) _L_FLAG((tty),ECHOK) | ||
37 | #define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) | ||
38 | #define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) | ||
39 | |||
40 | #define I_UCLC(tty) _I_FLAG((tty),IUCLC) | ||
41 | #define I_NLCR(tty) _I_FLAG((tty),INLCR) | ||
42 | #define I_CRNL(tty) _I_FLAG((tty),ICRNL) | ||
43 | #define I_NOCR(tty) _I_FLAG((tty),IGNCR) | ||
44 | |||
45 | #define O_POST(tty) _O_FLAG((tty),OPOST) | ||
46 | #define O_NLCR(tty) _O_FLAG((tty),ONLCR) | ||
47 | #define O_CRNL(tty) _O_FLAG((tty),OCRNL) | ||
48 | #define O_NLRET(tty) _O_FLAG((tty),ONLRET) | ||
49 | #define O_LCUC(tty) _O_FLAG((tty),OLCUC) | ||
50 | |||
51 | struct tty_struct tty_table[] = { | ||
52 | { | ||
53 | {ICRNL, /* change incoming CR to NL */ | ||
54 | OPOST|ONLCR, /* change outgoing NL to CRNL */ | ||
55 | 0, | ||
56 | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, | ||
57 | 0, /* console termio */ | ||
58 | INIT_C_CC}, | ||
59 | 0, /* initial pgrp */ | ||
60 | 0, /* initial stopped */ | ||
61 | con_write, | ||
62 | {0,0,0,0,""}, /* console read-queue */ | ||
63 | {0,0,0,0,""}, /* console write-queue */ | ||
64 | {0,0,0,0,""} /* console secondary queue */ | ||
65 | },{ | ||
66 | {0, /* no translation */ | ||
67 | 0, /* no translation */ | ||
68 | B2400 | CS8, | ||
69 | 0, | ||
70 | 0, | ||
71 | INIT_C_CC}, | ||
72 | 0, | ||
73 | 0, | ||
74 | rs_write, | ||
75 | {0x3f8,0,0,0,""}, /* rs 1 */ | ||
76 | {0x3f8,0,0,0,""}, | ||
77 | {0,0,0,0,""} | ||
78 | },{ | ||
79 | {0, /* no translation */ | ||
80 | 0, /* no translation */ | ||
81 | B2400 | CS8, | ||
82 | 0, | ||
83 | 0, | ||
84 | INIT_C_CC}, | ||
85 | 0, | ||
86 | 0, | ||
87 | rs_write, | ||
88 | {0x2f8,0,0,0,""}, /* rs 2 */ | ||
89 | {0x2f8,0,0,0,""}, | ||
90 | {0,0,0,0,""} | ||
91 | } | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * these are the tables used by the machine code handlers. | ||
96 | * you can implement pseudo-tty's or something by changing | ||
97 | * them. Currently not done. | ||
98 | */ | ||
99 | struct tty_queue * table_list[]={ | ||
100 | &tty_table[0].read_q, &tty_table[0].write_q, | ||
101 | &tty_table[1].read_q, &tty_table[1].write_q, | ||
102 | &tty_table[2].read_q, &tty_table[2].write_q | ||
103 | }; | ||
104 | |||
105 | void tty_init(void) | ||
106 | { | ||
107 | rs_init(); | ||
108 | con_init(); | ||
109 | } | ||
110 | |||
111 | void tty_intr(struct tty_struct * tty, int mask) | ||
112 | { | ||
113 | int i; | ||
114 | |||
115 | if (tty->pgrp <= 0) | ||
116 | return; | ||
117 | for (i=0;i<NR_TASKS;i++) | ||
118 | if (task[i] && task[i]->pgrp==tty->pgrp) | ||
119 | task[i]->signal |= mask; | ||
120 | } | ||
121 | |||
122 | static void sleep_if_empty(struct tty_queue * queue) | ||
123 | { | ||
124 | cli(); | ||
125 | while (!current->signal && EMPTY(*queue)) | ||
126 | interruptible_sleep_on(&queue->proc_list); | ||
127 | sti(); | ||
128 | } | ||
129 | |||
130 | static void sleep_if_full(struct tty_queue * queue) | ||
131 | { | ||
132 | if (!FULL(*queue)) | ||
133 | return; | ||
134 | cli(); | ||
135 | while (!current->signal && LEFT(*queue)<128) | ||
136 | interruptible_sleep_on(&queue->proc_list); | ||
137 | sti(); | ||
138 | } | ||
139 | |||
140 | void wait_for_keypress(void) | ||
141 | { | ||
142 | sleep_if_empty(&tty_table[0].secondary); | ||
143 | } | ||
144 | |||
145 | void copy_to_cooked(struct tty_struct * tty) | ||
146 | { | ||
147 | signed char c; | ||
148 | |||
149 | while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) { | ||
150 | GETCH(tty->read_q,c); | ||
151 | if (c==13) | ||
152 | if (I_CRNL(tty)) | ||
153 | c=10; | ||
154 | else if (I_NOCR(tty)) | ||
155 | continue; | ||
156 | else ; | ||
157 | else if (c==10 && I_NLCR(tty)) | ||
158 | c=13; | ||
159 | if (I_UCLC(tty)) | ||
160 | c=tolower(c); | ||
161 | if (L_CANON(tty)) { | ||
162 | if (c==KILL_CHAR(tty)) { | ||
163 | /* deal with killing the input line */ | ||
164 | while(!(EMPTY(tty->secondary) || | ||
165 | (c=LAST(tty->secondary))==10 || | ||
166 | c==EOF_CHAR(tty))) { | ||
167 | if (L_ECHO(tty)) { | ||
168 | if (c<32) | ||
169 | PUTCH(127,tty->write_q); | ||
170 | PUTCH(127,tty->write_q); | ||
171 | tty->write(tty); | ||
172 | } | ||
173 | DEC(tty->secondary.head); | ||
174 | } | ||
175 | continue; | ||
176 | } | ||
177 | if (c==ERASE_CHAR(tty)) { | ||
178 | if (EMPTY(tty->secondary) || | ||
179 | (c=LAST(tty->secondary))==10 || | ||
180 | c==EOF_CHAR(tty)) | ||
181 | continue; | ||
182 | if (L_ECHO(tty)) { | ||
183 | if (c<32) | ||
184 | PUTCH(127,tty->write_q); | ||
185 | PUTCH(127,tty->write_q); | ||
186 | tty->write(tty); | ||
187 | } | ||
188 | DEC(tty->secondary.head); | ||
189 | continue; | ||
190 | } | ||
191 | if (c==STOP_CHAR(tty)) { | ||
192 | tty->stopped=1; | ||
193 | continue; | ||
194 | } | ||
195 | if (c==START_CHAR(tty)) { | ||
196 | tty->stopped=0; | ||
197 | continue; | ||
198 | } | ||
199 | } | ||
200 | if (L_ISIG(tty)) { | ||
201 | if (c==INTR_CHAR(tty)) { | ||
202 | tty_intr(tty,INTMASK); | ||
203 | continue; | ||
204 | } | ||
205 | if (c==QUIT_CHAR(tty)) { | ||
206 | tty_intr(tty,QUITMASK); | ||
207 | continue; | ||
208 | } | ||
209 | } | ||
210 | if (c==10 || c==EOF_CHAR(tty)) | ||
211 | tty->secondary.data++; | ||
212 | if (L_ECHO(tty)) { | ||
213 | if (c==10) { | ||
214 | PUTCH(10,tty->write_q); | ||
215 | PUTCH(13,tty->write_q); | ||
216 | } else if (c<32) { | ||
217 | if (L_ECHOCTL(tty)) { | ||
218 | PUTCH('^',tty->write_q); | ||
219 | PUTCH(c+64,tty->write_q); | ||
220 | } | ||
221 | } else | ||
222 | PUTCH(c,tty->write_q); | ||
223 | tty->write(tty); | ||
224 | } | ||
225 | PUTCH(c,tty->secondary); | ||
226 | } | ||
227 | wake_up(&tty->secondary.proc_list); | ||
228 | } | ||
229 | |||
230 | int tty_read(unsigned channel, char * buf, int nr) | ||
231 | { | ||
232 | struct tty_struct * tty; | ||
233 | char c, * b=buf; | ||
234 | int minimum,time,flag=0; | ||
235 | long oldalarm; | ||
236 | |||
237 | if (channel>2 || nr<0) return -1; | ||
238 | tty = &tty_table[channel]; | ||
239 | oldalarm = current->alarm; | ||
240 | time = 10L*tty->termios.c_cc[VTIME]; | ||
241 | minimum = tty->termios.c_cc[VMIN]; | ||
242 | if (time && !minimum) { | ||
243 | minimum=1; | ||
244 | if ((flag=(!oldalarm || time+jiffies<oldalarm))) | ||
245 | current->alarm = time+jiffies; | ||
246 | } | ||
247 | if (minimum>nr) | ||
248 | minimum=nr; | ||
249 | while (nr>0) { | ||
250 | if (flag && (current->signal & ALRMMASK)) { | ||
251 | current->signal &= ~ALRMMASK; | ||
252 | break; | ||
253 | } | ||
254 | if (current->signal) | ||
255 | break; | ||
256 | if (EMPTY(tty->secondary) || (L_CANON(tty) && | ||
257 | !tty->secondary.data && LEFT(tty->secondary)>20)) { | ||
258 | sleep_if_empty(&tty->secondary); | ||
259 | continue; | ||
260 | } | ||
261 | do { | ||
262 | GETCH(tty->secondary,c); | ||
263 | if (c==EOF_CHAR(tty) || c==10) | ||
264 | tty->secondary.data--; | ||
265 | if (c==EOF_CHAR(tty) && L_CANON(tty)) | ||
266 | return (b-buf); | ||
267 | else { | ||
268 | put_fs_byte(c,b++); | ||
269 | if (!--nr) | ||
270 | break; | ||
271 | } | ||
272 | } while (nr>0 && !EMPTY(tty->secondary)); | ||
273 | if (time && !L_CANON(tty)) { | ||
274 | if ((flag=(!oldalarm || time+jiffies<oldalarm))) | ||
275 | current->alarm = time+jiffies; | ||
276 | else | ||
277 | current->alarm = oldalarm; | ||
278 | } | ||
279 | if (L_CANON(tty)) { | ||
280 | if (b-buf) | ||
281 | break; | ||
282 | } else if (b-buf >= minimum) | ||
283 | break; | ||
284 | } | ||
285 | current->alarm = oldalarm; | ||
286 | if (current->signal && !(b-buf)) | ||
287 | return -EINTR; | ||
288 | return (b-buf); | ||
289 | } | ||
290 | |||
291 | int tty_write(unsigned channel, char * buf, int nr) | ||
292 | { | ||
293 | static int cr_flag=0; | ||
294 | struct tty_struct * tty; | ||
295 | char c, *b=buf; | ||
296 | |||
297 | if (channel>2 || nr<0) return -1; | ||
298 | tty = channel + tty_table; | ||
299 | while (nr>0) { | ||
300 | sleep_if_full(&tty->write_q); | ||
301 | if (current->signal) | ||
302 | break; | ||
303 | while (nr>0 && !FULL(tty->write_q)) { | ||
304 | c=get_fs_byte(b); | ||
305 | if (O_POST(tty)) { | ||
306 | if (c=='\r' && O_CRNL(tty)) | ||
307 | c='\n'; | ||
308 | else if (c=='\n' && O_NLRET(tty)) | ||
309 | c='\r'; | ||
310 | if (c=='\n' && !cr_flag && O_NLCR(tty)) { | ||
311 | cr_flag = 1; | ||
312 | PUTCH(13,tty->write_q); | ||
313 | continue; | ||
314 | } | ||
315 | if (O_LCUC(tty)) | ||
316 | c=toupper(c); | ||
317 | } | ||
318 | b++; nr--; | ||
319 | cr_flag = 0; | ||
320 | PUTCH(c,tty->write_q); | ||
321 | } | ||
322 | tty->write(tty); | ||
323 | if (nr>0) | ||
324 | schedule(); | ||
325 | } | ||
326 | return (b-buf); | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * Jeh, sometimes I really like the 386. | ||
331 | * This routine is called from an interrupt, | ||
332 | * and there should be absolutely no problem | ||
333 | * with sleeping even in an interrupt (I hope). | ||
334 | * Of course, if somebody proves me wrong, I'll | ||
335 | * hate intel for all time :-). We'll have to | ||
336 | * be careful and see to reinstating the interrupt | ||
337 | * chips before calling this, though. | ||
338 | * | ||
339 | * I don't think we sleep here under normal circumstances | ||
340 | * anyway, which is good, as the task sleeping might be | ||
341 | * totally innocent. | ||
342 | */ | ||
343 | void do_tty_interrupt(int tty) | ||
344 | { | ||
345 | copy_to_cooked(tty_table+tty); | ||
346 | } | ||
347 | |||
348 | void chr_dev_init(void) | ||
349 | { | ||
350 | } | ||
diff --git a/src/kernel/chr_drv/tty_ioctl.c b/src/kernel/chr_drv/tty_ioctl.c new file mode 100644 index 0000000..e4e3745 --- /dev/null +++ b/src/kernel/chr_drv/tty_ioctl.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * linux/kernel/chr_drv/tty_ioctl.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | #include <termios.h> | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/tty.h> | ||
13 | |||
14 | #include <asm/io.h> | ||
15 | #include <asm/segment.h> | ||
16 | #include <asm/system.h> | ||
17 | |||
18 | static unsigned short quotient[] = { | ||
19 | 0, 2304, 1536, 1047, 857, | ||
20 | 768, 576, 384, 192, 96, | ||
21 | 64, 48, 24, 12, 6, 3 | ||
22 | }; | ||
23 | |||
24 | static void change_speed(struct tty_struct * tty) | ||
25 | { | ||
26 | unsigned short port,quot; | ||
27 | |||
28 | if (!(port = tty->read_q.data)) | ||
29 | return; | ||
30 | quot = quotient[tty->termios.c_cflag & CBAUD]; | ||
31 | cli(); | ||
32 | outb_p(0x80,port+3); /* set DLAB */ | ||
33 | outb_p(quot & 0xff,port); /* LS of divisor */ | ||
34 | outb_p(quot >> 8,port+1); /* MS of divisor */ | ||
35 | outb(0x03,port+3); /* reset DLAB */ | ||
36 | sti(); | ||
37 | } | ||
38 | |||
39 | static void flush(struct tty_queue * queue) | ||
40 | { | ||
41 | cli(); | ||
42 | queue->head = queue->tail; | ||
43 | sti(); | ||
44 | } | ||
45 | |||
46 | static void wait_until_sent(struct tty_struct * tty) | ||
47 | { | ||
48 | /* do nothing - not implemented */ | ||
49 | } | ||
50 | |||
51 | static void send_break(struct tty_struct * tty) | ||
52 | { | ||
53 | /* do nothing - not implemented */ | ||
54 | } | ||
55 | |||
56 | static int get_termios(struct tty_struct * tty, struct termios * termios) | ||
57 | { | ||
58 | int i; | ||
59 | |||
60 | verify_area(termios, sizeof (*termios)); | ||
61 | for (i=0 ; i< (sizeof (*termios)) ; i++) | ||
62 | put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios ); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int set_termios(struct tty_struct * tty, struct termios * termios) | ||
67 | { | ||
68 | int i; | ||
69 | |||
70 | for (i=0 ; i< (sizeof (*termios)) ; i++) | ||
71 | ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); | ||
72 | change_speed(tty); | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int get_termio(struct tty_struct * tty, struct termio * termio) | ||
77 | { | ||
78 | int i; | ||
79 | struct termio tmp_termio; | ||
80 | |||
81 | verify_area(termio, sizeof (*termio)); | ||
82 | tmp_termio.c_iflag = tty->termios.c_iflag; | ||
83 | tmp_termio.c_oflag = tty->termios.c_oflag; | ||
84 | tmp_termio.c_cflag = tty->termios.c_cflag; | ||
85 | tmp_termio.c_lflag = tty->termios.c_lflag; | ||
86 | tmp_termio.c_line = tty->termios.c_line; | ||
87 | for(i=0 ; i < NCC ; i++) | ||
88 | tmp_termio.c_cc[i] = tty->termios.c_cc[i]; | ||
89 | for (i=0 ; i< (sizeof (*termio)) ; i++) | ||
90 | put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * This only works as the 386 is low-byt-first | ||
96 | */ | ||
97 | static int set_termio(struct tty_struct * tty, struct termio * termio) | ||
98 | { | ||
99 | int i; | ||
100 | struct termio tmp_termio; | ||
101 | |||
102 | for (i=0 ; i< (sizeof (*termio)) ; i++) | ||
103 | ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); | ||
104 | *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; | ||
105 | *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; | ||
106 | *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; | ||
107 | *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; | ||
108 | tty->termios.c_line = tmp_termio.c_line; | ||
109 | for(i=0 ; i < NCC ; i++) | ||
110 | tty->termios.c_cc[i] = tmp_termio.c_cc[i]; | ||
111 | change_speed(tty); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | int tty_ioctl(int dev, int cmd, int arg) | ||
116 | { | ||
117 | struct tty_struct * tty; | ||
118 | if (MAJOR(dev) == 5) { | ||
119 | dev=current->tty; | ||
120 | if (dev<0) | ||
121 | panic("tty_ioctl: dev<0"); | ||
122 | } else | ||
123 | dev=MINOR(dev); | ||
124 | tty = dev + tty_table; | ||
125 | switch (cmd) { | ||
126 | case TCGETS: | ||
127 | return get_termios(tty,(struct termios *) arg); | ||
128 | case TCSETSF: | ||
129 | flush(&tty->read_q); /* fallthrough */ | ||
130 | case TCSETSW: | ||
131 | wait_until_sent(tty); /* fallthrough */ | ||
132 | case TCSETS: | ||
133 | return set_termios(tty,(struct termios *) arg); | ||
134 | case TCGETA: | ||
135 | return get_termio(tty,(struct termio *) arg); | ||
136 | case TCSETAF: | ||
137 | flush(&tty->read_q); /* fallthrough */ | ||
138 | case TCSETAW: | ||
139 | wait_until_sent(tty); /* fallthrough */ | ||
140 | case TCSETA: | ||
141 | return set_termio(tty,(struct termio *) arg); | ||
142 | case TCSBRK: | ||
143 | if (!arg) { | ||
144 | wait_until_sent(tty); | ||
145 | send_break(tty); | ||
146 | } | ||
147 | return 0; | ||
148 | case TCXONC: | ||
149 | return -EINVAL; /* not implemented */ | ||
150 | case TCFLSH: | ||
151 | if (arg==0) | ||
152 | flush(&tty->read_q); | ||
153 | else if (arg==1) | ||
154 | flush(&tty->write_q); | ||
155 | else if (arg==2) { | ||
156 | flush(&tty->read_q); | ||
157 | flush(&tty->write_q); | ||
158 | } else | ||
159 | return -EINVAL; | ||
160 | return 0; | ||
161 | case TIOCEXCL: | ||
162 | return -EINVAL; /* not implemented */ | ||
163 | case TIOCNXCL: | ||
164 | return -EINVAL; /* not implemented */ | ||
165 | case TIOCSCTTY: | ||
166 | return -EINVAL; /* set controlling term NI */ | ||
167 | case TIOCGPGRP: | ||
168 | verify_area((void *) arg,4); | ||
169 | put_fs_long(tty->pgrp,(unsigned long *) arg); | ||
170 | return 0; | ||
171 | case TIOCSPGRP: | ||
172 | tty->pgrp=get_fs_long((unsigned long *) arg); | ||
173 | return 0; | ||
174 | case TIOCOUTQ: | ||
175 | verify_area((void *) arg,4); | ||
176 | put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); | ||
177 | return 0; | ||
178 | case TIOCINQ: | ||
179 | verify_area((void *) arg,4); | ||
180 | put_fs_long(CHARS(tty->secondary), | ||
181 | (unsigned long *) arg); | ||
182 | return 0; | ||
183 | case TIOCSTI: | ||
184 | return -EINVAL; /* not implemented */ | ||
185 | case TIOCGWINSZ: | ||
186 | return -EINVAL; /* not implemented */ | ||
187 | case TIOCSWINSZ: | ||
188 | return -EINVAL; /* not implemented */ | ||
189 | case TIOCMGET: | ||
190 | return -EINVAL; /* not implemented */ | ||
191 | case TIOCMBIS: | ||
192 | return -EINVAL; /* not implemented */ | ||
193 | case TIOCMBIC: | ||
194 | return -EINVAL; /* not implemented */ | ||
195 | case TIOCMSET: | ||
196 | return -EINVAL; /* not implemented */ | ||
197 | case TIOCGSOFTCAR: | ||
198 | return -EINVAL; /* not implemented */ | ||
199 | case TIOCSSOFTCAR: | ||
200 | return -EINVAL; /* not implemented */ | ||
201 | default: | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | } | ||