/* * This routine is the bottom half of the keyboard interrupt * routine, and runs with all interrupts enabled. It does * console changing, led setting and copy_to_cooked, which can * take a reasonably long time. * * Aside from timing (which isn't really that important for * keyboard interrupts as they happen often), using the software * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. Not yet * used, but this allows for easy and efficient race-condition * prevention later on. */ static void kbd_bh(void) { unsigned char leds = getleds(); unsigned char kbd_leds = vcleds_to_sunkbd(leds); if (kbd_leds != sunkbd_ledstate) { ledstate = leds; sunkbd_ledstate = kbd_leds; send_cmd(SKBDCMD_SETLED); send_cmd(kbd_leds); } }
/* * Toggle all of the LED's on and off, just for show. */ void blinkleds(struct akbd_softc *sc) { u_char origleds; origleds = getleds(sc->adbaddr); setleds(sc, LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK); delay(400000); setleds(sc, origleds); if (origleds & LED_NUMLOCK) sc->sc_leds |= WSKBD_LED_NUM; if (origleds & LED_CAPSLOCK) sc->sc_leds |= WSKBD_LED_CAPS; if (origleds & LED_SCROLL_LOCK) sc->sc_leds |= WSKBD_LED_SCROLL; }
/* * This routine is the bottom half of the keyboard interrupt * routine, and runs with all interrupts enabled. It does * console changing, led setting and copy_to_cooked, which can * take a reasonably long time. * * Aside from timing (which isn't really that important for * keyboard interrupts as they happen often), using the software * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. Not yet * used, but this allows for easy and efficient race-condition * prevention later on. */ static unsigned char sunkbd_ledstate = 0xff; /* undefined */ void sun_kbd_bh(unsigned long dummy) { unsigned long flags; unsigned char leds, kbd_leds; spin_lock_irqsave(&sunkbd_lock, flags); leds = getleds(); kbd_leds = vcleds_to_sunkbd(leds); if (kbd_leds != sunkbd_ledstate) { ledstate = leds; sunkbd_ledstate = kbd_leds; send_cmd(SKBDCMD_SETLED); send_cmd(kbd_leds); } spin_unlock_irqrestore(&sunkbd_lock, flags); }
static int kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) { unsigned char c; unsigned char leds = 0; int value; switch (cmd){ case KIOCTYPE: /* return keyboard type */ put_user_ret(sunkbd_type, (int *) arg, -EFAULT); break; case KIOCGTRANS: put_user_ret(TR_UNTRANS_EVENT, (int *) arg, -EFAULT); break; case KIOCTRANS: get_user_ret(value, (int *) arg, -EFAULT); if (value != TR_UNTRANS_EVENT) return -EINVAL; break; case KIOCLAYOUT: put_user_ret(sunkbd_layout, (int *) arg, -EFAULT); break; case KIOCSDIRECT: #ifndef CODING_NEW_DRIVER get_user_ret(value, (int *) arg, -EFAULT); if(value) kbd_redirected = fg_console + 1; else kbd_redirected = 0; kbd_table [fg_console].kbdmode = kbd_redirected ? VC_RAW : VC_XLATE; #endif break; case KIOCCMD: get_user_ret(value, (int *) arg, -EFAULT); c = (unsigned char) value; switch (c) { case SKBDCMD_CLICK: case SKBDCMD_NOCLICK: send_cmd(c); return 0; case SKBDCMD_BELLON: kd_mksound(1,0); return 0; case SKBDCMD_BELLOFF: kd_mksound(0,0); return 0; default: return -EINVAL; } case KIOCSLED: get_user_ret(c, (unsigned char *) arg, -EFAULT); if (c & LED_SCRLCK) leds |= (1 << VC_SCROLLOCK); if (c & LED_NLOCK) leds |= (1 << VC_NUMLOCK); if (c & LED_CLOCK) leds |= (1 << VC_CAPSLOCK); compose_led_on = !!(c & LED_CMPOSE); sun_setledstate(kbd_table + fg_console, leds); break; case KIOCGLED: put_user_ret(vcleds_to_sunkbd(getleds()), (unsigned char *) arg, -EFAULT); break; case KIOCGRATE: { struct kbd_rate rate; rate.delay = kbd_delay_ticks; if (kbd_rate_ticks) rate.rate = HZ / kbd_rate_ticks; else rate.rate = 0; copy_to_user_ret((struct kbd_rate *)arg, &rate, sizeof(struct kbd_rate), -EFAULT); return 0; } case KIOCSRATE: { struct kbd_rate rate; if (verify_area(VERIFY_READ, (void *)arg, sizeof(struct kbd_rate))) return -EFAULT; copy_from_user(&rate, (struct kbd_rate *)arg, sizeof(struct kbd_rate)); if (rate.rate > 50) return -EINVAL; if (rate.rate == 0) kbd_rate_ticks = 0; else kbd_rate_ticks = HZ / rate.rate; kbd_delay_ticks = rate.delay; return 0; } case FIONREAD: /* return number of bytes in kbd queue */ { int count; count = kbd_head - kbd_tail; put_user_ret((count < 0) ? KBD_QSIZE - count : count, (int *) arg, -EFAULT); return 0; } default: printk ("Unknown Keyboard ioctl: %8.8x\n", cmd); return -EINVAL; } return 0; }