📄 pcikbd.c
字号:
}void pcikbd_leds(unsigned char leds){ if (!pcikbd_iobase) return; if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds)) send_data(KBD_CMD_ENABLE);}static unsigned char parse_kbd_rate(struct kbd_repeat *r){ static struct r2v { int rate; unsigned char val; } kbd_rates[]={ { 5, 0x14 }, { 7, 0x10 }, { 10, 0x0c }, { 15, 0x08 }, { 20, 0x04 }, { 25, 0x02 }, { 30, 0x00 } }; static struct d2v { int delay; unsigned char val; } kbd_delays[]={ { 250, 0 }, { 500, 1 }, { 750, 2 }, { 1000, 3 } }; int rate = 0, delay = 0; if (r != NULL) { int i, new_rate = 30, new_delay = 250; if (r->rate <= 0) r->rate = kbdrate.rate; if (r->delay <= 0) r->delay = kbdrate.delay; for (i = 0; i < sizeof(kbd_rates) / sizeof(struct r2v); i++) { if (kbd_rates[i].rate == r->rate) { new_rate = kbd_rates[i].rate; rate = kbd_rates[i].val; break; } } for (i=0; i < sizeof(kbd_delays) / sizeof(struct d2v); i++) { if (kbd_delays[i].delay == r->delay) { new_delay = kbd_delays[i].delay; delay = kbd_delays[i].val; break; } } r->rate = new_rate; r->delay = new_delay; } return (delay << 5) | rate;}static int write_kbd_rate(unsigned char r){ if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)) { /* re-enable kbd if any errors */ send_data(KBD_CMD_ENABLE); return 0; } return 1;}static int pcikbd_rate(struct kbd_repeat *rep){ unsigned char r; struct kbd_repeat old_rep; if (rep == NULL) return -EINVAL; r = parse_kbd_rate(rep); memcpy(&old_rep, &kbdrate, sizeof(struct kbd_repeat)); if (write_kbd_rate(r)) { memcpy(&kbdrate,rep,sizeof(struct kbd_repeat)); memcpy(rep,&old_rep,sizeof(struct kbd_repeat)); return 0; } return -EIO;}static int pcikbd_wait_for_input(void){ int status, data; unsigned long timeout = 1000; do { mdelay(1); status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); if (!(status & KBD_STAT_OBF)) continue; data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) continue; return (data & 0xff); } while (--timeout > 0); return -1;}static void pcikbd_write(int address, int data){ int status; do { status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while (status & KBD_STAT_IBF); pcikbd_outb(data, pcikbd_iobase + address);}#ifdef __sparc_v9__static unsigned long pcibeep_iobase = 0;/* Timer routine to turn off the beep after the interval expires. */static void pcikbd_kd_nosound(unsigned long __unused){ if (pcibeep_iobase & 0x2UL) outb(0, pcibeep_iobase); else outl(0, pcibeep_iobase);}/* * Initiate a keyboard beep. If the frequency is zero, then we stop * the beep. Any other frequency will start a monotone beep. The beep * will be stopped by a timer after "ticks" jiffies. If ticks is 0, * then we do not start a timer. */static void pcikbd_kd_mksound(unsigned int hz, unsigned int ticks){ unsigned long flags; static struct timer_list sound_timer = { function: pcikbd_kd_nosound }; save_flags(flags); cli(); del_timer(&sound_timer); if (hz) { if (pcibeep_iobase & 0x2UL) outb(1, pcibeep_iobase); else outl(1, pcibeep_iobase); if (ticks) { sound_timer.expires = jiffies + ticks; add_timer(&sound_timer); } } else { if (pcibeep_iobase & 0x2UL) outb(0, pcibeep_iobase); else outl(0, pcibeep_iobase); } restore_flags(flags);}#if (defined(CONFIG_USB) || defined(CONFIG_USB_MODULE)) && defined(CONFIG_SPARC64)static void isa_kd_nosound(unsigned long __unused){ /* disable counter 2 */ outb(inb(pcibeep_iobase + 0x61)&0xFC, pcibeep_iobase + 0x61); return;}static void isa_kd_mksound(unsigned int hz, unsigned int ticks){ static struct timer_list sound_timer = { function: isa_kd_nosound }; unsigned int count = 0; unsigned long flags; if (hz > 20 && hz < 32767) count = 1193180 / hz; save_flags(flags); cli(); del_timer(&sound_timer); if (count) { /* enable counter 2 */ outb(inb(pcibeep_iobase + 0x61)|3, pcibeep_iobase + 0x61); /* set command for counter 2, 2 byte write */ outb(0xB6, pcibeep_iobase + 0x43); /* select desired HZ */ outb(count & 0xff, pcibeep_iobase + 0x42); outb((count >> 8) & 0xff, pcibeep_iobase + 0x42); if (ticks) { sound_timer.expires = jiffies+ticks; add_timer(&sound_timer); } } else isa_kd_nosound(0); restore_flags(flags); return;}#endif#endifstatic void nop_kd_mksound(unsigned int hz, unsigned int ticks){}extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);static char * __init do_pcikbd_init_hw(void){ while(pcikbd_wait_for_input() != -1) ; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); if(pcikbd_wait_for_input() != 0x55) return "Keyboard failed self test"; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); if(pcikbd_wait_for_input() != 0x00) return "Keyboard interface failed self test"; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE); pcikbd_write(KBD_DATA_REG, KBD_CMD_RESET); if(pcikbd_wait_for_input() != KBD_REPLY_ACK) return "Keyboard reset failed, no ACK"; if(pcikbd_wait_for_input() != KBD_REPLY_POR) return "Keyboard reset failed, no ACK"; pcikbd_write(KBD_DATA_REG, KBD_CMD_DISABLE); if(pcikbd_wait_for_input() != KBD_REPLY_ACK) return "Disable keyboard: no ACK"; pcikbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); pcikbd_write(KBD_DATA_REG, (KBD_MODE_KBD_INT | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC)); pcikbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); if(pcikbd_wait_for_input() != KBD_REPLY_ACK) return "Enable keyboard: no ACK"; write_kbd_rate(parse_kbd_rate(&kbdrate)); return NULL; /* success */}void __init pcikbd_init_hw(void){ struct linux_ebus *ebus; struct linux_ebus_device *edev; struct linux_ebus_child *child; char *msg; if (pcikbd_mrcoffee) { if ((pcikbd_iobase = (unsigned long) ioremap(0x71300060, 8)) == 0) { prom_printf("pcikbd_init_hw: cannot map\n"); return; } pcikbd_irq = 13 | 0x20; if (request_irq(pcikbd_irq, &pcikbd_interrupt, SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) { printk("8042: cannot register IRQ %x\n", pcikbd_irq); return; } printk("8042(kbd): iobase[%x] irq[%x]\n", (unsigned)pcikbd_iobase, pcikbd_irq); } else { for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if(!strcmp(edev->prom_name, "8042")) { for_each_edevchild(edev, child) { if (strcmp(child->prom_name, PCI_KB_NAME1) == 0 || strcmp(child->prom_name, PCI_KB_NAME2) == 0) goto found; } } } }#if defined(CONFIG_USB) || defined(CONFIG_USB_MODULE) /* We are being called for the sake of USB keyboard * state initialization. So we should check for beeper * device in this case. */ edev = 0; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "beep")) { pcibeep_iobase = edev->resource[0].start; kd_mksound = pcikbd_kd_mksound; printk("8042(speaker): iobase[%016lx]\n", pcibeep_iobase); return; } } }#ifdef CONFIG_SPARC64 /* Maybe we have one inside the ALI southbridge? */ { struct isa_bridge *isa_br; struct isa_device *isa_dev; for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { /* This is a hack, the 'dma' device node has * the base of the I/O port space for that PBM * as it's resource, so we use that. -DaveM */ if (!strcmp(isa_dev->prom_name, "dma")) { pcibeep_iobase = isa_dev->resource.start; kd_mksound = isa_kd_mksound; printk("isa(speaker): iobase[%016lx:%016lx]\n", pcibeep_iobase + 0x42, pcibeep_iobase + 0x61); return; } } } }#endif /* No beeper found, ok complain. */#endif printk("pcikbd_init_hw: no 8042 found\n"); return;found: pcikbd_iobase = child->resource[0].start; pcikbd_irq = child->irqs[0]; if (request_irq(pcikbd_irq, &pcikbd_interrupt, SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) { printk("8042: cannot register IRQ %s\n", __irq_itoa(pcikbd_irq)); return; } printk("8042(kbd) at 0x%lx (irq %s)\n", pcikbd_iobase, __irq_itoa(pcikbd_irq)); } kd_mksound = nop_kd_mksound; kbd_rate = pcikbd_rate;#ifdef __sparc_v9__ edev = 0; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { if(!strcmp(edev->prom_name, "beeper")) goto ebus_done; } }ebus_done: /* * XXX: my 3.1.3 PROM does not give me the beeper node for the audio * auxio register, though I know it is there... (ecd) * * JavaStations appear not to have beeper. --zaitcev */ if (!edev) pcibeep_iobase = (pcikbd_iobase & ~(0xffffff)) | 0x722000; else pcibeep_iobase = edev->resource[0].start; kd_mksound = pcikbd_kd_mksound; printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase, edev ? "" : " (forced)"); prom_keyboard = pcikbd_enter_prom;#endif disable_irq(pcikbd_irq); msg = do_pcikbd_init_hw(); enable_irq(pcikbd_irq); if(msg) printk("8042: keyboard init failure [%s]\n", msg);}/* * Here begins the Mouse Driver. */static unsigned long pcimouse_iobase = 0;static unsigned int pcimouse_irq;#define AUX_BUF_SIZE 2048struct aux_queue { unsigned long head; unsigned long tail; wait_queue_head_t proc_list; struct fasync_struct *fasync; unsigned char buf[AUX_BUF_SIZE];};static struct aux_queue *queue;static int aux_count = 0;static int aux_present = 0;#define pcimouse_inb(x) inb(x)#define pcimouse_outb(v,x) outb(v,x)/* * Shared subroutines */static unsigned int get_from_queue(void){ unsigned int result; unsigned long flags; spin_lock_irqsave(&pcikbd_lock, flags); result = queue->buf[queue->tail]; queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); spin_unlock_irqrestore(&pcikbd_lock, flags); return result;}static inline int queue_empty(void){ return queue->head == queue->tail;}static int aux_fasync(int fd, struct file *filp, int on){ int retval; retval = fasync_helper(fd, filp, on, &queue->fasync); if (retval < 0) return retval; return 0;}/* * PS/2 Aux Device */#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | \ KBD_MODE_SYS | KBD_MODE_KBD_INT)#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | \ KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)#define MAX_RETRIES 60 /* some aux operations take long time*//* * Status polling */static int poll_aux_status(void){ int retries = 0; while ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) { if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); mdelay(5); retries++; } return (retries < MAX_RETRIES);}/* * Write to aux device */static void aux_write_dev(int val)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -