📄 sa1111_keyb.c
字号:
#if 0static void kbd_write_command_w(int data){ unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); kbd_write_command(data); spin_unlock_irqrestore(&kbd_controller_lock, flags);}#endifstatic void kbd_write_output_w(int data){ unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); KBDDATA = data & 0xff; spin_unlock_irqrestore(&kbd_controller_lock, flags);}/* * Test the keyboard interface. We basically check to make sure that * we can drive each line to the keyboard independently of each other. */static int kbdif_test(void){ int ret = 0; KBDCR = KBDCR_ENA | KBDCR_FKC; udelay(2); if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != KBDSTAT_KBD) { printk("Keyboard interface test failed[1]: %02x\n", KBDSTAT); ret = -ENODEV; } KBDCR = KBDCR_ENA; udelay(2); if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != (KBDSTAT_KBC | KBDSTAT_KBD)) { printk("Keyboard interface test failed[2]: %02x\n", KBDSTAT); ret = -ENODEV; } KBDCR = KBDCR_ENA | KBDCR_FKD; udelay(2); if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != KBDSTAT_KBC) { printk("Keyboard interface test failed[3]: %02x\n", KBDSTAT); ret = -ENODEV; } return ret;}static char *__init initialize_kbd(void){ int status; /* * Test the keyboard interface. */ kbdif_test(); /* * Ok, drop the force low bits, and wait a while, * and clear the stop bit error flag. */ KBDCR = KBDCR_ENA; udelay(4); KBDSTAT = KBD_STAT_STP; /* * Ok, we're now ready to talk to the keyboard. Reset * it, just to make sure we're starting in a sane state. * * Set up to try again if the keyboard asks for RESEND. */ do { KBDDATA = 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_output_w(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);#if 0 /*@@@ */ kbd_write_command_w(KBD_CCMD_WRITE_MODE); kbd_write_output_w(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_command_w(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_output_w(0xF0); kbd_wait_for_input(); kbd_write_output_w(0x01); kbd_wait_for_input(); }#else kbd_write_output_w(0xf0); kbd_wait_for_input(); kbd_write_output_w(0x01); kbd_wait_for_input();#endif kbd_write_output_w(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_output_w(KBD_CMD_SET_RATE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; kbd_write_output_w(0x00); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; return NULL;}int __init sa1111_kbd_init_hw(void){ char *msg; int ret; if (!request_mem_region(_KBDCR, 512, "keyboard")) return -EBUSY; SKPCR |= SKPCR_PTCLKEN; KBDCLKDIV = 0; KBDPRECNT = 127; /* Flush any pending input. */ kbd_clear_input(); msg = initialize_kbd(); if (msg) printk(KERN_WARNING "initialize_kbd: %s\n", msg);#if defined CONFIG_PSMOUSE psaux_init();#endif k_setkeycode = sa1111_setkeycode; k_getkeycode = sa1111_getkeycode; k_translate = sa1111_translate; k_unexpected_up = sa1111_unexpected_up; k_leds = sa1111_leds;#ifdef CONFIG_MAGIC_SYSRQ k_sysrq_xlate = sa1111_sysrq_xlate; k_sysrq_key = 0x54;#endif /* Ok, finally allocate the IRQ, and off we go.. */ ret = request_irq(IRQ_TPRXINT, keyboard_interrupt, 0, "keyboard", NULL); if (ret) release_mem_region(_KBDCR, 512); return ret;}#if defined CONFIG_PSMOUSEstatic inline void handle_mouse_event(unsigned char scancode){ if (mouse_reply_expected) { if (scancode == AUX_ACK) { mouse_reply_expected--; return; } mouse_reply_expected = 0; } add_mouse_randomness(scancode); if (aux_count) { int head = queue->head; queue->buf[head] = scancode; head = (head + 1) & (AUX_BUF_SIZE - 1); if (head != queue->tail) { queue->head = head; if (queue->fasync) kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } }}static void handle_mse_event(void){ unsigned int msests = MSESTAT; unsigned int work = 10000; unsigned char scancode; while (msests & MSE_STAT_RXF) { while (msests & MSE_STAT_RXF) { scancode = MSEDATA & 0xff; if (!(msests & MSE_STAT_STP)) handle_mouse_event(scancode); if (!--work) { printk(KERN_ERR "pc_keyb: mouse controller jammed (0x%02X).\n", msests); return; /*XXX*/} msests = MSESTAT; } work = 10000; }}static void ms_wait(void){ unsigned long timeout = KBC_TIMEOUT; do { /* * "handle_kbd_event()" will handle any incoming events * while we wait - keypresses or mouse movement. */ handle_mse_event(); if (MSESTAT & MSE_STAT_TXE) return; mdelay(1); timeout--; } while (timeout);#ifdef KBD_REPORT_TIMEOUTS printk(KERN_WARNING "Mouse timed out[1]\n");#endif}static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs){ unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); handle_mse_event(); spin_unlock_irqrestore(&kbd_controller_lock, flags);}/* * Check if this is a dual port controller. */static int __init detect_auxiliary_port(void){ unsigned long flags; int loops = 10; int retval = 0; /* Check if the BIOS detected a device on the auxiliary port. */ if (aux_device_present == 0xaa) return 1; 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(); // kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); SKPCR |= SKPCR_PMCLKEN; MSECLKDIV = 0; MSEPRECNT = 127; MSECR = MSECR_ENA; mdelay(50); MSEDATA = 0xf4; mdelay(50); do { unsigned int msests = MSESTAT; if (msests & MSE_STAT_RXF) { do { msests = MSEDATA; /* dummy read */ mdelay(50); msests = MSESTAT; } while (msests & MSE_STAT_RXF); 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(); // kbd_write_command(KBD_CCMD_WRITE_MOUSE); ms_wait(); MSEDATA = val; 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(); // kbd_write_command(KBD_CCMD_WRITE_MOUSE); ms_wait(); MSEDATA = val; /* we expect an ACK in response. */ mouse_reply_expected++; ms_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_command_w(KBD_CCMD_MOUSE_DISABLE); aux_write_ack(AUX_DISABLE_DEV); /* Disable aux device */ MSECR &= ~MSECR_ENA; free_irq(IRQ_MSRXINT, 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 */ /* Don't enable the mouse controller until we've registered IRQ handler */ if (request_irq(IRQ_MSRXINT, mouse_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) { aux_count--; return -EBUSY; } MSECLKDIV = 0; MSEPRECNT = 127; MSECR &= ~MSECR_ENA; mdelay(50); MSECR = MSECR_ENA; mdelay(50); MSEDATA = 0xf4; mdelay(50); if (MSESTAT & 0x0100) { MSESTAT = 0x0100; /* clear IRQ status */ }/* kbd_write_command_w(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 */ // send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ return 0;}/* * Put bytes from input queue to buffer. */static ssize_tread_aux(struct file *file, char *buffer, size_t count, loff_t * ppos){ DECLARE_WAITQUEUE(wait, current); 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: set_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_twrite_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 = { read: read_aux, write: write_aux, poll: aux_poll, open: open_aux, release: release_aux, fasync: fasync_aux,};/* * Initialize driver. */static struct miscdevice psaux_mouse = { PSMOUSE_MINOR, "psaux", &psaux_fops};static int __init psaux_init(void){ int ret; if (!request_mem_region(_MSECR, 512, "psaux")) return -EBUSY; if (!detect_auxiliary_port()) { ret = -EIO; goto out; } misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list);#ifdef CONFIG_PSMOUSE 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 ret = 0; out: if (ret) release_mem_region(_MSECR, 512); return ret;}#endif /* CONFIG_PSMOUSE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -