📄 pc_keyb.c
字号:
printk(KERN_WARNING "Keyboard timeout[2] 0x%x\n",data);#endif#if defined(CONFIG_OCTOPUS) kbd_clear_input();#endif return 0; } } } while (retries-- > 0);#ifdef KBD_REPORT_TIMEOUTS printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");#endif return 0;}void pckbd_leds(unsigned char leds){ if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds)) send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */}/* * In case we run on a non-x86 hardware we need to initialize both the * keyboard controller and the keyboard. On a x86, the BIOS will * already have initialized them. * * Some x86 BIOSes do not correctly initialize the keyboard, so the * "kbd-reset" command line options can be given to force a reset. * [Ranger] */#ifdef __i386__ int kbd_startup_reset __initdata = 0;#else int kbd_startup_reset __initdata = 1;#endif/* for "kbd-reset" cmdline param */void __init kbd_reset_setup(char *str, int *ints){ kbd_startup_reset = 1;}#define KBD_NO_DATA (-1) /* No data */#define KBD_BAD_DATA (-2) /* Parity or other error */static int __init kbd_read_input(void){ int retval = KBD_NO_DATA; unsigned char status; status = inb(KBD_STATUS_REG); if (status & KBD_STAT_OBF) { unsigned char data = inb(KBD_DATA_REG); retval = data; if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) retval = KBD_BAD_DATA; } return retval;}static void __init kbd_clear_input(void){ int maxread = 100; /* Random number */ do { if (kbd_read_input() == KBD_NO_DATA) break; } while (--maxread);}static int __init kbd_wait_for_input(void){ long timeout = KBD_INIT_TIMEOUT; do { int retval = kbd_read_input(); if (retval >= 0) return retval; mdelay(1); } while (--timeout); return -1;}static void kbd_write(int address, int data){ unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); outb(data, address); spin_unlock_irqrestore(&kbd_controller_lock, flags);}#if defined CONFIG_PSMOUSEstatic void kbd_write_cmd(int cmd){ unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); outb(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); kb_wait(); outb(cmd, KBD_DATA_REG); spin_unlock_irqrestore(&kbd_controller_lock, flags);}#endif /* CONFIG_PSMOUSE */static char * __init initialize_kbd(void){ int status; /* * Test the keyboard interface. * This seems to be the only way to get it going. * If the test is successful a x55 is placed in the input buffer. */ kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); if (kbd_wait_for_input() != 0x55) return "Keyboard failed self test"; /* * Perform a keyboard interface test. This causes the controller * to test the keyboard clock and data lines. The results of the * test are placed in the input buffer. */ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); if (kbd_wait_for_input() != 0x00) return "Keyboard interface failed self test"; /* * Enable the keyboard by allowing the keyboard clock to run. */ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE); /* * Reset keyboard. If the read times out * then the assumption is that no keyboard is * plugged into the machine. * This defaults the keyboard to scan-code set 2. * * Set up to try again if the keyboard asks for RESEND. */ do { kbd_write(KBD_DATA_REG, KBD_CMD_RESET); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status != KBD_REPLY_RESEND) return "Keyboard reset failed, no ACK"; } while (1); if (kbd_wait_for_input() != KBD_REPLY_POR) return "Keyboard reset failed, no POR"; /* * Set keyboard controller mode. During this, the keyboard should be * in the disabled state. * * Set up to try again if the keyboard asks for RESEND. */ do { kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status != KBD_REPLY_RESEND) return "Disable keyboard: no ACK"; } while (1); kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC); /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE); if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { /* * If the controller does not support conversion, * Set the keyboard to scan-code set 1. */ kbd_write(KBD_DATA_REG, 0xF0); kbd_wait_for_input(); kbd_write(KBD_DATA_REG, 0x01); kbd_wait_for_input(); } kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Enable keyboard: no ACK"; /* * Finally, set the typematic rate to maximum. */ kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; kbd_write(KBD_DATA_REG, 0x00); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; return NULL;}void __init pckbd_init_hw(void){ /* Get the keyboard controller registers (incomplete decode) */ request_region(0x60, 16, "keyboard"); /* Flush any pending input. */ kbd_clear_input(); if (kbd_startup_reset) { char *msg = initialize_kbd(); if (msg) printk(KERN_WARNING "initialize_kbd: %s\n", msg); }#if defined CONFIG_PSMOUSE psaux_init();#endif /* Ok, finally allocate the IRQ, and off we go.. */ request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);}#if defined CONFIG_PSMOUSE/* * Check if this is a dual port controller. */static int __init detect_auxiliary_port(void){ unsigned long flags; int loops = 10; int retval = 0; spin_lock_irqsave(&kbd_controller_lock, flags); /* Put the value 0x5A in the output buffer using the "Write * Auxiliary Device Output Buffer" command (0xD3). Poll the * Status Register for a while to see if the value really * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF * bit is also set to 1 in the Status Register, we assume this * controller has an Auxiliary Port (a.k.a. Mouse Port). */ kb_wait(); outb(KBD_CCMD_WRITE_AUX_OBUF, KBD_CNTL_REG); kb_wait(); outb(0x5a, KBD_DATA_REG); /* 0x5a is a random dummy value. */ do { unsigned char status = inb(KBD_STATUS_REG); if (status & KBD_STAT_OBF) { (void) inb(KBD_DATA_REG); if (status & KBD_STAT_MOUSE_OBF) { printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); retval = 1; } break; } mdelay(1); } while (--loops); spin_unlock_irqrestore(&kbd_controller_lock, flags); return retval;}/* * Send a byte to the mouse. */static void aux_write_dev(int val){ unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); kb_wait(); outb(val, KBD_DATA_REG); spin_unlock_irqrestore(&kbd_controller_lock, flags);}/* * Send a byte to the mouse & handle returned ack */static void aux_write_ack(int val){ unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); kb_wait(); outb(val, KBD_DATA_REG); /* we expect an ACK in response. */ mouse_reply_expected++; kb_wait(); spin_unlock_irqrestore(&kbd_controller_lock, flags);}static unsigned char get_from_queue(void){ unsigned char result; unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); result = queue->buf[queue->tail]; queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); spin_unlock_irqrestore(&kbd_controller_lock, flags); return result;}static inline int queue_empty(void){ return queue->head == queue->tail;}static int fasync_aux(int fd, struct file *filp, int on){ int retval; retval = fasync_helper(fd, filp, on, &queue->fasync); if (retval < 0) return retval; return 0;}/* * Random magic cookie for the aux device */#define AUX_DEV ((void *)queue)static int release_aux(struct inode * inode, struct file * file){ fasync_aux(-1, file, 0); if (--aux_count) return 0; kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); free_irq(AUX_IRQ, AUX_DEV); return 0;}/* * Install interrupt handler. * Enable auxiliary device. */static int open_aux(struct inode * inode, struct file * file){ if (aux_count++) { return 0; } queue->head = queue->tail = 0; /* Flush input queue */ if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) { aux_count--; return -EBUSY; } kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ return 0;}/* * Put bytes from input queue to buffer. */static ssize_t read_aux(struct file * file, char * buffer, size_t count, loff_t *ppos){ struct wait_queue wait = { current, NULL }; ssize_t i = count; unsigned char c; if (queue_empty()) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; add_wait_queue(&queue->proc_list, &wait);repeat: current->state = TASK_INTERRUPTIBLE; if (queue_empty() && !signal_pending(current)) { schedule(); goto repeat; } current->state = TASK_RUNNING; remove_wait_queue(&queue->proc_list, &wait); } while (i > 0 && !queue_empty()) { c = get_from_queue(); put_user(c, buffer++); i--; } if (count-i) { file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-i; } if (signal_pending(current)) return -ERESTARTSYS; return 0;}/* * Write to the aux device. */static ssize_t write_aux(struct file * file, const char * buffer, size_t count, loff_t *ppos){ ssize_t retval = 0; if (count) { ssize_t written = 0; if (count > 32) count = 32; /* Limit to 32 bytes. */ do { char c; get_user(c, buffer++); aux_write_dev(c); written++; } while (--count); retval = -EIO; if (written) { retval = written; file->f_dentry->d_inode->i_mtime = CURRENT_TIME; } } return retval;}static unsigned int aux_poll(struct file *file, poll_table * wait){ poll_wait(file, &queue->proc_list, wait); if (!queue_empty()) return POLLIN | POLLRDNORM; return 0;}struct file_operations psaux_fops = { NULL, /* seek */ read_aux, write_aux, NULL, /* readdir */ aux_poll, NULL, /* ioctl */ NULL, /* mmap */ open_aux, NULL, /* flush */ release_aux, NULL, fasync_aux,};/* * Initialize driver. */static struct miscdevice psaux_mouse = { PSMOUSE_MINOR, "psaux", &psaux_fops};static int __init psaux_init(void){ if (!detect_auxiliary_port()) return -EIO; misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; queue->proc_list = NULL;#ifdef INITIALIZE_MOUSE kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ aux_write_ack(AUX_SET_SAMPLE); aux_write_ack(100); /* 100 samples/sec */ aux_write_ack(AUX_SET_RES); aux_write_ack(3); /* 8 counts per mm */ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */#endif /* INITIALIZE_MOUSE */ kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ return 0;}#endif /* CONFIG_PSMOUSE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -