发布时间 : 星期一 文章Linux下USB驱动程序简单例程更新完毕开始阅读320d55ecf8c75fbfc77db216
// 自定义结构体类型
// 用于保存USB设备相关信息 struct usb_skel {
struct usb_device * udev; /* usb设备对象 */ struct usb_interface * interface; /* usb设备接口对象 */ struct semaphore limit_sem; /* 写信号量 */
unsigned char * bulk_in_buffer; /* 批量传输方式的接收缓存 */ size_t bulk_in_size; /* 接收缓存中的有效字节数 */ __u8 bulk_in_endpointAddr; /* 批量输入端口地址 */ __u8 bulk_out_endpointAddr; /* 批量输出端口地址 */ struct kref kref; }dev;
// 以production ID和vendor ID组合匹配驱动程序 static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* Terminating entry */ };
Static ssize_t skel_write(struct file * filep, const char * buff, size_t count, loff_t * offp) {
// 数据的发送方式可以选择urb方式和非urb方式
// urb方式将数据填充到一个urb中,然后发送urb给内核,内核再将数据送上USB总线 // 非urb方式直接将数据发送给内核,而不填充urb结构
// 创建通讯管道
unsigned int pipe = usb_sndbulkpipe(dev.udevice, dev.bulk_out_endpointAddr);
/************************** urb 方式 *********************************/
// 创建一个urb(usb request block)
struct urb * usb_alloc_urb(0, // 等时包的数量,如果不是乘载等时包,应该为0
mem_flags);
// 填充urb
void usb_fill_bulk_urb(urb,
dev.udevice, // 目的USB设备指针 pipe, // 与USB设备通讯时使用的管道
buff, // 发送数据缓存
count,// 发送数据的字节数
skel_write_bulk_callback, // 数据发送结束后回调函数指针 void *context); // 由用户定义
// 发送urb,如果成功retval值为0,数据发送结束后可以通过urb->status查询状态 retval = usb_submit_urb(urb, GFP_KERNEL);
/*************************** 非urb方式 ***************************/ Usinged int bytes_read;
retval = usb_bulk_msg(dev->udev,
pipe, buff, count, &bytes_read,
10000);
}
// 设备文件操作结构
static struct file_operations skel_fops = { .owner = THIS_MODULE, .read = skel_read, .write = skel_write, .open = skel_open, .release = skel_release, };
static struct usb_class_driver skel_class = { .name = \设备驱动程序类名 .fops = &skel_fops, // 设备文件操作结构 .minor_base = USB_SKEL_MINOR_BASE, // 次设备号的基准值 };
skel_probe(usb_interface * interface, struct usb_device_id * device_id) {
dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface;
// 本例程,probe函数查找端口中BULK_IN端点和BULK_OUT端点, // 并将相关信息保存道dev变量中
iface_desc = interface->cur_altsetting; // 获取接口的当前配置 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
{
endpoint = &iface_desc->endpoint[i].desc;
// 如果这是一个BULK_IN端点
if ( !dev->bulk_in_endpointAddr &&
((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) = = USB_DIR_IN) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) = = USB_ENDPOINT_XFER_BULK))
{
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) {
err(\ goto error; } }
// 如果这是一个BULK_OUT端点
if (!dev->bulk_out_endpointAddr &&
((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)= =USB_DIR_OUT) && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)= = USB_ENDPOINT_XFER_BULK))
{
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; } }
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { err(\ goto error; }
// 注册usb_class_driver结构,其中包含对USB设备的操作方法等 retval = usb_register_dev(interface, &skel_class); }
static struct usb_driver skel_driver = { .name = \驱动程序名
.probe = skel_probe, // 函数指针,设备与skel_table匹配成功后被调用,
// 完成一些初始化工作
.disconnect = skel_disconnect,
.id_table = skel_table, // usb内核通过设备的production ID和vendor ID的组合
// 或者设备的class、subclass跟protocol的组合来识别设备 // skel_table用于匹配USB内核识别是否将此驱动程序作为已// 识别设备的驱动程序。
};
static int __init usb_skel_init(void) {
int result;
/* register this driver with the USB subsystem */ result = usb_register(&skel_driver); if (result)
err(\ return result; }
static void __exit usb_skel_exit(void) {
/* deregister this driver with the USB subsystem */ usb_deregister(&skel_driver); }
module_init (usb_skel_init); module_exit (usb_skel_exit); MODULE_LICENSE(\