www.pudn.com > Linux2410_device.rar > mouse.c
/* * mouse_fd/mouse.c * * Copyright (c) 2000, 2001, 2002 Lineo * Copyright (c) 2001 Hewlett Packard * * By: * Stuart Lynne, * Tom Rushworth , * Bruce Balden * * Copyright (C) 2002 Toshiba Corporation * * Changes Copyright (c) 2003 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * Usage: * move pointer to right(10) and bottom(20) * echo "0 10 20" > /proc/driver/mouse_fd * move pointer to left(10) and top(20) * echo "0 246 236" > /proc/driver/mouse_fd * press button 1 * echo "1 0 00" > /proc/driver/mouse_fd * press button 2 * echo "2 0 00" > /proc/driver/mouse_fd * press button 3 * echo "4 0 00" > /proc/driver/mouse_fd * release buttons * echo "0 0 00" > /proc/driver/mouse_fd */ #include #include #include "../usbd-export.h" #include "../usbd-build.h" #include "../usbd-module.h" MODULE_AUTHOR("sl@lineo.com, tbr@lineo.com, TOSHIBA Corporation"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("USB Device Mouse Function"); USBD_MODULE_INFO("mouse_fd 0.1-beta"); #ifndef MODULE #undef GET_USE_COUNT #define GET_USE_COUNT(foo) 1 #endif #include #include #include #include #include #include #include #include #include #include #include "../usbd.h" #include "../usbd-func.h" #include "../usbd-bus.h" #include "../usbd-debug.h" #include "../usbd-inline.h" #include "../usbd-arch.h" #define MOUSE_PACKET_SIZE 3 #define MOUSE_PROC_NAME "driver/mouse_fd" #if !defined (CONFIG_USBD_VENDORID) && !defined(CONFIG_USBD_MOUSE_VENDORID) #error No Vendor ID #endif #if !defined (CONFIG_USBD_PRODUCTID) && !defined(CONFIG_USBD_MOUSE_PRODUCTID) #error No Product ID #endif #if CONFIG_USBD_MOUSE_VENDORID #undef CONFIG_USBD_VENDORID #define CONFIG_USBD_VENDORID CONFIG_USBD_MOUSE_VENDORID #endif #if CONFIG_USBD_MOUSE_PRODUCTID #undef CONFIG_USBD_PRODUCTID #define CONFIG_USBD_PRODUCTID CONFIG_USBD_MOUSE_PRODUCTID #endif #ifndef CONFIG_USBD_SERIAL_NUMBER_STR #define CONFIG_USBD_SERIAL_NUMBER_STR "" #endif #ifdef CONFIG_USBD_SELFPOWERED #define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED #define BMAXPOWER 0 #else #define BMATTRIBUTE BMATTRIBUTE_RESERVED #define BMAXPOWER CONFIG_USBD_MAXPOWER #endif /* * setup some default values for pktsizes and endpoint addresses. */ #ifndef CONFIG_USBD_MOUSE_INT_PKTSIZE #define CONFIG_USBD_MOUSE_INT_PKTSIZE 16 #endif #ifndef CONFIG_USBD_MOUSE_INT_ENDPOINT #define CONFIG_USBD_MOUSE_INT_ENDPOINT 3 #endif /* * check for architecture specific endpoint configurations */ #if defined(ABS_INT_ADDR) #warning #warning USING ABS ENDPOINT INT ADDRESS #undef CONFIG_USBD_MOUSE_INT_ENDPOINT #if ABS_INT_ADDR #define CONFIG_USBD_MOUSE_INT_ENDPOINT ABS_INT_ADDR #endif #elif defined(MAX_INT_ADDR) && defined(CONFIG_USBD_MOUSE_INT_ENDPOINT) && (CONFIG_USBD_MOUSE_INT_ENDPOINT > MAX_INT_ADDR) #warning #warning USING DEFAULT ENDPOINT INT ADDRESS #undef CONFIG_USBD_MOUSE_INT_ENDPOINT #define CONFIG_USBD_MOUSE_INT_ENDPOINT DFL_INT_ADDR #endif #if defined(MAX_INT_PKTSIZE) && defined(CONFIG_USBD_MOUSE_INT_PKTSIZE) && CONFIG_USBD_MOUSE_INT_PKTSIZE > MAX_INT_PKTSIZE #warning #warning OVERIDING ENDPOINT INT PKTSIZE #undef CONFIG_USBD_MOUSE_INT_PKTSIZE #define CONFIG_USBD_MOUSE_INT_PKTSIZE MAX_INT_PKTSIZE #endif struct usb_mouse_private { struct usb_device_instance *device; spinlock_t lock; __u8 data[MOUSE_PACKET_SIZE]; int data_valid; int duration; }; /* Module Parameters ************************************************************************* */ static char *dbg = NULL; static u32 vendor_id; static u32 product_id; MODULE_PARM(dbg, "s"); MODULE_PARM(vendor_id, "i"); MODULE_PARM(product_id, "i"); MODULE_PARM_DESC(dbg, "USB Device Debug options"); MODULE_PARM_DESC(vendor_id, "USB Device Vendor ID"); MODULE_PARM_DESC(product_id, "USB Device Product ID"); /* Debug switches (module parameter "dbg=...") *********************************************** */ extern int dbgflg_usbdfd_init; int dbgflg_usbdfd_ep0; int dbgflg_usbdfd_usbe; int dbgflg_usbdfd_tx; static debug_option dbg_table[] = { {&dbgflg_usbdfd_init,NULL,"init","initialization and termination"}, {&dbgflg_usbdfd_ep0,NULL,"ep0","End Point 0 (setup) packet handling"}, {&dbgflg_usbdfd_usbe,NULL,"usbe","USB events"}, {&dbgflg_usbdfd_tx,NULL,"tx","transmit (to host)"}, {NULL,NULL,NULL,NULL} }; #define dbg_init(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_init,lvl,fmt,##args) #define dbg_ep0(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_ep0,lvl,fmt,##args) #define dbg_usbe(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_usbe,lvl,fmt,##args) #define dbg_tx(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_tx,lvl,fmt,##args) /* ******************************************************************************************* */ /* HID Class descriptions */ static struct usb_endpoint_description mouse_default[] = { { bEndpointAddress: CONFIG_USBD_MOUSE_INT_ENDPOINT, bmAttributes: INTERRUPT, wMaxPacketSize: CONFIG_USBD_MOUSE_INT_PKTSIZE, bInterval: 0x0a, /* 10ms */ direction: IN, transferSize: MOUSE_PACKET_SIZE, }, }; /* HID Class descriptions */ /* c.f. HID E.10 Report Descriptor (Mouse) */ static __u8 mouse_report_desc[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x01, // USAGE (Pointer) 0xa1, 0x00, // COLLECTION (Physical) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x03, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Variable,Absolute) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x01, // INPUT (Cnstant) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x06, // INPUT (Data,Variable,Relative) 0xc0, // END_COLLECTION 0xc0 // END_COLLECTION }; static struct usb_class_description mouse_class[] = { { USB_DT_HID, 0, 0, { hid: { bcdCDC: CLASS_HID_BCD_VERSION, bCountryCode: 0, bDescriptorType: USB_DT_REPORT, wDescriptorLength: sizeof(mouse_report_desc), reportDescriptor: mouse_report_desc } }}, }; /* Data Interface Alternate description(s) */ static __devinitdata struct usb_alternate_description mouse_data_alternate_descriptions[] = { { iInterface: "Simple Mouse Data Interface - Int mode", bAlternateSetting: 0, classes: sizeof(mouse_class)/sizeof(struct usb_class_description), class_list: mouse_class, endpoints: sizeof(mouse_default)/sizeof(struct usb_endpoint_description), endpoint_list: mouse_default, }, }; /* Interface description(s) */ static __devinitdata struct usb_interface_description mouse_interfaces[] = { { iInterface: "Simple Mouse Data Interface", bInterfaceClass: USB_CLASS_HID, bInterfaceSubClass: 0x01, /* Keyboard/Mouse */ bInterfaceProtocol: 0x02, /* Mouse:2 */ alternates: sizeof(mouse_data_alternate_descriptions)/sizeof(struct usb_alternate_description), alternate_list: mouse_data_alternate_descriptions, }, }; /* Configuration description(s) */ struct __devinitdata usb_configuration_description mouse_description[] = { { iConfiguration: "USB Simple Mouse Configuration", bmAttributes: BMATTRIBUTE, bMaxPower: BMAXPOWER, interfaces: sizeof(mouse_interfaces)/sizeof(struct usb_interface_description), interface_list: mouse_interfaces, }, }; /* Device Description */ struct __devinitdata usb_device_description mouse_device_description = { bDeviceClass: 0, bDeviceSubClass: 0, bDeviceProtocol: 0, idVendor: CONFIG_USBD_VENDORID, idProduct: CONFIG_USBD_PRODUCTID, iManufacturer: CONFIG_USBD_MANUFACTURER, iProduct: CONFIG_USBD_PRODUCT_NAME, iSerialNumber: CONFIG_USBD_SERIAL_NUMBER_STR, }; static int mouse_send(struct usb_mouse_private *mouse_private) { int port = 0; // XXX compound device struct urb *urb; unsigned long flags; spin_lock_irqsave(&mouse_private->lock, flags); if (!mouse_private->data_valid) { spin_unlock_irqrestore(&mouse_private->lock, flags); return 0; } if ((urb = usbd_alloc_urb(mouse_private->device, (mouse_private->device->function_instance_array+port), CONFIG_USBD_MOUSE_INT_ENDPOINT | IN, MOUSE_PACKET_SIZE))==NULL) { dbg_tx(0, "failed to alloc urb"); spin_unlock_irqrestore(&mouse_private->lock, flags); return -EINVAL; } memcpy(urb->buffer, mouse_private->data, MOUSE_PACKET_SIZE); urb->actual_length = MOUSE_PACKET_SIZE; mouse_private->data_valid = 0; spin_unlock_irqrestore(&mouse_private->lock, flags); dbgPRINTmem(dbgflg_usbdfd_tx,3,urb->buffer,MOUSE_PACKET_SIZE); // push it down into the usb-device layer return usbd_send_urb(urb); } /* mouse_urb_sent - called to indicate URB transmit finished * @urb: pointer to struct urb * @rc: result */ int mouse_urb_sent (struct urb *urb, int status) { int port = 0; // XXX compound device struct usb_device_instance *device = urb->device; struct usb_mouse_private *mouse_private = (device->function_instance_array+port)->privdata; dbg_tx(2,"%s length: %d status : %x",urb->device->name, urb->actual_length, status); usbd_dealloc_urb(urb); /* send next urb */ return mouse_send(mouse_private); } /** * mouse_recv_setup - called with a control URB * @urb - pointer to struct urb * * Check if this is a setup packet, process the device request, put results * back into the urb and return zero or non-zero to indicate success (DATA) * or failure (STALL). * * This routine IS called at interrupt time. Please use the usual precautions. * */ int mouse_recv_setup (struct urb * urb) { struct usb_device_request *request; struct usb_device_instance *device = urb->device; int port = 0; struct usb_mouse_private *mouse_private = (device->function_instance_array+port)->privdata; request = &urb->device_request; // handle HID Class-Specific Request (c.f. HID 7.2) if ((request->bmRequestType&USB_REQ_TYPE_MASK)!=USB_REQ_TYPE_CLASS) { dbg_ep0(1, "not class request: %x %x", request->bmRequestType, request->bmRequestType&USB_REQ_TYPE_MASK); return 0; // XXX } if ((request->bmRequestType&USB_REQ_DIRECTION_MASK)) { dbg_ep0(1, "Device-to-Host"); switch (request->bRequest) { case USB_REQ_SET_IDLE: mouse_private->duration = le16_to_cpu (request->wValue) >> 8; break; case USB_REQ_SET_REPORT: /* ignore */ break; } } else { dbg_ep0(1, "Host-to-Device"); switch (request->bRequest) { case USB_REQ_GET_IDLE: /* FIXME */ break; case USB_REQ_GET_REPORT: /* FIXME */ break; } } return 0; } /* USB Device Functions ************************************************************************ */ /* proc interface */ static int mouse_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) { char str[128]; int val[MOUSE_PACKET_SIZE]; unsigned long flags; struct usb_mouse_private *mouse_private = data; memset(str, 0, sizeof(str)); if (copy_from_user(str, buffer, min_t(unsigned long, count, sizeof(str)))) return -EFAULT; if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) return -EINVAL; spin_lock_irqsave(&mouse_private->lock, flags); if (mouse_private->device->device_state == STATE_CONFIGURED && !mouse_private->data_valid) { int i; for (i = 0; i < MOUSE_PACKET_SIZE; i++) mouse_private->data[i] = val[i]; mouse_private->data_valid = 1; mouse_send(mouse_private); } spin_unlock_irqrestore(&mouse_private->lock, flags); return count; } /* mouse_event - process a device event * */ void mouse_event(struct usb_device_instance *device, usb_device_event_t event, int data) { int port = 0; // XXX compound device struct usb_function_instance *function; dbg_usbe(5,"%d",event); if ((function = device->function_instance_array+port)==NULL){ dbg_usbe(1,"no function"); return; } dbg_usbe(3,"---> %s %d", device->name, event); switch (event) { case DEVICE_UNKNOWN: case DEVICE_INIT: dbg_usbe(1,"---> INIT %s %d", device->name, event); break; case DEVICE_CREATE: dbg_usbe(1,"---> CREATE %s %d", device->name, event); { struct usb_mouse_private *mouse_private; struct proc_dir_entry *pentry; // There is no way to indicate error, so make this unconditional // and undo it in the DESTROY event unconditionally as well. // It the responsibility of the USBD core and the bus interface // to see that there is a matching DESTROY for every CREATE. if ((mouse_private = kmalloc(sizeof(struct usb_mouse_private),GFP_ATOMIC))==NULL) { dbg_usbe(1,"---> CREATE malloc failed %s",device->name); return; } mouse_private->device = device; mouse_private->duration = 0; /* infinite */ mouse_private->data_valid = 0; spin_lock_init(&mouse_private->lock); pentry = create_proc_entry(MOUSE_PROC_NAME, 0200, NULL); if (pentry) { pentry->write_proc = mouse_write_proc; pentry->data = mouse_private; } function->privdata = mouse_private; dbg_usbe(1,"---> START %s privdata assigned: %p", device->name, mouse_private); return; } break; case DEVICE_HUB_CONFIGURED: break; case DEVICE_RESET: break; case DEVICE_ADDRESS_ASSIGNED: break; case DEVICE_CONFIGURED: dbg_usbe(1,"---> CONFIGURED %s %d", device->name, event); break; case DEVICE_SET_INTERFACE: break; case DEVICE_SET_FEATURE: break; case DEVICE_CLEAR_FEATURE: break; case DEVICE_DE_CONFIGURED: dbg_usbe(1,"---> DECONFIGURED %s %d", device->name, event); break; case DEVICE_BUS_INACTIVE: break; case DEVICE_BUS_ACTIVITY: break; case DEVICE_POWER_INTERRUPTION: break; case DEVICE_HUB_RESET: break; case DEVICE_DESTROY: dbg_usbe(1, "---> DESTROY %s %d", device->name, event); { struct usb_mouse_private *mouse_private; if ((mouse_private = (device->function_instance_array+port)->privdata) == NULL) { dbg_usbe(1, "---> DESTROY %s mouse_private null", device->name); return; } dbg_usbe(1, "---> DESTROY %s mouse_private %p", device->name, mouse_private); kfree(mouse_private); remove_proc_entry(MOUSE_PROC_NAME, NULL); dbg_usbe(1,"---> STOP %s",device->name); return; } break; case DEVICE_FUNCTION_PRIVATE: dbg_usbe(3, "%s", usbd_device_events[DEVICE_FUNCTION_PRIVATE]); break; } } static void mouse_function_exit(struct usb_device_instance *device) { dbg_init(1, "CLOSING **************************"); /* DEVICE_DESTROY will not called when bi driver unloaded. Call here. */ mouse_event(device, DEVICE_DESTROY, 0); } struct usb_function_operations function_ops = { event: mouse_event, urb_sent: mouse_urb_sent, recv_setup:mouse_recv_setup, function_exit: mouse_function_exit, }; struct usb_function_driver function_driver = { name: "usbd mouse", ops: &function_ops, device_description: &mouse_device_description, configurations: sizeof(mouse_description)/sizeof(struct usb_configuration_description), configuration_description: mouse_description, this_module: THIS_MODULE, }; /* * mouse_modinit - module init * */ static int __init mouse_modinit(void) { printk(KERN_INFO "%s (dbg=\"%s\")\n", __usbd_module_info, dbg?dbg:""); if (vendor_id) { mouse_device_description.idVendor = vendor_id; } if (product_id) { mouse_device_description.idProduct = product_id; } printk(KERN_INFO "vendor_id: %04x product_id: %04x\n", mouse_device_description.idVendor, mouse_device_description.idProduct); if (0 != scan_debug_options("mouse_fd",dbg_table,dbg)) { return(-EINVAL); } // register us with the usb device support layer // if (usbd_register_function(&function_driver)) { return -EINVAL; } // return return 0; } /* mouse_modexit - module cleanup */ static void __exit mouse_modexit(void) { // de-register us with the usb device support layer // usbd_deregister_function(&function_driver); } module_init(mouse_modinit); module_exit(mouse_modexit); /* * Local variables: * c-basic-offset: 4 * End: */