当前位置: 首页 > news >正文

LINUX中USB驱动架构—USB驱动程序框架

usb/usb-skeleton.c文件为我们提供了一个最基础的USB驱动程序,即USB 程序框架,它可被看作一个最简单的USB设备驱动实例。

usb_driver结构体

static struct usb_driver skel_driver = {.name =		"skeleton",.probe =	skel_probe,.disconnect =	skel_disconnect,.suspend =	skel_suspend,.resume =	skel_resume,.pre_reset =	skel_pre_reset,.post_reset =	skel_post_reset,.id_table =	skel_table,.supports_autosuspend = 1,
};

所支持的USB设备的列表数组为skel_table[],id_table的结构为:

static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, skel_table);

对上述usb_driver的注册和注销发生在USB骨架程序的模块加载与卸载函数内,其分别调用了 usb_register()和usb_deregister(),不过这个注册和注销的代码却不用写出来,直接用一个快捷宏 module_usb_driver即可。

在usb_driver的probe()成员函数中,会根据usb_interface的成员寻找第一个批量输入和输出端点,将端点地址、缓冲区等信息存入为USB骨架程序定义的usb_skel结构体中,并将usb_skel实例的指针传入 usb_set_intfdata()中以作为USB接口的私有数据,最后,它会注册USB设备。

static int skel_probe(struct usb_interface *interface,const struct usb_device_id *id)
{struct usb_skel *dev;struct usb_host_interface *iface_desc;struct usb_endpoint_descriptor *endpoint;size_t buffer_size;int i;int retval = -ENOMEM;/* allocate memory for our device state and initialize it */dev = kzalloc(sizeof(*dev), GFP_KERNEL);if (!dev)goto error;kref_init(&dev->kref);sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);mutex_init(&dev->io_mutex);spin_lock_init(&dev->err_lock);init_usb_anchor(&dev->submitted);init_waitqueue_head(&dev->bulk_in_wait);dev->udev = usb_get_dev(interface_to_usbdev(interface));dev->interface = usb_get_intf(interface);/* set up the endpoint information *//* use only the first bulk-in and bulk-out endpoints */iface_desc = interface->cur_altsetting;for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {endpoint = &iface_desc->endpoint[i].desc;if (!dev->bulk_in_endpointAddr &&usb_endpoint_is_bulk_in(endpoint)) {/* we found a bulk in endpoint */buffer_size = usb_endpoint_maxp(endpoint);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)goto error;dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);if (!dev->bulk_in_urb)goto error;}if (!dev->bulk_out_endpointAddr &&usb_endpoint_is_bulk_out(endpoint)) {/* we found a bulk out endpoint */dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;}}if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {dev_err(&interface->dev,"Could not find both bulk-in and bulk-out endpoints\n");goto error;}/* save our data pointer in this interface device */usb_set_intfdata(interface, dev);/* we can register the device now, as it is ready */retval = usb_register_dev(interface, &skel_class);if (retval) {/* something prevented us from registering this driver */dev_err(&interface->dev,"Not able to get a minor for this device.\n");usb_set_intfdata(interface, NULL);goto error;}/* let the user know what node this device is now attached to */dev_info(&interface->dev,"USB Skeleton device now attached to USBSkel-%d",interface->minor);return 0;error:if (dev)/* this frees allocated memory */kref_put(&dev->kref, skel_delete);return retval;
}

usb_skel结构体可以被看作是一个私有数据结构体,应该根据具体的设备量身定制。

USB骨架程序的断开函数会完成与probe()函数相反的工作,即设置接口数据为NULL,注销USB设备。

usb_register_dev(interface,&skel_class)中的第二个参数skel_class包含了字符设备的 file_operations结构体指针,而这个结构体中的成员实现也是USB字符设备的另一个组成成分。

open()成员函数的实现非常简单,它根据usb_driver和次设备号 通过usb_find_interface()获得USB接口,之后通过usb_get_intfdata()获得接口的私有数据并赋予file- >private_data

接下来要分析的是读写函数,前面已经提到,在访问USB设备的时候,贯穿其中的“中枢神经”是URB 结构体。

设备写函数在urb小节已经给出,下面是skel_read读函数

