patch-2.3.36 linux/drivers/usb/keyboard.c
Next file: linux/drivers/usb/keymap-mac.c
Previous file: linux/drivers/usb/keybdev.c
Back to the patch index
Back to the overall index
- Lines: 296
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.35/linux/drivers/usb/keyboard.c
- Orig date:
Mon Dec 20 18:48:22 1999
diff -u --recursive --new-file v2.3.35/linux/drivers/usb/keyboard.c linux/drivers/usb/keyboard.c
@@ -1,295 +0,0 @@
-/*
- Fixes:
- 1999/09/04 - Arnaldo Carvalho de Melo <[email protected]>
- Handle states in usb_kbd_irq
- 1999/09/06 - Arnaldo Carvalho de Melo <[email protected]>
- rmmod usb-keyboard doesn't crash the system anymore: the irq
- handlers are correctly released with usb_release_irq
-*/
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kbd_ll.h>
-#include "usb.h"
-
-#define PCKBD_PRESSED 0x00
-#define PCKBD_RELEASED 0x80
-#define PCKBD_NEEDS_E0 0x80
-
-#define USBKBD_MODIFIER_BASE 224
-#define USBKBD_KEYCODE_OFFSET 2
-#define USBKBD_KEYCODE_COUNT 6
-
-#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3)
-#define USBKBD_FIND_KEYCODE(down, key, count) \
- ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count)))
-
-#define USBKBD_REPEAT_DELAY (HZ / 4)
-#define USBKBD_REPEAT_RATE (HZ / 20)
-
-struct usb_keyboard {
- struct usb_device *dev;
- unsigned long down[2];
- unsigned char repeat_key;
- struct timer_list repeat_timer;
- struct list_head list;
- unsigned int irqpipe;
- void *irq_handler; /* host controller's IRQ transfer handle */
-};
-
-extern unsigned char usb_kbd_map[];
-
-static void *usb_kbd_probe(struct usb_device *dev, unsigned int i);
-static void usb_kbd_disconnect(struct usb_device *dev, void *ptr);
-static void usb_kbd_repeat(unsigned long dummy);
-
-static LIST_HEAD(usb_kbd_list);
-
-static struct usb_driver usb_kbd_driver = {
- "keyboard",
- usb_kbd_probe,
- usb_kbd_disconnect,
- {NULL, NULL}
-};
-
-
-static void usb_kbd_handle_key(unsigned char key, int down)
-{
- int scancode = (int) usb_kbd_map[key];
- if (scancode) {
-#ifndef CONFIG_MAC_KEYBOARD
- if (scancode & PCKBD_NEEDS_E0) {
- handle_scancode(0xe0, 1);
- }
-#endif /* CONFIG_MAC_KEYBOARD */
- handle_scancode((scancode & ~PCKBD_NEEDS_E0), down);
- }
-}
-
-static void usb_kbd_repeat(unsigned long dev_id)
-{
- struct usb_keyboard *kbd = (struct usb_keyboard *) dev_id;
-
- unsigned long flags;
- save_flags(flags);
- cli();
-
- if (kbd->repeat_key) {
- usb_kbd_handle_key(kbd->repeat_key, 1);
-
- /* reset repeat timer */
- kbd->repeat_timer.function = usb_kbd_repeat;
- kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE;
- kbd->repeat_timer.data = (unsigned long) kbd;
- kbd->repeat_timer.prev = NULL;
- kbd->repeat_timer.next = NULL;
- add_timer(&kbd->repeat_timer);
- }
-
- restore_flags(flags);
-}
-
-static int usb_kbd_irq(int state, void *buffer, int len, void *dev_id)
-{
- struct usb_keyboard *kbd = (struct usb_keyboard *) dev_id;
- unsigned long *down = (unsigned long *) buffer;
-
- /*
- * USB_ST_NOERROR is the normal case.
- * USB_ST_REMOVED occurs if keyboard disconnected
- * On other states, ignore
- */
-
- switch (state) {
- case USB_ST_REMOVED:
- case USB_ST_INTERNALERROR:
- printk(KERN_DEBUG "%s(%d): Suspending\n", __FILE__,
- __LINE__);
- return 0; /* disable */
- case USB_ST_NOERROR:
- break;
- default:
- return 1; /* ignore */
- }
-
- if (kbd->down[0] != down[0] || kbd->down[1] != down[1]) {
- unsigned char *olddown, *newdown;
- unsigned char modsdelta, key;
- int i;
-
- /* handle modifier change */
- modsdelta =
- (*(unsigned char *) down ^ *(unsigned char *) kbd->
- down);
- if (modsdelta) {
- for (i = 0; i < 8; i++) {
- if (modsdelta & 0x01) {
- int pressed =
- (*(unsigned char *) down >> i)
- & 0x01;
- usb_kbd_handle_key(i +
- USBKBD_MODIFIER_BASE,
- pressed);
- }
- modsdelta >>= 1;
- }
- }
-
- olddown =
- (unsigned char *) kbd->down + USBKBD_KEYCODE_OFFSET;
- newdown = (unsigned char *) down + USBKBD_KEYCODE_OFFSET;
-
- /* handle released keys */
- for (i = 0; i < USBKBD_KEYCODE_COUNT; i++) {
- key = olddown[i];
- if (USBKBD_VALID_KEYCODE(key)
- && !USBKBD_FIND_KEYCODE(newdown, key,
- USBKBD_KEYCODE_COUNT))
- {
- usb_kbd_handle_key(key, 0);
- }
- }
-
- /* handle pressed keys */
- kbd->repeat_key = 0;
- for (i = 0; i < USBKBD_KEYCODE_COUNT; i++) {
- key = newdown[i];
- if (USBKBD_VALID_KEYCODE(key)
- && !USBKBD_FIND_KEYCODE(olddown, key,
- USBKBD_KEYCODE_COUNT))
- {
- usb_kbd_handle_key(key, 1);
- kbd->repeat_key = key;
- }
- }
-
- /* set repeat timer if any keys were pressed */
- if (kbd->repeat_key) {
- del_timer(&kbd->repeat_timer);
- kbd->repeat_timer.function = usb_kbd_repeat;
- kbd->repeat_timer.expires =
- jiffies + USBKBD_REPEAT_DELAY;
- kbd->repeat_timer.data = (unsigned long) kbd;
- kbd->repeat_timer.prev = NULL;
- kbd->repeat_timer.next = NULL;
- add_timer(&kbd->repeat_timer);
- }
-
- kbd->down[0] = down[0];
- kbd->down[1] = down[1];
- }
-
- return 1;
-}
-
-static void *usb_kbd_probe(struct usb_device *dev, unsigned int i)
-{
- struct usb_interface_descriptor *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_keyboard *kbd;
- int ret;
-
- interface = &dev->actconfig->interface[i].altsetting[0];
- endpoint = &interface->endpoint[0];
-
- if (interface->bInterfaceClass != 3
- || interface->bInterfaceSubClass != 1
- || interface->bInterfaceProtocol != 1) {
- return NULL;
- }
-
- printk(KERN_INFO "USB HID boot protocol keyboard detected.\n");
-
- kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL);
- if (kbd) {
- memset(kbd, 0, sizeof(*kbd));
- kbd->dev = dev;
-
- usb_set_protocol(dev, 0);
- usb_set_idle(dev, 0, 0);
-
- kbd->irqpipe =
- usb_rcvintpipe(dev, endpoint->bEndpointAddress);
- ret =
- usb_request_irq(dev, kbd->irqpipe, usb_kbd_irq,
- endpoint->bInterval, kbd,
- &kbd->irq_handler);
- if (ret) {
- printk(KERN_INFO
- "usb-keyboard failed usb_request_irq (0x%x)\n",
- ret);
- goto probe_err;
- }
-
- list_add(&kbd->list, &usb_kbd_list);
-
- return kbd;
- }
-
-probe_err:
- if (kbd)
- kfree(kbd);
- return NULL;
-}
-
-static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
-{
- struct usb_keyboard *kbd = (struct usb_keyboard *) ptr;
- if (kbd) {
- usb_release_irq(dev, kbd->irq_handler, kbd->irqpipe);
- list_del(&kbd->list);
- del_timer(&kbd->repeat_timer);
- kfree(kbd);
- }
-
- printk(KERN_INFO "USB HID boot protocol keyboard removed.\n");
-}
-
-int usb_kbd_init(void)
-{
- return usb_register(&usb_kbd_driver);
-}
-
-void usb_kbd_cleanup(void)
-{
- struct list_head *cur, *head = &usb_kbd_list;
-
- cur = head->next;
-
- while (cur != head) {
- struct usb_keyboard *kbd =
- list_entry(cur, struct usb_keyboard, list);
-
- cur = cur->next;
-
- list_del(&kbd->list);
- INIT_LIST_HEAD(&kbd->list);
-
- if (kbd->irq_handler) {
- usb_release_irq(kbd->dev, kbd->irq_handler,
- kbd->irqpipe);
- /* never keep a reference to a released IRQ! */
- kbd->irq_handler = NULL;
- }
- }
-
- usb_deregister(&usb_kbd_driver);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- return usb_kbd_init();
-}
-
-void cleanup_module(void)
-{
- usb_kbd_cleanup();
-}
-
-#endif
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen (who was at: [email protected])