diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/qtronix.c | 605 |
1 files changed, 0 insertions, 605 deletions
diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c deleted file mode 100644 index 5c9477741a30..000000000000 --- a/drivers/char/qtronix.c +++ /dev/null | |||
@@ -1,605 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * BRIEF MODULE DESCRIPTION | ||
4 | * Qtronix 990P infrared keyboard driver. | ||
5 | * | ||
6 | * | ||
7 | * Copyright 2001 MontaVista Software Inc. | ||
8 | * Author: MontaVista Software, Inc. | ||
9 | * ppopov@mvista.com or source@mvista.com | ||
10 | * | ||
11 | * | ||
12 | * The bottom portion of this driver was take from | ||
13 | * pc_keyb.c Please see that file for copyrights. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License as published by the | ||
17 | * Free Software Foundation; either version 2 of the License, or (at your | ||
18 | * option) any later version. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
21 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
23 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
26 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
30 | * | ||
31 | * You should have received a copy of the GNU General Public License along | ||
32 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
33 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
34 | */ | ||
35 | |||
36 | |||
37 | /* | ||
38 | * NOTE: | ||
39 | * | ||
40 | * This driver has only been tested with the Consumer IR | ||
41 | * port of the ITE 8172 system controller. | ||
42 | * | ||
43 | * You do not need this driver if you are using the ps/2 or | ||
44 | * USB adapter that the keyboard ships with. You only need | ||
45 | * this driver if your board has a IR port and the keyboard | ||
46 | * data is being sent directly to the IR. In that case, | ||
47 | * you also need some low-level IR support. See it8172_cir.c. | ||
48 | * | ||
49 | */ | ||
50 | |||
51 | #ifdef CONFIG_QTRONIX_KEYBOARD | ||
52 | |||
53 | #include <linux/module.h> | ||
54 | #include <linux/types.h> | ||
55 | #include <linux/pci.h> | ||
56 | #include <linux/kernel.h> | ||
57 | |||
58 | #include <asm/it8172/it8172.h> | ||
59 | #include <asm/it8172/it8172_int.h> | ||
60 | #include <asm/it8172/it8172_cir.h> | ||
61 | |||
62 | #include <linux/spinlock.h> | ||
63 | #include <linux/sched.h> | ||
64 | #include <linux/interrupt.h> | ||
65 | #include <linux/tty.h> | ||
66 | #include <linux/mm.h> | ||
67 | #include <linux/signal.h> | ||
68 | #include <linux/init.h> | ||
69 | #include <linux/kbd_ll.h> | ||
70 | #include <linux/delay.h> | ||
71 | #include <linux/poll.h> | ||
72 | #include <linux/miscdevice.h> | ||
73 | #include <linux/slab.h> | ||
74 | #include <linux/kbd_kern.h> | ||
75 | #include <linux/smp_lock.h> | ||
76 | #include <asm/io.h> | ||
77 | #include <linux/pc_keyb.h> | ||
78 | |||
79 | #include <asm/keyboard.h> | ||
80 | #include <linux/bitops.h> | ||
81 | #include <asm/uaccess.h> | ||
82 | #include <asm/irq.h> | ||
83 | #include <asm/system.h> | ||
84 | |||
85 | #define leading1 0 | ||
86 | #define leading2 0xF | ||
87 | |||
88 | #define KBD_CIR_PORT 0 | ||
89 | #define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */ | ||
90 | |||
91 | static int data_index; | ||
92 | struct cir_port *cir; | ||
93 | static unsigned char kbdbytes[5]; | ||
94 | static unsigned char cir_data[32]; /* we only need 16 chars */ | ||
95 | |||
96 | static void kbd_int_handler(int irq, void *dev_id); | ||
97 | static int handle_data(unsigned char *p_data); | ||
98 | static inline void handle_mouse_event(unsigned char scancode); | ||
99 | static inline void handle_keyboard_event(unsigned char scancode, int down); | ||
100 | static int __init psaux_init(void); | ||
101 | |||
102 | static struct aux_queue *queue; /* Mouse data buffer. */ | ||
103 | static int aux_count = 0; | ||
104 | |||
105 | /* | ||
106 | * Keys accessed through the 'Fn' key | ||
107 | * The Fn key does not produce a key-up sequence. So, the first | ||
108 | * time the user presses it, it will be key-down event. The key | ||
109 | * stays down until the user presses it again. | ||
110 | */ | ||
111 | #define NUM_FN_KEYS 56 | ||
112 | static unsigned char fn_keys[NUM_FN_KEYS] = { | ||
113 | 0,0,0,0,0,0,0,0, /* 0 7 */ | ||
114 | 8,9,10,93,0,0,0,0, /* 8 15 */ | ||
115 | 0,0,0,0,0,0,0,5, /* 16 23 */ | ||
116 | 6,7,91,0,0,0,0,0, /* 24 31 */ | ||
117 | 0,0,0,0,0,2,3,4, /* 32 39 */ | ||
118 | 92,0,0,0,0,0,0,0, /* 40 47 */ | ||
119 | 0,0,0,0,11,0,94,95 /* 48 55 */ | ||
120 | |||
121 | }; | ||
122 | |||
123 | void __init init_qtronix_990P_kbd(void) | ||
124 | { | ||
125 | int retval; | ||
126 | |||
127 | cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL); | ||
128 | if (!cir) { | ||
129 | printk("Unable to initialize Qtronix keyboard\n"); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * revisit | ||
135 | * this should be programmable, somehow by the, by the user. | ||
136 | */ | ||
137 | cir->port = KBD_CIR_PORT; | ||
138 | cir->baud_rate = 0x1d; | ||
139 | cir->rdwos = 0; | ||
140 | cir->rxdcr = 0x3; | ||
141 | cir->hcfs = 0; | ||
142 | cir->fifo_tl = 0; | ||
143 | cir->cfq = 0x1d; | ||
144 | cir_port_init(cir); | ||
145 | |||
146 | retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler, | ||
147 | (unsigned long )(IRQF_DISABLED|IRQF_SHARED), | ||
148 | (const char *)"Qtronix IR Keyboard", (void *)cir); | ||
149 | |||
150 | if (retval) { | ||
151 | printk("unable to allocate cir %d irq %d\n", | ||
152 | cir->port, IT8172_CIR0_IRQ); | ||
153 | } | ||
154 | #ifdef CONFIG_PSMOUSE | ||
155 | psaux_init(); | ||
156 | #endif | ||
157 | } | ||
158 | |||
159 | static inline unsigned char BitReverse(unsigned short key) | ||
160 | { | ||
161 | unsigned char rkey = 0; | ||
162 | rkey |= (key & 0x1) << 7; | ||
163 | rkey |= (key & 0x2) << 5; | ||
164 | rkey |= (key & 0x4) << 3; | ||
165 | rkey |= (key & 0x8) << 1; | ||
166 | rkey |= (key & 0x10) >> 1; | ||
167 | rkey |= (key & 0x20) >> 3; | ||
168 | rkey |= (key & 0x40) >> 5; | ||
169 | rkey |= (key & 0x80) >> 7; | ||
170 | return rkey; | ||
171 | |||
172 | } | ||
173 | |||
174 | |||
175 | static inline u_int8_t UpperByte(u_int8_t data) | ||
176 | { | ||
177 | return (data >> 4); | ||
178 | } | ||
179 | |||
180 | |||
181 | static inline u_int8_t LowerByte(u_int8_t data) | ||
182 | { | ||
183 | return (data & 0xF); | ||
184 | } | ||
185 | |||
186 | |||
187 | int CheckSumOk(u_int8_t byte1, u_int8_t byte2, | ||
188 | u_int8_t byte3, u_int8_t byte4, u_int8_t byte5) | ||
189 | { | ||
190 | u_int8_t CheckSum; | ||
191 | |||
192 | CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5; | ||
193 | if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) ) | ||
194 | return 0; | ||
195 | else | ||
196 | return 1; | ||
197 | } | ||
198 | |||
199 | |||
200 | static void kbd_int_handler(int irq, void *dev_id) | ||
201 | { | ||
202 | struct cir_port *cir; | ||
203 | int j; | ||
204 | unsigned char int_status; | ||
205 | |||
206 | cir = (struct cir_port *)dev_id; | ||
207 | int_status = get_int_status(cir); | ||
208 | if (int_status & 0x4) { | ||
209 | clear_fifo(cir); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | while (cir_get_rx_count(cir)) { | ||
214 | |||
215 | cir_data[data_index] = cir_read_data(cir); | ||
216 | |||
217 | if (data_index == 0) {/* expecting first byte */ | ||
218 | if (cir_data[data_index] != leading1) { | ||
219 | //printk("!leading byte %x\n", cir_data[data_index]); | ||
220 | set_rx_active(cir); | ||
221 | clear_fifo(cir); | ||
222 | continue; | ||
223 | } | ||
224 | } | ||
225 | if (data_index == 1) { | ||
226 | if ((cir_data[data_index] & 0xf) != leading2) { | ||
227 | set_rx_active(cir); | ||
228 | data_index = 0; /* start over */ | ||
229 | clear_fifo(cir); | ||
230 | continue; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | if ( (cir_data[data_index] == 0xff)) { /* last byte */ | ||
235 | //printk("data_index %d\n", data_index); | ||
236 | set_rx_active(cir); | ||
237 | #if 0 | ||
238 | for (j=0; j<=data_index; j++) { | ||
239 | printk("rx_data %d: %x\n", j, cir_data[j]); | ||
240 | } | ||
241 | #endif | ||
242 | data_index = 0; | ||
243 | handle_data(cir_data); | ||
244 | return; | ||
245 | } | ||
246 | else if (data_index>16) { | ||
247 | set_rx_active(cir); | ||
248 | #if 0 | ||
249 | printk("warning: data_index %d\n", data_index); | ||
250 | for (j=0; j<=data_index; j++) { | ||
251 | printk("rx_data %d: %x\n", j, cir_data[j]); | ||
252 | } | ||
253 | #endif | ||
254 | data_index = 0; | ||
255 | clear_fifo(cir); | ||
256 | return; | ||
257 | } | ||
258 | data_index++; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | #define NUM_KBD_BYTES 5 | ||
264 | static int handle_data(unsigned char *p_data) | ||
265 | { | ||
266 | u_int32_t bit_bucket; | ||
267 | u_int32_t i, j; | ||
268 | u_int32_t got_bits, next_byte; | ||
269 | int down = 0; | ||
270 | |||
271 | /* Reorganize the bit stream */ | ||
272 | for (i=0; i<16; i++) | ||
273 | p_data[i] = BitReverse(~p_data[i]); | ||
274 | |||
275 | /* | ||
276 | * We've already previously checked that p_data[0] | ||
277 | * is equal to leading1 and that (p_data[1] & 0xf) | ||
278 | * is equal to leading2. These twelve bits are the | ||
279 | * leader code. We can now throw them away (the 12 | ||
280 | * bits) and continue parsing the stream. | ||
281 | */ | ||
282 | bit_bucket = p_data[1] << 12; | ||
283 | got_bits = 4; | ||
284 | next_byte = 2; | ||
285 | |||
286 | /* | ||
287 | * Process four bits at a time | ||
288 | */ | ||
289 | for (i=0; i<NUM_KBD_BYTES; i++) { | ||
290 | |||
291 | kbdbytes[i]=0; | ||
292 | |||
293 | for (j=0; j<8; j++) /* 8 bits per byte */ | ||
294 | { | ||
295 | if (got_bits < 4) { | ||
296 | bit_bucket |= (p_data[next_byte++] << (8 - got_bits)); | ||
297 | got_bits += 8; | ||
298 | } | ||
299 | |||
300 | if ((bit_bucket & 0xF000) == 0x8000) { | ||
301 | /* Convert 1000b to 1 */ | ||
302 | kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1); | ||
303 | got_bits -= 4; | ||
304 | bit_bucket = bit_bucket << 4; | ||
305 | } | ||
306 | else if ((bit_bucket & 0xC000) == 0x8000) { | ||
307 | /* Convert 10b to 0 */ | ||
308 | kbdbytes[i] = kbdbytes[i] >> 1; | ||
309 | got_bits -= 2; | ||
310 | bit_bucket = bit_bucket << 2; | ||
311 | } | ||
312 | else { | ||
313 | /* bad serial stream */ | ||
314 | return 1; | ||
315 | } | ||
316 | |||
317 | if (next_byte > 16) { | ||
318 | //printk("error: too many bytes\n"); | ||
319 | return 1; | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | |||
324 | |||
325 | if (!CheckSumOk(kbdbytes[0], kbdbytes[1], | ||
326 | kbdbytes[2], kbdbytes[3], kbdbytes[4])) { | ||
327 | //printk("checksum failed\n"); | ||
328 | return 1; | ||
329 | } | ||
330 | |||
331 | if (kbdbytes[1] & 0x08) { | ||
332 | //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]); | ||
333 | handle_mouse_event(kbdbytes[1]); | ||
334 | handle_mouse_event(kbdbytes[2]); | ||
335 | handle_mouse_event(kbdbytes[3]); | ||
336 | } | ||
337 | else { | ||
338 | if (kbdbytes[2] == 0) down = 1; | ||
339 | #if 0 | ||
340 | if (down) | ||
341 | printk("down %d\n", kbdbytes[3]); | ||
342 | else | ||
343 | printk("up %d\n", kbdbytes[3]); | ||
344 | #endif | ||
345 | handle_keyboard_event(kbdbytes[3], down); | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | |||
351 | DEFINE_SPINLOCK(kbd_controller_lock); | ||
352 | static unsigned char handle_kbd_event(void); | ||
353 | |||
354 | |||
355 | int kbd_setkeycode(unsigned int scancode, unsigned int keycode) | ||
356 | { | ||
357 | printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | int kbd_getkeycode(unsigned int scancode) | ||
362 | { | ||
363 | return scancode; | ||
364 | } | ||
365 | |||
366 | |||
367 | int kbd_translate(unsigned char scancode, unsigned char *keycode, | ||
368 | char raw_mode) | ||
369 | { | ||
370 | static int prev_scancode = 0; | ||
371 | |||
372 | if (scancode == 0x00 || scancode == 0xff) { | ||
373 | prev_scancode = 0; | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | /* todo */ | ||
378 | if (!prev_scancode && scancode == 160) { /* Fn key down */ | ||
379 | //printk("Fn key down\n"); | ||
380 | prev_scancode = 160; | ||
381 | return 0; | ||
382 | } | ||
383 | else if (prev_scancode && scancode == 160) { /* Fn key up */ | ||
384 | //printk("Fn key up\n"); | ||
385 | prev_scancode = 0; | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | /* todo */ | ||
390 | if (prev_scancode == 160) { | ||
391 | if (scancode <= NUM_FN_KEYS) { | ||
392 | *keycode = fn_keys[scancode]; | ||
393 | //printk("fn keycode %d\n", *keycode); | ||
394 | } | ||
395 | else | ||
396 | return 0; | ||
397 | } | ||
398 | else if (scancode <= 127) { | ||
399 | *keycode = scancode; | ||
400 | } | ||
401 | else | ||
402 | return 0; | ||
403 | |||
404 | |||
405 | return 1; | ||
406 | } | ||
407 | |||
408 | char kbd_unexpected_up(unsigned char keycode) | ||
409 | { | ||
410 | //printk("kbd_unexpected_up\n"); | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static unsigned char kbd_exists = 1; | ||
415 | |||
416 | static inline void handle_keyboard_event(unsigned char scancode, int down) | ||
417 | { | ||
418 | kbd_exists = 1; | ||
419 | handle_scancode(scancode, down); | ||
420 | tasklet_schedule(&keyboard_tasklet); | ||
421 | } | ||
422 | |||
423 | |||
424 | void kbd_leds(unsigned char leds) | ||
425 | { | ||
426 | } | ||
427 | |||
428 | /* dummy */ | ||
429 | void kbd_init_hw(void) | ||
430 | { | ||
431 | } | ||
432 | |||
433 | |||
434 | |||
435 | static inline void handle_mouse_event(unsigned char scancode) | ||
436 | { | ||
437 | if(scancode == AUX_RECONNECT){ | ||
438 | queue->head = queue->tail = 0; /* Flush input queue */ | ||
439 | // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ | ||
440 | return; | ||
441 | } | ||
442 | |||
443 | if (aux_count) { | ||
444 | int head = queue->head; | ||
445 | |||
446 | queue->buf[head] = scancode; | ||
447 | head = (head + 1) & (AUX_BUF_SIZE-1); | ||
448 | if (head != queue->tail) { | ||
449 | queue->head = head; | ||
450 | kill_fasync(&queue->fasync, SIGIO, POLL_IN); | ||
451 | wake_up_interruptible(&queue->proc_list); | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static unsigned char get_from_queue(void) | ||
457 | { | ||
458 | unsigned char result; | ||
459 | unsigned long flags; | ||
460 | |||
461 | spin_lock_irqsave(&kbd_controller_lock, flags); | ||
462 | result = queue->buf[queue->tail]; | ||
463 | queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); | ||
464 | spin_unlock_irqrestore(&kbd_controller_lock, flags); | ||
465 | return result; | ||
466 | } | ||
467 | |||
468 | |||
469 | static inline int queue_empty(void) | ||
470 | { | ||
471 | return queue->head == queue->tail; | ||
472 | } | ||
473 | |||
474 | static int fasync_aux(int fd, struct file *filp, int on) | ||
475 | { | ||
476 | int retval; | ||
477 | |||
478 | //printk("fasync_aux\n"); | ||
479 | retval = fasync_helper(fd, filp, on, &queue->fasync); | ||
480 | if (retval < 0) | ||
481 | return retval; | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | |||
486 | /* | ||
487 | * Random magic cookie for the aux device | ||
488 | */ | ||
489 | #define AUX_DEV ((void *)queue) | ||
490 | |||
491 | static int release_aux(struct inode * inode, struct file * file) | ||
492 | { | ||
493 | fasync_aux(-1, file, 0); | ||
494 | aux_count--; | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static int open_aux(struct inode * inode, struct file * file) | ||
499 | { | ||
500 | if (aux_count++) { | ||
501 | return 0; | ||
502 | } | ||
503 | queue->head = queue->tail = 0; /* Flush input queue */ | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * Put bytes from input queue to buffer. | ||
509 | */ | ||
510 | |||
511 | static ssize_t read_aux(struct file * file, char * buffer, | ||
512 | size_t count, loff_t *ppos) | ||
513 | { | ||
514 | DECLARE_WAITQUEUE(wait, current); | ||
515 | ssize_t i = count; | ||
516 | unsigned char c; | ||
517 | |||
518 | if (queue_empty()) { | ||
519 | if (file->f_flags & O_NONBLOCK) | ||
520 | return -EAGAIN; | ||
521 | add_wait_queue(&queue->proc_list, &wait); | ||
522 | repeat: | ||
523 | set_current_state(TASK_INTERRUPTIBLE); | ||
524 | if (queue_empty() && !signal_pending(current)) { | ||
525 | schedule(); | ||
526 | goto repeat; | ||
527 | } | ||
528 | current->state = TASK_RUNNING; | ||
529 | remove_wait_queue(&queue->proc_list, &wait); | ||
530 | } | ||
531 | while (i > 0 && !queue_empty()) { | ||
532 | c = get_from_queue(); | ||
533 | put_user(c, buffer++); | ||
534 | i--; | ||
535 | } | ||
536 | if (count-i) { | ||
537 | struct inode *inode = file->f_dentry->d_inode; | ||
538 | inode->i_atime = current_fs_time(inode->i_sb); | ||
539 | return count-i; | ||
540 | } | ||
541 | if (signal_pending(current)) | ||
542 | return -ERESTARTSYS; | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * Write to the aux device. | ||
548 | */ | ||
549 | |||
550 | static ssize_t write_aux(struct file * file, const char * buffer, | ||
551 | size_t count, loff_t *ppos) | ||
552 | { | ||
553 | /* | ||
554 | * The ITE boards this was tested on did not have the | ||
555 | * transmit wires connected. | ||
556 | */ | ||
557 | return count; | ||
558 | } | ||
559 | |||
560 | static unsigned int aux_poll(struct file *file, poll_table * wait) | ||
561 | { | ||
562 | poll_wait(file, &queue->proc_list, wait); | ||
563 | if (!queue_empty()) | ||
564 | return POLLIN | POLLRDNORM; | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | struct file_operations psaux_fops = { | ||
569 | .read = read_aux, | ||
570 | .write = write_aux, | ||
571 | .poll = aux_poll, | ||
572 | .open = open_aux, | ||
573 | .release = release_aux, | ||
574 | .fasync = fasync_aux, | ||
575 | }; | ||
576 | |||
577 | /* | ||
578 | * Initialize driver. | ||
579 | */ | ||
580 | static struct miscdevice psaux_mouse = { | ||
581 | PSMOUSE_MINOR, "psaux", &psaux_fops | ||
582 | }; | ||
583 | |||
584 | static int __init psaux_init(void) | ||
585 | { | ||
586 | int retval; | ||
587 | |||
588 | retval = misc_register(&psaux_mouse); | ||
589 | if(retval < 0) | ||
590 | return retval; | ||
591 | |||
592 | queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); | ||
593 | if (!queue) { | ||
594 | misc_deregister(&psaux_mouse); | ||
595 | return -ENOMEM; | ||
596 | } | ||
597 | |||
598 | memset(queue, 0, sizeof(*queue)); | ||
599 | queue->head = queue->tail = 0; | ||
600 | init_waitqueue_head(&queue->proc_list); | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | module_init(init_qtronix_990P_kbd); | ||
605 | #endif | ||