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

大学网站建设定制网站建设昆明网站建设外包

大学网站建设定制网站建设,昆明网站建设外包,seo快速软件,我要自学网做网站随着生活水平的提高#xff0c;人们对USB设备的使用也越来越多#xff0c;鉴于Linux在硬件配置上尚不能全部即插即用#xff0c;因此关于Linux如何配置和使用#xff0c;成为困扰我们的一大问题。本文引用地址#xff1a;http://www.eepw.com.cn/article/70029.htmlinux操…随着生活水平的提高人们对USB设备的使用也越来越多鉴于Linux在硬件配置上尚不能全部即插即用因此关于Linux如何配置和使用成为困扰我们的一大问题。本文引用地址http://www.eepw.com.cn/article/70029.htmlinux操作系统文章专题:linux操作系统详解(linux不再难懂)什么是USBUSB是英文Universal Serial Bus的缩写意为通用串行总线。USB最初是为了替代许多不同的低速总线(包括并行、串行和键盘连接)而设计的它以单一类型的总线连接各种不同的类型的设备。USB的发展已经超越了这些低速的连接方式它现在可以支持几乎所有可以连接到PC上的设备。最新的USB规范修订了理论上高达480Mbps的高速连接。Linux内核支持两种主要类型的USB驱动程序宿主系统上的驱动程序和设备上的驱动程序从宿主的观点来看(一个普通的宿主也就是一个PC机)宿主系统的USB设备驱动程序控制插入其中的USB设备而USB设备的驱动程序控制该设备如何作为一个USB设备和主机通信。USB的具体构成在动手写USB驱动程序这前让我们先看看写的USB驱动程序在内核中的结构如下图USB驱动程序存在于不同的内核子系统和USB硬件控制器之间USB核心为USB驱动程序提供了一个用于访问和控制USB硬件的接口而不必考虑系统当前存在的各种不同类型的USB硬件控制器。USB是一个非常复杂的设备linux内核为我们提供了一个称为USB的核心的子系统来处理大部分的复杂性USB设备包括配置(configuration)、接口(interface)和端点(endpoint)USB设备绑定到接口上而不是整个USB设备。如下图所示USB通信最基本的形式是通过端点(USB端点分中断、批量、等时、控制四种每种用途不同)USB端点只能往一个方向传送数据从主机到设备或者从设备到主机端点可以看作是单向的管道(pipe)。所以我们可以这样认为设备通常具有一个或者更多的配置配置经常具有一个或者更多的接口接口通常具有一个或者更多的设置接口没有或具有一个以上的端点。驱动程序把驱动程序对象注册到USB子系统中稍后再使用制造商和设备标识来判断是否已经安装了硬件。USB核心使用一个列表(是一个包含制造商ID和设备号ID的一个结构体)来判断对于一个设备该使用哪一个驱动程序热插拨脚本使用它来确定当一个特定的设备插入到系统时该自动装载哪一个驱动程序。上面我们简要说明了驱动程序的基本理论在写一个设备驱动程序之前我们还要了解以下两个概念模块和设备文件。模块是在内核空间运行的程序实际上是一种目标对象文件没有链接不能独立运行但是可以装载到系统中作为内核的一部分运行从而可以动态扩充内核的功能。模块最主要的用处就是用来实现设备驱动程序。Linux下对于一个硬件的驱动可以有两种方式直接加载到内核代码中启动内核时就会驱动此硬件设备。另一种就是以模块方式编译生成一个.ko文件(在2.4以下内核中是用.o作模块文件我们以2.6的内核为准以下同)。当应用程序需要时再加载到内核空间运行。所以我们所说的一个硬件的驱动程序通常指的就是一个驱动模块。设备文件对于一个设备它可以在/dev下面存在一个对应的逻辑设备节点这个节点以文件的形式存在但它不是普通意义上的文件它是设备文件更确切的说它是设备节点。这个节点是通过mknod命令建立的其中指定了主设备号和次设备号。主设备号表明了某一类设备一般对应着确定的驱动程序次设备号一般是区分不同属性例如不同的使用方法不同的位置不同的操作。这个设备号是从/proc/devices文件中获得的所以一般是先有驱动程序在内核中才有设备节点在目录中。这个设备号(特指主设备号)的主要作用就是声明设备所使用的驱动程序。驱动程序和设备号是一一对应的当你打开一个设备文件时操作系统就已经知道这个设备所对应的驱动程序。对于一个硬件Linux是这样来进行驱动的首先我们必须提供一个.ko的驱动模块文件。我们要使用这个驱动程序首先要加载它我们可以用insmod xxx.ko这样驱动就会根据自己的类型(字符设备类型或块设备类型例如鼠标就是字符设备而硬盘就是块设备)向系统注册注册成功系统会反馈一个主设备号这个主设备号就是系统对它的唯一标识。驱动就是根据此主设备号来创建一个一般放置在/dev目录下的设备文件。在我们要访问此硬件时就可以对设备文件通过open、read、write、close等命令进行。而驱动就会接收到相应的read、write操作而根据自己的模块中的相应函数进行操作了。USB驱动程序如何应用了解了上述理论后我们就可以动手写驱动程序如果你基本功好而且写过linux下的硬件驱动USB的硬件驱动和pci_driver很类似那么写USB的驱动就比较简单了如果你只是大体了解了linux的硬件驱动那也不要紧因为在linux的内核源码中有一个框架程序可以拿来借用一下这个框架程序在/usr/src/~(你的内核版本以下同)/drivers/usb下文件名为usb-skeleton.c。写一个USB的驱动程序最基本的要做四件事驱动程序要支持的设备、注册USB驱动程序、探测和断开、提交和控制urb(USB请求块)(当然也可以不用urb来传输数据下文我们会说到)。驱动程序支持的设备有一个结构体struct usb_device_id这个结构体提供了一列不同类型的该驱动程序支持的USB设备对于一个只控制一个特定的USB设备的驱动程序来说struct usb_device_id表被定义为/* 驱动程序支持的设备列表 */static struct usb_device_id skel_table [] {{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },{ }                               /* 终止入口 */};MODULE_DEVICE_TABLE (usb, skel_table);对于PC驱动程序MODULE_DEVICE_TABLE是必需的而且usb必需为该宏的第一个值而USB_SKEL_VENDOR_ID和USB_SKEL_PRODUCT_ID就是这个特殊设备的制造商和产品的ID了我们在程序中把定义的值改为我们这款USB的如/* 定义制造商和产品的ID号 */#define USB_SKEL_VENDOR_ID       0x1234#define USB_SKEL_PRODUCT_ID     0x2345这两个值可以通过命令lsusb当然你得先把USB设备先插到主机上了。或者查看厂商的USB设备的手册也能得到在我机器上运行lsusb是这样的结果Bus 004 Device 001: ID 0000:0000Bus 003 Device 002: ID 1234:2345  Abc  Corp.Bus 002 Device 001: ID 0000:0000Bus 001 Device 001: ID 0000:0000得到这两个值后把它定义到程序里就可以了。注册USB驱动程序所有的USB驱动程序都必须创建的结构体是struct usb_driver。这个结构体必须由USB驱动程序来填写包括许多回调函数和变量它们向USB核心代码描述USB驱动程序。创建一个有效的struct usb_driver结构体只须要初始化五个字段就可以了在框架程序中是这样的static struct usb_driver skel_driver {.owner THIS_MODULE,.name          skeleton,.probe  skel_probe,.disconnect  skel_disconnect,.id_table      skel_table,};struct module *owner 指向该驱动程序的模块所有者的批针。USB核心使用它来正确地对该USB驱动程序进行引用计数使它不会在不合适的时刻被卸载掉这个变量应该被设置为THIS_MODULE宏。const char *name指向驱动程序名字的指针在内核的所有USB驱动程序中它必须是唯一的通常被设置为和驱动程序模块名相同的名字。 {{分页}}int (*probe) (struct usb_interface *intf,const struct usb_device_id *id)这个是指向USB驱动程序中的探测函数的指针。当USB核心认为它有一个接口(usb_interface)可以由该驱动程序处理时这个函数被调用。void (disconnect)(struct usb_interface *intf)指向USB驱动程序中的断开函数的指针当一个USB接口(usb_interface)被从系统中移除或者驱动程序正在从USB核心中卸载时USB核心将调用这个函数。const struct usb_device_id *id_table指向ID设备表的指针这个表包含了一列该驱动程序可以支持的USB设备如果没有设置这个变量USB驱动程序中的探测回调函数就不会被调用。在这个结构体中还有其它的几个回调函数不是很常用这里就不一一说明了。以struct usb_driver 指针为参数的usb_register_driver函数调用把struct usb_driver注册到USB核心。一般是在USB驱动程序的模块初始化代码中完成这个工作的static int __init usb_skel_init(void){int result;/* 驱动程序注册到USB子系统中*/result usb_register(skel_driver);if (result)err(usb_register failed. Error number %d, result);return result;}当USB驱动程序将要被卸开时需要把struct usb_driver从内核中注销。通过调用usb_deregister_driver来完成这个工作当调用发生时当前绑定到该驱动程序上的任何USB接口都被断开断开函数将被调用static void __exit usb_skel_exit(void){/* 从子系统注销驱动程序 */usb_deregister(skel_driver);}探测和断开当一个设备被安装而USB核心认为该驱动程序应该处理时探测函数被调用探测函数检查传递给它的设备信息确定驱动程序是否真的适合该设备。当驱动程序因为某种原因不应该控制设备时断开函数被调用它可以做一些清理工作。探测回调函数中USB驱动程序初始化任何可能用于控制USB设备的局部结构体它还把所需的任何设备相关信息保存到一个局部结构体中下面是探测函数的部分源码我们加以分析。/* 设置端点信息 *//* 只使用第一个批量IN和批量OUT端点 */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 (endpoint-bEndpointAddress USB_DIR_IN) ((endpoint-bmAttributes USB_ENDPOINT_XFERTYPE_MASK) USB_ENDPOINT_XFER_BULK)) {/* 找到一个批量IN端点 */buffer_size 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(Could not allocate bulk_in_buffer);goto error;}}if (!dev-bulk_out_endpointAddr !(endpoint-bEndpointAddress USB_DIR_IN) ((endpoint-bmAttributes USB_ENDPOINT_XFERTYPE_MASK) USB_ENDPOINT_XFER_BULK)) {/* 找到一个批量OUT端点 */dev-bulk_out_endpointAddr endpoint-bEndpointAddress;}}if (!(dev-bulk_in_endpointAddr dev-bulk_out_endpointAddr)) {err(Could not find both bulk-in and bulk-out endpoints);goto error;}在探测函数里这个循环首先访问该接口中存在的每一个端点给该端点一个局部指针以便以后访问for (i 0; i iface_desc-desc.bNumEndpoints; i) {endpoint iface_desc-endpoint[i].desc;在一轮探测过后我们就有了一个端点在还没有发现批量IN类型的端点时探测该端点方向是否为IN这可以通过检查USB_DIR_IN是否包含在bEndpointAddress端点变量有确定如果是的话我们在探测该端点类型是否为批量先用USB_ENDPOINT_XFERTYPE_MASK位掩来取bmAttributes变量的值然后探测它是否和USB_ENDPOINT_XFER_BULK值匹配if (!dev-bulk_out_endpointAddr !(endpoint-bEndpointAddress USB_DIR_IN) ((endpoint-bmAttributes USB_ENDPOINT_XFERTYPE_MASK) USB_ENDPOINT_XFER_BULK))如果所有这些探测都通过了驱动程序就知道它已经发现了正确的端点类型可以把该端点的相关信息保存到一个局部结构体中以便稍后用它来和端点进行通信/* 找到一个批量IN类型的端点 */buffer_size 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(Could not allocate bulk_in_buffer);goto error;}因为USB驱动程序要在设备的生命周期的稍后时间获取和接口相关联的局部数据结构体所以调用了usb_set_intfdata函数把它保存到struct usb_interface结构体中以便后面的访问/* 把数据指针保存到这个接口设备中 */usb_set_intfdata(interface, dev);我们以后调用usb_set_intfdata函数来获取数据。当这一切都完成后USB驱动程序必须在探测函数中调用usb_register_dev函数来把该设备注册到USB核心里/* 注册设备到USB核心 */retval usb_register_dev(interface, skel_class);if (retval) {/* 有些情况下是不允许注册驱动程序的 */err(Not able to get a minor for this device.);usb_set_intfdata(interface, NULL);goto error;}当一个USB设备被断开时和该设备相关联的所有资源都应该被尽可能的清理掉在此时如果已在在探测函数中调用了注册函数来为该USB设备分配了一个次设备号话必须调用usb_deregister_dev函数来把次设备号交还给USB核心。在断开函数中从接口获取之前调用usb_set_intfdata设置的任何数据也是很重要的。然后设置struct usb_interface结构体中的数据指针为NULL以防任何不适当的对该数据的错误访问。在探测函数中会对每一个接口进行一次探测所以我们在写USB驱动程序的时候只要做好第一个端点其它的端点就会自动完成探测。在探测函数中我们要注意的是在内核中用结构体struct usb_host_endpoint来描述USB端点这个结构体在另一个名为struct usb_endpoint_descriptor的结构体中包含了真正的端点信息struct usb_endpoint_descriptor结构体包含了所有的USB特定的数据该结构体中我们要关心的几个字段是bEndpointAddress这个是特定的USB地址可以结合USB_DIR_IN和USB_DIR_OUT来使用以确定该端点的数据是传向设备还是主机。bmAttributes这个是端点的类型这个值可以结合位掩码USB_ENDPOINT_XFERTYPE_MASK来使用以确定此端点的类型是USB_ENDPOINT_XFER_ISOC(等时)、USB_ENDPOINT_XFER_BULK(批量)、USB_ENDPOINT_XFER_INT的哪一种。wMaxPacketSize这个是端点一次可以处理的最大字节数驱动程序可以发送数量大于此值的数据到端点在实际传输中数据量如果大于此值会被分割。bInterval这个值只有在端点类型是中断类型时才起作用它是端点中断请求的间隔时间以毫秒为单位。 {{分页}}提交和控制urb当驱动程序有数据要发送到USB设备时(大多数情况是在驱动程序的写函数中)要分配一个urb来把数据传输给设备/* 创建一个urb,并且给它分配一个缓存*/urb usb_alloc_urb(0, GFP_KERNEL);if (!urb) {retval -ENOMEM;goto error;}当urb被成功分配后还要创建一个DMA缓冲区来以高效的方式发送数据到设备传递给驱动程序的数据要复制到这块缓冲中去buf usb_buffer_alloc(dev-udev, count, GFP_KERNEL, urb-transfer_dma);if (!buf) {retval -ENOMEM;goto error;}if (copy_from_user(buf, user_buffer, count)) {retval -EFAULT;goto error;}当数据从用户空间正确复制到局部缓冲区后urb必须在可以被提交给USB核心之前被正确初始化/* 初始化urb */usb_fill_bulk_urb(urb, dev-udev,usb_sndbulkpipe(dev-udev, dev-bulk_out_endpointAddr),buf, count, skel_write_bulk_callback, dev);urb-transfer_flags | URB_NO_TRANSFER_DMA_MAP;然后urb就可以被提交给USB核心以传输到设备了/* 把数据从批量OUT端口发出 */retval usb_submit_urb(urb, GFP_KERNEL);if (retval) {err(%s - failed submitting write urb, error %d, __FUNCTION__, retval);goto error;}当urb被成功传输到USB设备之后urb回调函数将被USB核心调用在我们的例子中我们初始化urb使它指向skel_write_bulk_callback函数以下就是该函数static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs){struct usb_skel *dev;dev (struct usb_skel *)urb-context;if (urb-status !(urb-status -ENOENT ||urb-status -ECONNRESET ||urb-status -ESHUTDOWN)) {dbg(%s - nonzero write bulk status received: %d,__FUNCTION__, urb-status);}/* 释放已分配的缓冲区 */usb_buffer_free(urb-dev, urb-transfer_buffer_length,urb-transfer_buffer, urb-transfer_dma);}有时候USB驱动程序只是要发送或者接收一些简单的数据驱动程序也可以不用urb来进行数据的传输这是里涉及到两个简单的接口函数usb_bulk_msg和usb_control_msg 在这个USB框架程序里读操作就是这样的一个应用/* 进行阻塞的批量读以从设备获取数据 */retval usb_bulk_msg(dev-udev,usb_rcvbulkpipe(dev-udev, dev-bulk_in_endpointAddr),dev-bulk_in_buffer,min(dev-bulk_in_size, count),count, HZ*10);/*如果读成功复制到用户空间 */if (!retval) {if (copy_to_user(buffer, dev-bulk_in_buffer, count))retval -EFAULT;elsen
http://www.pierceye.com/news/763437/

