字符设备-seria.c tty_io.c seria.c rs_io.s tty_iocnl.c tty.h termios.h keyboard.s源码分析
2015-06-12 15:50
645 查看
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 */
16 #include <linux/tty.h>
17 #include <linux/sched.h>
18 #include <asm/system.h>
19 #include <asm/io.h>
21 #define WAKEUP_CHARS (TTY_BUF_SIZE/4)
23 extern void rs1_interrupt(void);
24 extern void rs2_interrupt(void);
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 }
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 }
ttyio.c
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 }
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 }
140 void wait_for_keypress(void)
141 {
142 sleep_if_empty(&tty_table[0].secondary);
143 }
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 }
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 if (L_CANON(tty)) {
279 if (b-buf)
280 break;
281 } else if (b-buf >= minimum)
282 break;
283 }
284 current->alarm = oldalarm;
285 if (current->signal && !(b-buf))
286 return -EINTR;
287 return (b-buf);
288 }
290 int tty_write(unsigned channel, char * buf, int nr)
291 {
292 static cr_flag=0;
293 struct tty_struct * tty;
294 char c, *b=buf;
295
296 if (channel>2 || nr<0) return -1;
297 tty = channel + tty_table;
298 while (nr>0) {
299 sleep_if_full(&tty->write_q);
300 if (current->signal)
301 break;
302 while (nr>0 && !FULL(tty->write_q)) {
303 c=get_fs_byte(b);
304 if (O_POST(tty)) {
305 if (c=='\r' && O_CRNL(tty))
306 c='\n';
307 else if (c=='\n' && O_NLRET(tty))
308 c='\r';
309 if (c=='\n' && !cr_flag && O_NLCR(tty)) {
310 cr_flag = 1;
311 PUTCH(13,tty->write_q);
312 continue;
313 }
314 if (O_LCUC(tty))
315 c=toupper(c);
316 }
317 b++; nr--;
318 cr_flag = 0;
319 PUTCH(c,tty->write_q);
320 }
321 tty->write(tty);
322 if (nr>0)
323 schedule();
324 }
325 return (b-buf);
326 }
328 /*
329 * Jeh, sometimes I really like the 386.
330 * This routine is called from an interrupt,
331 * and there should be absolutely no problem
332 * with sleeping even in an interrupt (I hope).
333 * Of course, if somebody proves me wrong, I'll
334 * hate intel for all time :-). We'll have to
335 * be careful and see to reinstating the interrupt
336 * chips before calling this, though.
337 *
338 * I don't think we sleep here under normal circumstances
339 * anyway, which is good, as the task sleeping might be
340 * totally innocent.
341 */
342 void do_tty_interrupt(int tty)
343 {
344 copy_to_cooked(tty_table+tty);
345 }
346
347 void chr_dev_init(void)
348 {
349 }
tty_iocnlt.c
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 }
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 }
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 }
rs_io.s
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
include/linux/tty.h
1 /*
2 * 'tty.h' defines some structures used by tty_io.c and some defines.
3 *
4 * NOTE! Don't touch this without checking that nothing in rs_io.s or
5 * con_io.s breaks. Some constants are hardwired into the system (mainly
6 * offsets into 'tty_queue'
7 */
8
9 #ifndef _TTY_H
10 #define _TTY_H
11
12 #include <termios.h>
13
14 #define TTY_BUF_SIZE 1024
15
16 struct tty_queue {
17 unsigned long data; //缓冲区数据统计值
18 unsigned long head; //缓冲区队首
19 unsigned long tail; //缓冲区队尾
20 struct task_struct * proc_list; //等待缓冲区的进程
21 char buf[TTY_BUF_SIZE]; //缓冲区
22 };
23
24 #define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
25 #define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
26 #define EMPTY(a) ((a).head == (a).tail)
27 #define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1))
28 #define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)])
29 #define FULL(a) (!LEFT(a))
30 #define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1))
31 #define GETCH(queue,c) \
32 (void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
33 #define PUTCH(c,queue) \
34 (void)({(queue).buf[(queue).head]=(c);INC((queue).head);})
35
36 #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
37 #define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
38 #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
39 #define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL])
40 #define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
41 #define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
42 #define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
43 #define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP])
44
45 struct tty_struct {
46 struct termios termios; //终端io属性和控制字符数据结构
47 int pgrp; //所属进程组
48 int stopped; //停止标志
49 void (*write)(struct tty_struct * tty); //tty函数指针
50 struct tty_queue read_q; //读队列
51 struct tty_queue write_q; //写队列
52 struct tty_queue secondary; //辅助队列
53 };
54
55 extern struct tty_struct tty_table[];
56
57 /* intr=^C quit=^| erase=del kill=^U
58 eof=^D vtime=\0 vmin=\1 sxtc=\0
59 start=^Q stop=^S susp=^Z eol=\0
60 reprint=^R discard=^U werase=^W lnext=^V
61 eol2=\0
62 */
63 #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
64
65 void rs_init(void);
66 void con_init(void);
67 void tty_init(void);
68
69 int tty_read(unsigned c, char * buf, int n);
70 int tty_write(unsigned c, char * buf, int n);
71
72 void rs_write(struct tty_struct * tty);
73 void con_write(struct tty_struct * tty);
74
75 void copy_to_cooked(struct tty_struct * tty);
76
77 #endif
termios.h
36 struct winsize {
37 unsigned short ws_row;
38 unsigned short ws_col;
39 unsigned short ws_xpixel;
40 unsigned short ws_ypixel;
41 };
43 #define NCC 8
44 struct termio {
45 unsigned short c_iflag; /* input mode flags */
46 unsigned short c_oflag; /* output mode flags */
47 unsigned short c_cflag; /* control mode flags */
48 unsigned short c_lflag; /* local mode flags */
49 unsigned char c_line; /* line discipline */
50 unsigned char c_cc[NCC]; /* control characters */
51 };
52
53 #define NCCS 17
54 struct termios {
55 unsigned long c_iflag; /* input mode flags */
56 unsigned long c_oflag; /* output mode flags */
57 unsigned long c_cflag; /* control mode flags */
58 unsigned long c_lflag; /* local mode flags */
59 unsigned char c_line; /* line discipline */
60 unsigned char c_cc[NCCS]; /* control characters */
61 };
keyboard.s
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 !!!! */
size是键盘缓冲区队列长度
23 head = 4
24 tail = 8
25 proc_list = 12
26 buf = 16
上面的值是字段在tty_queue中的偏移
28 mode: .byte 0 /* caps, alt, ctrl and shift mode */
一个byte不同的bit代表不同的键按下
29 leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
同样不同的位代表不同的按键状态
30 e0: .byte 0
扫描码为0xe0或0xe1时,设置该标志。当扫描码为0xe0时,说明后面还有一个字符;当扫描码为0xe1时说明后面还有两个字符
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 xorl %al,%al /* %eax is scan code */
48 inb $0x60,%al //从键盘控制器相应端口0x60读入扫描码
49 cmpb $0xe0,%al //如果是0xe0说明后面还有一个字符
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 //al位7置位,禁止键盘工作
59 jmp 1f
60 1: jmp 1f
61 1: outb %al,$0x61 //写入到端口中,禁止键盘工作
62 jmp 1f
63 1: jmp 1f
64 1: andb $0x7F,%al //al位7复位
65 outb %al,$0x61 //允许键盘工作
66 movb $0x20,%al //
67 outb %al,$0x20 //向8259发送结束中断命令
68 pushl $0 //控制台tty号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
83 /*
84 * This routine fills the buffer with max 8 bytes, taken from
85 * %ebx:%eax. (%ebx 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) //al放到头部
94 incl %ecx //增加头指针
95 andl $size-1,%ecx //&
96 cmpl tail(%edx),%ecx # buffer full - discard everything
97 je 3f //缓冲区满的话跳到3
98 shrdl $8,%ebx,%eax //将ebx中的8个比特右移到eax,ebx保持不变
99 je 2f //如果没有数据就跳到2:
100 shrl $8,%ebx //ebx右移8位
101 jmp 1b //跳转到1,也就是这里是循环把数据存入缓冲区
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
put_queue会在相应键的处理过程中调用来把处理过的扫描码放到队列中
下面是跳转表中各键处理子程序
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
以下是扫描码与ASCII字符映射转换
KBD_FINNISH是include/linux/config.h中的键盘类型
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
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
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
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 ? ? ? ? */
我们获取键盘扫描码后根据跳转表进行跳转
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
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 */
16 #include <linux/tty.h>
17 #include <linux/sched.h>
18 #include <asm/system.h>
19 #include <asm/io.h>
21 #define WAKEUP_CHARS (TTY_BUF_SIZE/4)
23 extern void rs1_interrupt(void);
24 extern void rs2_interrupt(void);
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 }
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 }
ttyio.c
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 }
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 }
140 void wait_for_keypress(void)
141 {
142 sleep_if_empty(&tty_table[0].secondary);
143 }
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 }
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 if (L_CANON(tty)) {
279 if (b-buf)
280 break;
281 } else if (b-buf >= minimum)
282 break;
283 }
284 current->alarm = oldalarm;
285 if (current->signal && !(b-buf))
286 return -EINTR;
287 return (b-buf);
288 }
290 int tty_write(unsigned channel, char * buf, int nr)
291 {
292 static cr_flag=0;
293 struct tty_struct * tty;
294 char c, *b=buf;
295
296 if (channel>2 || nr<0) return -1;
297 tty = channel + tty_table;
298 while (nr>0) {
299 sleep_if_full(&tty->write_q);
300 if (current->signal)
301 break;
302 while (nr>0 && !FULL(tty->write_q)) {
303 c=get_fs_byte(b);
304 if (O_POST(tty)) {
305 if (c=='\r' && O_CRNL(tty))
306 c='\n';
307 else if (c=='\n' && O_NLRET(tty))
308 c='\r';
309 if (c=='\n' && !cr_flag && O_NLCR(tty)) {
310 cr_flag = 1;
311 PUTCH(13,tty->write_q);
312 continue;
313 }
314 if (O_LCUC(tty))
315 c=toupper(c);
316 }
317 b++; nr--;
318 cr_flag = 0;
319 PUTCH(c,tty->write_q);
320 }
321 tty->write(tty);
322 if (nr>0)
323 schedule();
324 }
325 return (b-buf);
326 }
328 /*
329 * Jeh, sometimes I really like the 386.
330 * This routine is called from an interrupt,
331 * and there should be absolutely no problem
332 * with sleeping even in an interrupt (I hope).
333 * Of course, if somebody proves me wrong, I'll
334 * hate intel for all time :-). We'll have to
335 * be careful and see to reinstating the interrupt
336 * chips before calling this, though.
337 *
338 * I don't think we sleep here under normal circumstances
339 * anyway, which is good, as the task sleeping might be
340 * totally innocent.
341 */
342 void do_tty_interrupt(int tty)
343 {
344 copy_to_cooked(tty_table+tty);
345 }
346
347 void chr_dev_init(void)
348 {
349 }
tty_iocnlt.c
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 }
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 }
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 }
rs_io.s
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
include/linux/tty.h
1 /*
2 * 'tty.h' defines some structures used by tty_io.c and some defines.
3 *
4 * NOTE! Don't touch this without checking that nothing in rs_io.s or
5 * con_io.s breaks. Some constants are hardwired into the system (mainly
6 * offsets into 'tty_queue'
7 */
8
9 #ifndef _TTY_H
10 #define _TTY_H
11
12 #include <termios.h>
13
14 #define TTY_BUF_SIZE 1024
15
16 struct tty_queue {
17 unsigned long data; //缓冲区数据统计值
18 unsigned long head; //缓冲区队首
19 unsigned long tail; //缓冲区队尾
20 struct task_struct * proc_list; //等待缓冲区的进程
21 char buf[TTY_BUF_SIZE]; //缓冲区
22 };
23
24 #define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
25 #define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
26 #define EMPTY(a) ((a).head == (a).tail)
27 #define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1))
28 #define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)])
29 #define FULL(a) (!LEFT(a))
30 #define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1))
31 #define GETCH(queue,c) \
32 (void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
33 #define PUTCH(c,queue) \
34 (void)({(queue).buf[(queue).head]=(c);INC((queue).head);})
35
36 #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
37 #define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
38 #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
39 #define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL])
40 #define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
41 #define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
42 #define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
43 #define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP])
44
45 struct tty_struct {
46 struct termios termios; //终端io属性和控制字符数据结构
47 int pgrp; //所属进程组
48 int stopped; //停止标志
49 void (*write)(struct tty_struct * tty); //tty函数指针
50 struct tty_queue read_q; //读队列
51 struct tty_queue write_q; //写队列
52 struct tty_queue secondary; //辅助队列
53 };
54
55 extern struct tty_struct tty_table[];
56
57 /* intr=^C quit=^| erase=del kill=^U
58 eof=^D vtime=\0 vmin=\1 sxtc=\0
59 start=^Q stop=^S susp=^Z eol=\0
60 reprint=^R discard=^U werase=^W lnext=^V
61 eol2=\0
62 */
63 #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
64
65 void rs_init(void);
66 void con_init(void);
67 void tty_init(void);
68
69 int tty_read(unsigned c, char * buf, int n);
70 int tty_write(unsigned c, char * buf, int n);
71
72 void rs_write(struct tty_struct * tty);
73 void con_write(struct tty_struct * tty);
74
75 void copy_to_cooked(struct tty_struct * tty);
76
77 #endif
termios.h
36 struct winsize {
37 unsigned short ws_row;
38 unsigned short ws_col;
39 unsigned short ws_xpixel;
40 unsigned short ws_ypixel;
41 };
43 #define NCC 8
44 struct termio {
45 unsigned short c_iflag; /* input mode flags */
46 unsigned short c_oflag; /* output mode flags */
47 unsigned short c_cflag; /* control mode flags */
48 unsigned short c_lflag; /* local mode flags */
49 unsigned char c_line; /* line discipline */
50 unsigned char c_cc[NCC]; /* control characters */
51 };
52
53 #define NCCS 17
54 struct termios {
55 unsigned long c_iflag; /* input mode flags */
56 unsigned long c_oflag; /* output mode flags */
57 unsigned long c_cflag; /* control mode flags */
58 unsigned long c_lflag; /* local mode flags */
59 unsigned char c_line; /* line discipline */
60 unsigned char c_cc[NCCS]; /* control characters */
61 };
keyboard.s
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 !!!! */
size是键盘缓冲区队列长度
23 head = 4
24 tail = 8
25 proc_list = 12
26 buf = 16
上面的值是字段在tty_queue中的偏移
28 mode: .byte 0 /* caps, alt, ctrl and shift mode */
一个byte不同的bit代表不同的键按下
29 leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */
同样不同的位代表不同的按键状态
30 e0: .byte 0
扫描码为0xe0或0xe1时,设置该标志。当扫描码为0xe0时,说明后面还有一个字符;当扫描码为0xe1时说明后面还有两个字符
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 xorl %al,%al /* %eax is scan code */
48 inb $0x60,%al //从键盘控制器相应端口0x60读入扫描码
49 cmpb $0xe0,%al //如果是0xe0说明后面还有一个字符
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 //al位7置位,禁止键盘工作
59 jmp 1f
60 1: jmp 1f
61 1: outb %al,$0x61 //写入到端口中,禁止键盘工作
62 jmp 1f
63 1: jmp 1f
64 1: andb $0x7F,%al //al位7复位
65 outb %al,$0x61 //允许键盘工作
66 movb $0x20,%al //
67 outb %al,$0x20 //向8259发送结束中断命令
68 pushl $0 //控制台tty号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
83 /*
84 * This routine fills the buffer with max 8 bytes, taken from
85 * %ebx:%eax. (%ebx 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) //al放到头部
94 incl %ecx //增加头指针
95 andl $size-1,%ecx //&
96 cmpl tail(%edx),%ecx # buffer full - discard everything
97 je 3f //缓冲区满的话跳到3
98 shrdl $8,%ebx,%eax //将ebx中的8个比特右移到eax,ebx保持不变
99 je 2f //如果没有数据就跳到2:
100 shrl $8,%ebx //ebx右移8位
101 jmp 1b //跳转到1,也就是这里是循环把数据存入缓冲区
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
put_queue会在相应键的处理过程中调用来把处理过的扫描码放到队列中
下面是跳转表中各键处理子程序
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
以下是扫描码与ASCII字符映射转换
KBD_FINNISH是include/linux/config.h中的键盘类型
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
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
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
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 ? ? ? ? */
我们获取键盘扫描码后根据跳转表进行跳转
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
相关文章推荐
- iOS coreData
- ios打包出来为pkg的处理方法
- IOS Block回调 精简代码示例
- ios实现两个tableview联动
- Cisco 12系列 AP 初始化配置-1-安装IOS
- IOS开发模块总结(一)本地数据存储1 plist
- iOS 图标、图形尺寸?
- 编译ffmpeg for iOS
- iOS开发常见文件--Info.plist
- iOS开发常见文件--pch
- IOS 疯狂基础之 页面间跳转
- ios项目icon和default 等相关图标命名规则和大小设置
- iOS 9允许开发者只为64位设备开发应用
- iOS block的用法 by -- 周傅琦君
- 【iOS开发】关于图片加载的第三方框架SDWebImage的使用
- IOS 使用XIB 自定义View
- IOS开发之多态
- ios启动界面和icon设置
- 高仿土豆视频iOS版
- IOS 2G 3G 4G WIFI