Linux USB 鼠标驱动程序详解
注册一个usb driver,这个drvier不是usb设备driver,而是接口driver。
/* use a define to avoid include chaining to get THIS_MODULE & friends */
#define usb_register(driver) \usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)retval = driver_register(&new_driver->drvwrap.driver);if (retval)goto out;
这个probe参数1是一个接口数据结构,表示注册的时接口驱动不是设备驱动,设备驱动在在系统中已经注册好了,是一个通用设备驱动,用来读取设备的描述符,做一些解析。所以我们真正实现的时一个usb接口驱动。
static int usb_mouse_probe(struct usb_interface *intf,const struct usb_device_id *id);
//表示一个接口
struct usb_interface {/* array of alternate settings for this interface,* stored in no particular order */struct usb_host_interface *altsetting;struct usb_host_interface *cur_altsetting; /* the currently* active alternate setting */unsigned num_altsetting; /* number of alternate settings *//* If there is an interface association descriptor then it will list* the associated interfaces */struct usb_interface_assoc_descriptor *intf_assoc;int minor; /* minor number this interface is* bound to */enum usb_interface_condition condition; /* state of binding */unsigned sysfs_files_created:1; /* the sysfs attributes exist */unsigned ep_devs_created:1; /* endpoint "devices" exist */unsigned unregistering:1; /* unregistration is in progress */unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */unsigned needs_binding:1; /* needs delayed unbind/rebind */unsigned resetting_device:1; /* true: bandwidth alloc after reset */unsigned authorized:1; /* used for interface authorization */struct device dev; /* interface specific device info */struct device *usb_dev;struct work_struct reset_ws; /* for resets in atomic context */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
usb设备结构体
struct usb_device {int devnum;char devpath[16];u32 route;enum usb_device_state state;enum usb_device_speed speed;unsigned int rx_lanes;unsigned int tx_lanes;struct usb_tt *tt;int ttport;unsigned int toggle[2];struct usb_device *parent;struct usb_bus *bus;struct usb_host_endpoint ep0;struct device dev;struct usb_device_descriptor descriptor;struct usb_host_bos *bos;struct usb_host_config *config;struct usb_host_config *actconfig;struct usb_host_endpoint *ep_in[16];struct usb_host_endpoint *ep_out[16];char **rawdescriptors;unsigned short bus_mA;u8 portnum;u8 level;unsigned can_submit:1;unsigned persist_enabled:1;unsigned have_langid:1;unsigned authorized:1;unsigned authenticated:1;unsigned wusb:1;unsigned lpm_capable:1;unsigned usb2_hw_lpm_capable:1;unsigned usb2_hw_lpm_besl_capable:1;unsigned usb2_hw_lpm_enabled:1;unsigned usb2_hw_lpm_allowed:1;unsigned usb3_lpm_u1_enabled:1;unsigned usb3_lpm_u2_enabled:1;int string_langid;/* static strings from the device */char *product;char *manufacturer;char *serial;struct list_head filelist;int maxchild;u32 quirks;atomic_t urbnum;unsigned long active_duration;#ifdef CONFIG_PMunsigned long connect_time;unsigned do_remote_wakeup:1;unsigned reset_resume:1;unsigned port_is_suspended:1;
#endifstruct wusb_dev *wusb_dev;int slot_id;enum usb_device_removable removable;struct usb2_lpm_parameters l1_params;struct usb3_lpm_parameters u1_params;struct usb3_lpm_parameters u2_params;unsigned lpm_disable_count;u16 hub_delay;
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
int devnum; //usb总线上的一个地址
struct usb_device_descriptor descriptor; //设备描述符
配置描述符,可以有多个配置描述。
struct usb_host_config {struct usb_config_descriptor desc;char *string; /* iConfiguration string, if present *//* List of any Interface Association Descriptors in this* configuration. */struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];/* the interfaces associated with this configuration,* stored in no particular order */struct usb_interface *interface[USB_MAXINTERFACES];/* Interface information available even when this is not the* active configuration */struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];unsigned char *extra; /* Extra descriptors */int extralen;
};
/* host-side wrapper for one interface setting’s parsed descriptors */
一个接口设置的解析描述符的主机端包装器
/* host-side wrapper for one interface setting's parsed descriptors */
struct usb_host_interface {struct usb_interface_descriptor desc;int extralen;unsigned char *extra; /* Extra descriptors *//* array of desc.bNumEndpoints endpoints associated with this* interface setting. these will be in no particular order.*/struct usb_host_endpoint *endpoint;char *string; /* iInterface string, if present */
};
端点结构体:表示一个端点
//鼠标驱动代码学习。
/** Copyright (c) 1999-2001 Vojtech Pavlik** USB HIDBP Mouse support*//** 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA** Should you need to contact me, the author, you can do so either by* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic*/#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>/* for apple IDs */
#ifdef CONFIG_USB_HID_MODULE
#include "../hid-ids.h"
#endif/** Version Information*/
#define DRIVER_VERSION "v1.6"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB HID Boot Protocol mouse driver"MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");struct usb_mouse {char name[128];char phys[64];struct usb_device *usbdev;struct input_dev *dev;struct urb *irq;signed char *data;dma_addr_t data_dma;
};static void usb_mouse_irq(struct urb *urb)
{struct usb_mouse *mouse = urb->context;signed char *data = mouse->data;struct input_dev *dev = mouse->dev;int status;switch (urb->status) {case 0: /* success */break;case -ECONNRESET: /* unlink */case -ENOENT:case -ESHUTDOWN:return;/* -EPIPE: should clear the halt */default: /* error */goto resubmit;}input_report_key(dev, BTN_LEFT, data[0] & 0x01);input_report_key(dev, BTN_RIGHT, data[0] & 0x02);input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);input_report_key(dev, BTN_SIDE, data[0] & 0x08);input_report_key(dev, BTN_EXTRA, data[0] & 0x10);input_report_rel(dev, REL_X, data[1]);input_report_rel(dev, REL_Y, data[2]);input_report_rel(dev, REL_WHEEL, data[3]);input_sync(dev);
resubmit:status = usb_submit_urb (urb, GFP_ATOMIC);if (status)dev_err(&mouse->usbdev->dev,"can't resubmit intr, %s-%s/input0, status %d\n",mouse->usbdev->bus->bus_name,mouse->usbdev->devpath, status);
}static int usb_mouse_open(struct input_dev *dev)
{struct usb_mouse *mouse = input_get_drvdata(dev);mouse->irq->dev = mouse->usbdev;if (usb_submit_urb(mouse->irq, GFP_KERNEL))return -EIO;return 0;
}static void usb_mouse_close(struct input_dev *dev)
{struct usb_mouse *mouse = input_get_drvdata(dev);usb_kill_urb(mouse->irq);
}static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{struct usb_device *dev = interface_to_usbdev(intf);struct usb_host_interface *interface;struct usb_endpoint_descriptor *endpoint;struct usb_mouse *mouse;struct input_dev *input_dev;int pipe, maxp;int error = -ENOMEM;interface = intf->cur_altsetting;if (interface->desc.bNumEndpoints != 1)return -ENODEV;endpoint = &interface->endpoint[0].desc;if (!usb_endpoint_is_int_in(endpoint))return -ENODEV;pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);input_dev = input_allocate_device();if (!mouse || !input_dev)goto fail1;mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);if (!mouse->data)goto fail1;mouse->irq = usb_alloc_urb(0, GFP_KERNEL);if (!mouse->irq)goto fail2;mouse->usbdev = dev;mouse->dev = input_dev;if (dev->manufacturer)strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));if (dev->product) {if (dev->manufacturer)strlcat(mouse->name, " ", sizeof(mouse->name));strlcat(mouse->name, dev->product, sizeof(mouse->name));}if (!strlen(mouse->name))snprintf(mouse->name, sizeof(mouse->name),"USB HIDBP Mouse %04x:%04x",le16_to_cpu(dev->descriptor.idVendor),le16_to_cpu(dev->descriptor.idProduct));usb_make_path(dev, mouse->phys, sizeof(mouse->phys));strlcat(mouse->phys, "/input0", sizeof(mouse->phys));input_dev->name = mouse->name;input_dev->phys = mouse->phys;usb_to_input_id(dev, &input_dev->id);input_dev->dev.parent = &intf->dev;input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |BIT_MASK(BTN_EXTRA);input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);input_set_drvdata(input_dev, mouse);input_dev->open = usb_mouse_open;input_dev->close = usb_mouse_close;usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,(maxp > 8 ? 8 : maxp),usb_mouse_irq, mouse, endpoint->bInterval);mouse->irq->transfer_dma = mouse->data_dma;mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;error = input_register_device(mouse->dev);if (error)goto fail3;usb_set_intfdata(intf, mouse);return 0;fail3: usb_free_urb(mouse->irq);
fail2: usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
fail1: input_free_device(input_dev);kfree(mouse);return error;
}static void usb_mouse_disconnect(struct usb_interface *intf)
{struct usb_mouse *mouse = usb_get_intfdata (intf);usb_set_intfdata(intf, NULL);if (mouse) {usb_kill_urb(mouse->irq);input_unregister_device(mouse->dev);usb_free_urb(mouse->irq);usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);kfree(mouse);}
}static const struct usb_device_id usb_mouse_id_table[] = {{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE) },{ } /* Terminating entry */
};MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);static struct usb_driver usb_mouse_driver = {.name = "usbmouse",.probe = usb_mouse_probe,.disconnect = usb_mouse_disconnect,.id_table = usb_mouse_id_table,
};module_usb_driver(usb_mouse_driver);