static ssize_t skel_read(struct file *file, char *buffer, size_t count,loff_t *ppos)
{struct usb_skel *dev;int rv;bool ongoing_io;dev = file->private_data;/* if we cannot read at all, return EOF */if (!dev->bulk_in_urb || !count)return 0;/* no concurrent readers */rv = mutex_lock_interruptible(&dev->io_mutex);if (rv < 0)return rv;if (dev->disconnected) {		/* disconnect() was called */rv = -ENODEV;goto exit;}/* if IO is under way, we must not touch things */
retry:spin_lock_irq(&dev->err_lock);ongoing_io = dev->ongoing_read;spin_unlock_irq(&dev->err_lock);if (ongoing_io) {/* nonblocking IO shall not wait */if (file->f_flags & O_NONBLOCK) {rv = -EAGAIN;goto exit;}/** IO may take forever* hence wait in an interruptible state*/rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read));if (rv < 0)goto exit;}/* errors must be reported */rv = dev->errors;if (rv < 0) {/* any error is reported once */dev->errors = 0;/* to preserve notifications about reset */rv = (rv == -EPIPE) ? rv : -EIO;/* report it */goto exit;}/** if the buffer is filled we may satisfy the read* else we need to start IO*/if (dev->bulk_in_filled) {/* we had read data */size_t available = dev->bulk_in_filled - dev->bulk_in_copied;size_t chunk = min(available, count);if (!available) {/** all data has been used* actual IO needs to be done*/rv = skel_do_read_io(dev, count);if (rv < 0)goto exit;elsegoto retry;}/** data is available* chunk tells us how much shall be copied*/if (copy_to_user(buffer,dev->bulk_in_buffer + dev->bulk_in_copied,chunk))rv = -EFAULT;elserv = chunk;dev->bulk_in_copied += chunk;/** if we are asked for more than we have,* we start IO but don't wait*/if (available < count)skel_do_read_io(dev, count - chunk);} else {/* no data in the buffer */rv = skel_do_read_io(dev, count);if (rv < 0)goto exit;elsegoto retry;}
exit:mutex_unlock(&dev->io_mutex);return rv;
}


文章转载自:

http://eqMSLgM7.tdmgs.cn
http://AiAzFXg6.tdmgs.cn
http://65Vydcxj.tdmgs.cn
http://jZLJZA6H.tdmgs.cn
http://srV1U9kh.tdmgs.cn
http://GTseslu5.tdmgs.cn
http://ztBtWLqj.tdmgs.cn
http://ua61MjqG.tdmgs.cn
http://B2Wfwvs4.tdmgs.cn
http://VTcgzgUQ.tdmgs.cn
http://DY7tXWj9.tdmgs.cn
http://FnvB3DKe.tdmgs.cn
http://2MAyyk18.tdmgs.cn
http://Al1pyOjA.tdmgs.cn
http://ZJKrlFWe.tdmgs.cn
http://s91X45Qo.tdmgs.cn
http://d4XIFp05.tdmgs.cn
http://Q4j50nAe.tdmgs.cn
http://sP6T8DLD.tdmgs.cn
http://NsFe9IL0.tdmgs.cn
http://QqTrNc3N.tdmgs.cn
http://ylXw5lNk.tdmgs.cn
http://e2SV5APv.tdmgs.cn
http://bju91oTo.tdmgs.cn
http://C1ZmIGuy.tdmgs.cn
http://u6nO0dC0.tdmgs.cn
http://bnce0sTU.tdmgs.cn
http://eyXHKLQi.tdmgs.cn
http://44lMQt7C.tdmgs.cn
http://0Hrjuk0P.tdmgs.cn
http://www.dtcms.com/a/381599.html

相关文章:

  • 【Web】ImaginaryCTF 2025 wp
  • [Windows] (思源笔记首发ai辅助工具)叶归 AI 辅助精美笔记工具
  • 多线程详解
  • ArcGIS(Pro)在线地图服务被禁?提示感叹号?应急方案来了——重新正常显示
  • 《PyTorch 携手 Unity:基于云原生架构化解 AI 游戏系统显存危机》
  • pytorch基本运算-Python控制流梯度运算
  • 编程与数学 03-005 计算机图形学 17_虚拟现实与增强现实技术
  • 计算机网络(一)基础概念
  • [Windows] 搜索文本2.6.2(从word、wps、excel、pdf和txt文件中查找文本的工具)
  • 【iOS】设计模式复习
  • RNN,GRU和LSTM的简单实现
  • 无人机如何实现图传:从原理到实战的全景解读
  • 多旋翼无人机开发方案
  • 基于MATLAB的无人机三维路径规划与避障算法实现
  • Web基础学习笔记02
  • Spring Boot 项目启动报错:MongoSocketOpenException 连接被拒绝排查日记
  • OpenCV(cv2)学习笔记:从模板匹配入门到常用函数
  • FFmpeg合成mp4
  • 解决 ubuntu 重启串口号变化
  • 《算法与数据结构》第六章[第3节]:二叉树(第二部分)
  • 深入理解 Python 中的 `__call__` 方法
  • AI 智能体的定义与演进
  • 鸿蒙Next ArkWeb网页交互管理:从基础到高级实战
  • 给CentOS的虚拟机扩容
  • Redis 持久化:RDB 和 AOF 的 “爱恨情仇”
  • 多源最短路(Floyd算法
  • 【数据结构——图(例图篇)】
  • 安卓俄罗斯方块,经典拖动双模式体验
  • 21th cpp think
  • 收集飞花令碎片——C语言关键字typedef