1、基本框架
struct usb_dev_data {
struct usb_endpoint_descriptor *ep_in;
struct usb_endpoint_descriptor *ep_out;
struct input_dev *input;
spinlock_t lock;
};
static int usb_device_probe(struct usb_interface *iface, const struct usb_device_id *id)
{
int i, ret;
struct usb_dev_data *usb;
struct usb_host_interface *alt = iface->altsetting;
usb = kzalloc(sizeof(*usb), GFP_KERNEL);
if (!usb)
return -ENOMEM;
/* 获取主机与设备通信所使用的端点 */
for (i = 0; i < alt->desc.bNumEndpoints; i++) {
if (usb_endpoint_dir_in(&alt->endpoint[i].desc)) {
usb->ep_in = &alt->endpoint[i].desc;
} else if (usb_endpoint_dir_out(&alt->endpoint[i].desc)) {
usb->ep_out = &alt->endpoint[i].desc;
}
}
spin_lock_init(&usb->lock);
/* 将上面分配的内存保存到interface的私有数据中 */
usb_set_intfdata(iface, usb);
/* 先分配一个input_dev */
usb->input = input_allocate_device(sizeof(*usb));
if (!usb->input) {
kfree(usb)
return -ENOMEM;
}
xxxx
/*
*
*
*/
/* 注册input device */
ret = input_register_device(usb->input);
if (ret) {
input_free_device(usb->input);
kfree(usb);
return ret;
}
return ret;
}
static void usb_device_disconnect(struct usb_interface *iface)
{
struct usb_dev_data *usb = usb_get_intfdata(iface);
input_unregister_device(usb->input);
input_free_device(usb->input);
kfree(usb);
}
static const struct usb_device_id usb_device_id_table[] = {
{USB_DEVICE(VID, PID)},
{}
};
static struct usb_driver usb_device_driver = {
.name = "usb_device",
.probe = usb_device_probe,
.disconnect = usb_device_disconnect,
.id_table = usb_device_id_table
};
module_usb_driver(usb_device_driver);
MODULE_LICENSE("GPL");
以上是USB设备驱动的基本框架。
device_id_table用于告诉内核,这个驱动适用于哪些设备,
只有PID和VID完全匹配之后就会进入probe流程。
当设备被拔掉之后内核会执行disconnect方法。
在probe函数申明了一个struct usb_dev_data类型的指针,并为之分配了内存。
并将该指针保存到了interface的私有数据中,这个变量会在整个驱动的流程中使用到,
这里我只是在struct usb_dev_data中定义了2个变量,一个是out endpoint和in endpoint。在实际的驱动,这里还会有你需要的相应的设备结构,比如chrdev, input_dev等等。
这时候,就可以完成相应的驱动开发。
在相应的设备的私有数据中保存端点信息,收发的时候,使用usb相应的收发函数实现。今天就暂时不讲。