相关文章:

  • 北京大兴地区网站建设国外网站设计欣赏分析
  • 如何在网站中加入百度地图广东深圳软件开发公司
  • 诸城网站建设报价兰州网站建设公司有哪些
  • 技术网站的费用怎么做会计分录潍坊模板开发建站
  • 男生女生在床上做的那个网站公众号推广一个6元
  • 湛江做网站设计公司北京婚恋网站哪家最好
  • 大型网站建设的难点是什么物联网技术
  • 怎么免费建个免费的站点写作网站5妙不写就删除
  • 深圳网站建设软件开发公司排名网站做301的坏处
  • ai网站制作的图片
  • 自己想开个网站怎么弄移动端网站设计欣赏
  • 国外网站建站上海品牌策划设计
  • 郑州网站制作选择乐云seo网站建设误区图
  • 湖南智能网站建设多少钱会声会影免费模板网站
  • 社区网站建设方案书建站之星官方网站
  • 过时的网站什么公司做企业网站
  • 最新企业网站搜索引擎优化是做什么
  • 提高网站公信力 单仁手机设计培训网站建设
  • asp.net网站管理系统域名注册报备
  • 买了个网站后怎么做如何提高 网站的点击量
  • 哪些行业网站推广做的多o2o商城源码
  • 北京seo站内优化电商网站前端页面响应式设计
  • 贵港seo关键词整站优化网站恶意攻击
  • 王磊网络网站建设公关
  • 怎么建网站做推广win网站建设
  • 在线做英语题的网站wordpress被设置不录入
  • 桃花岛网站是什么翻硬币网站怎么做
  • 做海报的网站有哪些内容windows同步wordpress
  • 制作网页的网站费用属于资本性支出吗安徽区块链虚拟币网站开发方案
  • 做网站前产品经理要了解什么搜索引擎优化免费