第八章 USB 设备驱动移植
8.1 USB协议
USB协议系统主要组成,总线拓扑结构,内部层次关系,数据流模式,USB调度等等
8.1.1 主要组成部分
USB的连接部分,USB的设备和USB的主机
************USB主机,设备分层模型************
USB主机:USB主机控制器,USB系统软件集合,客户软件
USB系统软件集合:USB驱动程序、主机控制器驱动程序和主机软件
USB设备:USB总线接口、USB逻辑设备、应用层
USB结构体 usb_device
struct usb_device {int devnum; //设备号,在USB总线上的地址char devpath[16]; //用于传递消息的ID字符串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; //事务转换HUB的设备端口unsigned int toggle[2];//每个端点用一个bit表示,[0]:IN,[1]:OUTstruct usb_device *parent;//USB设备的父节点均为hub,根节点没有父结点struct usb_bus *bus; //USB总线,USB设备所在的总线struct usb_host_endpoint ep0;//端点0,默认的控制端点struct device dev;//通用设备接口struct usb_device_descriptor descriptor;//USB设备描述符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;//USB HUB祖先数u8 devaddr;unsigned can_submit:1; //可以被提交的URBunsigned persist_enabled:1;//该USB设备使能USB_PERSISTunsigned have_langid:1;//tring_langid是否有效unsigned authorized:1;//权限unsigned authenticated:1;//通过鉴权unsigned wusb:1;//无线USB设备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 */ //下面是设备的固有属性,包括产品ID,生产字符串,生产序列号等等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;//如果是无线设备,则为设备连接WUSB专门数据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;unsigned use_generic_driver:1;};
8.1.2 总线物理拓扑结构
USB系统中主机和设备采用星形连接方式
**************USB物理总线的拓扑***************
HUB是特殊的USB设备,它是一组USB连接点,主机中有一个被嵌入的HUB叫根HUB,主机通过HUB提供多个连接点。为防止出现环状,连接点采用星形连接体现层次性。
8.1.3 USB设备、配置、接口、端点---四个逻辑层次
1.USB设备都提供不同级别配置信息,包含若干配置,不同配置表现不同组合
2.每个配置由多个接口组成;
3.接口由多端点组成,每个接口代表一个基本功能,是USB设备驱动程序控制的对象
4.复杂的USB设备具有多个接口。
5.端点是USB通信的最基本形式。
6.对主机来说,一个USB设备就是一组端点集合,主机只有通过端点才能和设备进行通信,以使用设备的功能
7.USB系统中每个端点都有独一无二的地址,地址由设备地址和端点号指定。
8.端点属性:传输方式,总线访问频率,带宽,端点号和数据包的最大容量
9.单个USB端点智能在一个方向承载数据(主机->设备即输出端点,设备->主机即输入端点)。短单0位控制端点,用于初始化设备参数
10.设备连接到USB上并上电,端点0就可被访问,端点1,1等等一般做数据端,存放书籍和设备间通信的数据
***********************USB设备,配置,接口,和端点********************************
**设备通常有一个或多个配置
**配置通常有一个或多个接口
**接口通常有一个或多个设置
**接口有0或多个端点
1.设备描述符:设备通用信息(供应商ID,产品ID,修订ID,支持的设备类,子类和适用的协议,以及默认端点的最大包大小等)数据结构
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength; //描述符长度
__u8 bDescriptorType; //描述符类型编号
__le16 bcdUSB; //USB版本号
__u8 bDeviceClass; //USB分配的设备类code
__u8 bDeviceSubClass;//USB分配的设备子类code
__u8 bDeviceProtocol;//USB分配的协议
__u8 bMaxPacketSize0;//endpoint0最大包大小
__le16 idVendor;//厂商编号
__le16 idProduct; //产品编号
__le16 bcdDevice; //设备出厂编号
__u8 iManufacturer;//描述厂商字符串的索引
__u8 iProduct;//描述产品字符串的索引
__u8 iSerialNumber; //描述设备索引号字符串的索引
__u8 bNumConfigurations;//可能的配置数量
} __attribute__ ((packed));
2.配置描述符
包括接口数、支持的挂起和恢复能力以及功率要求。U
数据结构 usb_descriptor
/*
* USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
* descriptor type is different. Highspeed-capable devices can look
* different depending on what speed they're currently running. Only
* devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
* descriptors.
*/
struct usb_config_descriptor {
__u8 bLength; //长度
__u8 bDescriptorType;//描述符类型编号
__le16 wTotalLength;//配置所返回的所有数据的大小
__u8 bNumInterfaces;//配置所支持的接口数
__u8 bConfigurationValue;//Set_Configuration命令需要的参数值
__u8 iConfiguration;//描述该配置字符串的索引值
__u8 bmAttributes;//供电模式的选择
__u8 bMaxPower;//设备从总线提取的最大电流
} __attribute__ ((packed));
3.接口描述符
包括:接口类、子类和适用的协议
接口备用配置的数目和端点数目。
USB接口描述符在内核中定义为usb_interface ,usb_interface_descriptor
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber; //接口编号
__u8 bAlternateSetting;//备用接口的描述符编号
__u8 bNumEndpoints;//该接口使用的端点数,不包括端点0
__u8 bInterfaceClass; //接口类型
__u8 bInterfaceSubClass;//接口子类型
__u8 bInterfaceProtocol;//接口所遵循的协议
__u8 iInterface; //描述该接口的字符串索引值
} __attribute__ ((packed));
4.端点描述符
:端点地址、方向、类型、支持的最大包大小。
如果端点为中断类型,则端点描述符还包括轮询频率。
内核中定义为usb_host_endpoint usb_endpoint_descriptor
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;//端点地址:0--3是端点号,第7位是方向(0-out,1-in)端点属性:bit(0:1)的值为00表示
控制,01表示同步02表示批量,03表示中断
__u8 bmAttributes;
__le16 wMaxPacketSize; //本端点接收或发送的最大信息包大小
__u8 bInterval; //轮训数据传送端点的时间间隔
//对于批量传送的端点及控制传送的端点此域忽略
//对于同步传送的端点,此域必须为1
//对于中断传送的端点,此域值范围:1---255
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
//注意,下面两个字段仅在音频端点中使用
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
5.字符串描述符
:在其他描述符中为某些字段提供字符串索引,用来检索描述性字符串,可采用多种语言形式,
:字符串描述符可选,有些设备有,有些设备没有
:定义usb_string_descriptor 结构体,usb_string_descriptor结构体
struct usb_string_descritpor{
__u8 bLength;
__u8 bDescriptorType; //描述符类型编号
__le16 wData[1]; //UTF-16LE编码
}__attribute__((packed))
8.1.4 USB设备状态
六种状态:连接态,加电态,默认态,编址态,配置态和挂起态。关系如下图
**************************USB设备状态转化图*******************
**加电态:(外部电源或接口的集线器),外部的成为自给电源式USB设备,尽管连接时已经处于带电状态,但连接到USB接口后才被看做加电状态
**默认态:加电后在从总线接收到复位信号前不应对总线传输发生响应。只有设备接收到复位信号后,才能在默认地址变为可寻址。
**编制态:加电复位后所有USB设备都使用默认地址与主机通信。每个设备在连接或复位后由主机分配一个唯一地址,当USB设备被挂起时,它保持这个地址不变。
**配置态:正常工作前USB必须被正常配置。从设备角度看,配置包括将非0写入设备配置寄存器
配置一个设备或改变一个设备会使与这个相关接口的终端节点在所有状态与配置被设成默认值。
**挂起态:为省点,usb探测不到总线传输时自动进入中止态,中止时usb保持本身内部状态,包括地址及配置
8.1.5 USB枚举过程--主机集线器监视每个端口信号电压,当检测到新设备便开始枚举
********************USB枚举过程序列图***************
1)get_port_status()
2)clear_port_feature()
3)set_port_feature()
4)usb_reset_device()
5)get_port_status
6)check highspeed()
7)get_device_descriptor()
8)set_address()
9)get_device_descriptor()
10)get_configuration_descriptor():
11)get_device_string():主机发送get_device_string命令给设备,获取字符集描述(厂商,产品描述,型号德国)
12)answer():根据9&10应答。将设备、配置、端点描述符等反馈给主机。方便加载驱动
13)install driver(),PC主机需决定所用驱动,如已选定但未加载到内存须立即加载驱动套内存
14)set_configuration(),配置ok,进入配置态
8.1.6 USB请求块(URB)
是驱动用来描述与设备通信所用的基本载体和核心数据结构,与网络驱动sk_buff类似,是主机和设备间传输数据的封装定义如下
struct urb {/* private: usb core and host controller only fields in the urb */struct kref kref; /* reference count of the URB */int unlinked; /* unlink error code */void *hcpriv; /* private data for host controller */atomic_t use_count; /* concurrent submissions counter */atomic_t reject; /* submissions will fail *//* public: documented fields in the urb that can be used by drivers */struct list_head urb_list; /* list head for use by the urb's* current owner */struct list_head anchor_list; /* the URB may be anchored */struct usb_anchor *anchor;struct usb_device *dev; /* (in) pointer to associated device */struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */unsigned int pipe; /* (in) pipe information */unsigned int stream_id; /* (in) stream ID */int status; /* (return) non-ISO status */unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/void *transfer_buffer; /* (in) associated data buffer */dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */struct scatterlist *sg; /* (in) scatter gather buffer list */int num_mapped_sgs; /* (internal) mapped sg entries */int num_sgs; /* (in) number of entries in the sg list */u32 transfer_buffer_length; /* (in) data buffer length */u32 actual_length; /* (return) actual transfer length */unsigned char *setup_packet; /* (in) setup packet (control only) */dma_addr_t setup_dma; /* (in) dma addr for setup_packet */int start_frame; /* (modify) start frame (ISO) */int number_of_packets; /* (in) number of ISO packets */int interval; /* (modify) transfer interval* (INT/ISO) */int error_count; /* (return) number of ISO errors */void *context; /* (in) context for completion */usb_complete_t complete; /* (in) completion routine */struct usb_iso_packet_descriptor iso_frame_desc[];/* (in) ISO ONLY */};
1.URB创建函数
2.初始化URB函数:1)对于中断URB,初始化函数为 static inline void usb_fill_int_urb(0
2)对于控制URB,初始化函数为 static inline void usb_fill_control_urb()
3)对于批量URB,初始化函数为 static inline void usb_fill_int_urb()
3.释放URB usb_free_urb();
4.提交URB usb_submit_urb();
8.2 USB主机驱动:
主机功能统一系统可靠性和可移植性,定出三种标准,USB2.0(EHCI),UHCI,OHCI
8.2.1 USB主机驱动结构和功能
1.嵌入式采用OHCI
2.子系统核心模块为usb core模块,为usb驱动提供一个用于访问和控制usb硬件的统一接口。
3.应用发送的urb经usb设备驱动和usb core到达主机控制器(HC),主机控制器解析URB将数据发往指定USB设备
******************USB驱动结构*********************
4.主机控制器驱动完成的工作
**解析维护URB,根据不同端点分类缓存URB
**负责不同USB传输类型的调度工作
**负责usb数据的实际传输工作
**实现虚拟根HUB的功能
8.2.2 主机控制器驱动:
1.数据结构 usb_hcd ,描述主机控制器的硬件信息,状态和操作数。
2.路径 include/linux/usb/hcd.h
struct usb_hcd {/** housekeeping*/struct usb_bus self; /* hcd is-a bus */struct kref kref; /* 索引计数器 */const char *product_desc; /* 产品或厂商字符串 */int speed; /* Speed for this roothub.* May be different from* hcd->driver->flags & HCD_MASK*/char irq_descr[24]; /* 驱动+总线 # */struct timer_list rh_timer; /* drives root-hub polling */struct urb *status_urb; /* 当前URB状态 */#ifdef CONFIG_PMstruct work_struct wakeup_work; /* 具备远程唤醒 */#endifstruct work_struct died_work; /* 当设备死亡 *//** hardware info/state*/const struct hc_driver *driver; /*控制器驱动使用的回调函数*//** OTG and some Host controllers need software interaction with phys;* other external phys should be software-transparent*/struct usb_phy *usb_phy;struct usb_phy_roothub *phy_roothub;/* Flags that need to be manipulated atomically because they can* change while the host controller is running. Always use* set_bit() or clear_bit() to change their values.*/unsigned long flags;#define HCD_FLAG_HW_ACCESSIBLE 0 /* at full power */#define HCD_FLAG_POLL_RH 2 /* poll for rh status? */#define HCD_FLAG_POLL_PENDING 3 /* status has changed? */#define HCD_FLAG_WAKEUP_PENDING 4 /* root hub is resuming? */#define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */#define HCD_FLAG_DEAD 6 /* controller has died? */#define HCD_FLAG_INTF_AUTHORIZED 7 /* authorize interfaces? *//* The flags can be tested using these macros; they are likely to* be slightly faster than test_bit().*/#define HCD_HW_ACCESSIBLE(hcd) ((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE))#define HCD_POLL_RH(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_RH))#define HCD_POLL_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING))#define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))#define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))#define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD))/** Specifies if interfaces are authorized by default* or they require explicit user space authorization; this bit is* settable through /sys/class/usb_host/X/interface_authorized_default*/#define HCD_INTF_AUTHORIZED(hcd) \((hcd)->flags & (1U << HCD_FLAG_INTF_AUTHORIZED))/** Specifies if devices are authorized by default* or they require explicit user space authorization; this bit is* settable through /sys/class/usb_host/X/authorized_default*/enum usb_dev_authorize_policy dev_policy;/* Flags that get set only during HCD registration or removal. */unsigned rh_registered:1;/* is root hub registered? */unsigned rh_pollable:1; /* may we poll the root hub? */unsigned msix_enabled:1; /* driver has MSI-X enabled? */unsigned msi_enabled:1; /* driver has MSI enabled? *//** do not manage the PHY state in the HCD core, instead let the driver* handle this (for example if the PHY can only be turned on after a* specific event)*/unsigned skip_phy_initialization:1;/* The next flag is a stopgap, to be removed when all the HCDs* support the new root-hub polling mechanism. */unsigned uses_new_polling:1;unsigned wireless:1; /* Wireless USB HCD */unsigned has_tt:1; /* Integrated TT in root hub */unsigned amd_resume_bug:1; /* AMD remote wakeup quirk */unsigned can_do_streams:1; /* HC supports streams */unsigned tpl_support:1; /* OTG & EH TPL support */unsigned cant_recv_wakeups:1;/* wakeup requests from downstream aren't received */unsigned int irq; /* 控制器的中断请求号 */void __iomem *regs; /* device memory/io */resource_size_t rsrc_start; /* memory/io 起始地址 */resource_size_t rsrc_len; /* memory/io 资源长度*/unsigned power_budget; /* in mA, 0 = no limit */struct giveback_urb_bh high_prio_bh;struct giveback_urb_bh low_prio_bh;/* bandwidth_mutex should be taken before adding or removing* any new bus bandwidth constraints:* 1. Before adding a configuration for a new device.* 2. Before removing the configuration to put the device into* the addressed state.* 3. Before selecting a different configuration.* 4. Before selecting an alternate interface setting.** bandwidth_mutex should be dropped after a successful control message* to the device, or resetting the bandwidth after a failed attempt.*/struct mutex *address0_mutex;struct mutex *bandwidth_mutex;struct usb_hcd *shared_hcd;struct usb_hcd *primary_hcd;#define HCD_BUFFER_POOLS 4struct dma_pool *pool[HCD_BUFFER_POOLS];int state;# define __ACTIVE 0x01# define __SUSPEND 0x04# define __TRANSIENT 0x80# define HC_STATE_HALT 0# define HC_STATE_RUNNING (__ACTIVE)# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)# define HC_STATE_SUSPENDED (__SUSPEND)#define HC_IS_RUNNING(state) ((state) & __ACTIVE)#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)/* memory pool for HCs having local memory, or %NULL */struct gen_pool *localmem_pool;/* more shared queuing code would be good; it should support* smarter scheduling, handle transaction translators, etc;* input size of periodic table to an interrupt scheduler.* (ohci 32, uhci 1024, ehci 256/512/1024).*//** 主机控制器私有数据存在结构体末端.*/unsigned long hcd_priv[]__attribute__ ((aligned(sizeof(s64))));};
**内核使用usb_creat_hcd创建HCD
**内核使用usb_add_hcd和usb_remove_hcd增加和溢出hcd
8.2.3 OHCI主机控制器驱动
OHCI HCD驱动属于主机驱动HCD的实例,该结构体中指定与主机控制器通信的IO内存、驻村、主机控制器的队列信息和队列数据管理、驱动状态信息和ID等
struct ohci_hcd {
}
1.主机驱动安装系统后,系统自动识别OHCI主机驱动
2.识别后,自动调用探针函数
3.探针函数自动调用usb_create_hcd()函数
4.usb_create_hcd()创建主机控制器驱动实例
5.结构体ohci_s3c2410_hc_driver定义主机控制器驱动
6.当s3c2410_start_hc被调用,平台信息被传递。执行主机驱动的start时,自动执行ohci_s3c2410_start()
7.以上完成以后主机就运行起来了。注销过程和注册过程类似执行ohci_hcd_s3c2410_drv_remove(),在该函数中移除主机控制器实例,执行s3c2410_stop_hc(),释放资源
8.3 USB设备驱动
分类:音频设备类、通信设备类、HID设备类、显示设备类、海量设备类、电源设备类
打印设备类、集线器设备类。
USB骨架提供最基础驱动
8.3.1 USB骨架程序分析
路径:driver/usb/usb-skeleton.c
1.结构体
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,};
2.文件操作结构体与设备初始化
static const struct file_operations skel_fops = {.owner = THIS_MODULE,.read = skel_read,.write = skel_write,.open = skel_open,.release = skel_release,.flush = skel_flush,.llseek = noop_llseek,};/** usb class driver info in order to get a minor number from the usb core,* and to have the device registered with the driver core*/static struct usb_class_driver skel_class = {.name = "skel%d",.fops = &skel_fops,.minor_base = USB_SKEL_MINOR_BASE,};
name采用%d通配符表示十进制整数,当新的usb-skel类型的设备被接入usb总线后,会按照子设备编号自动为该设备设置设备名称。fops是设备的文件操作结构体变量
3.USB骨架程序模块的注册和注销
insmode skeleton.ko ==usb_skel_init()被调用,在该函数中调用注册usb_register()
remode skeleton.ko ==usb_skel_exit()被调用,usb_deregister()被调用
4.USB骨架驱动所支持的设备
数组skel_table[]中指定驱动所支持的设备VENDOR_ID和PRODUCT_ID,类似的设备驱动工作可以通过在该数组后添加该涉笔的NEW_VENDOR_ID和NEW_PRODUCT_ID方式添加
/* Define these values to match your devices */
#define USB_SKEL_VENDOR_ID 0xfff0
#define USB_SKEL_PRODUCT_ID 0xfff0
/* table of devices that work with this driver */
static const struct usb_device_id skel_table[] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, skel_table);
5.USB股价驱动探测函数
设备插入或安装后,USB核心认为该驱动应该进行处理时,探测函数被调用,他测函数检查传递给他的设备信息,确定驱动是否支持该设备
static int skel_probe()
6.USB骨架驱动断开函数
某种原因不在控制该设备,断开函数skel_disconnect()被调用.
8.3.2 USB 驱动移植时的时钟设置
时钟不正确,会导致超时,检查芯片的USB时钟控制,在S3C2440A内需要PLL产生48MHz的时钟给USB,UCLK知道PLL被配置才可以提供
Upll = (m * Fin)/(p*2s次方)
M = MDIV+8
p = PDIV +2
s = SDIV
修改mach-mini2440.c文件添加代码
*********************USB时钟函数的添加*****************************
8.4 USB鼠标键盘驱动
USB键鼠驱动已经存在只需编译选上即可源文件为driver/hid/usbhid/usbmouse.c driver/hid/usbkbd.c
8.4.1 USB鼠标驱动:
鼠标输入HID类型,其数据传输采用中断URB,鼠标端点类型为in,驱动主要为探针函数和中断函数
static void usb_mouse_irq(struct urb *urb){ //urb中的context用于为usb驱动保存数据struct usb_mouse *mouse = urb->context;signed char *data = mouse->data; //mouse->data指向的内存区域保存鼠标的按键和移动坐标信息struct input_dev *dev = mouse->dev;int status;switch (urb->status) {//status:0表示成功case 0: /* success */break;case -ECONNRESET: /* unlink */表示urb被urb_unlink_urb函数unlinkcase -ENOENT: //表示urb被usb_kill_urb函数销毁,usb_kill_urb表示彻底结束urb生命周期unlink则是停止urb,这个函数不等待urb完全终止就返回给回调函数。//这在运行中断处理程序时或等待自旋锁时很有用,这两种情况都不能睡眠,而等待一个urb完全停止很可能会出现睡眠的情况。case -ESHUTDOWN:return;/* -EPIPE: should clear the halt */default: /* error */goto resubmit;}0字节:bit0 左,1:右,2:中,3:SIDE,4:EXTRA1字节:水平移动2字节:垂直移动3字节:REL_WHEEL位移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);//系统周期性获取鼠标事件信息,因此在URB回调函数末尾再次提交URB请求块,这样又会调用新的回调函数,不断循环。在回调函数中提交URB只能是GFP_ATOMIC优先级,因为URB回调函数运行于中断上下文中禁止导致睡眠的行为。//在提交URB过程中可能会需要申请内存、保持信号量,这些操作或许会导致USB core睡眠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_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;}
8.4.2 USB键盘驱动代码分析
通过usb_fill_init_urb()调用usb_kbd_irq()来提交键盘按下信息,也使用usb_fill_control_urb()调用usb_kbd_led()控制键盘灯
8.4.3 内核添加USB键鼠驱动
1.需要添加对USB的支持,对HID接口的支持,对OHCI HCD驱动的支持
1)内核配置对HID接口支持
2)设备驱动对USB支持中选择配置对OHCI HCD的支持,鼠标套件还需要LCD屏幕
8.5 U盘驱动
代码 drivers/usb/storage 内核
1.只需要配置支持storage和
2.支持相关的文件系统对U盘中内容的支持,
3.添加对字符编码的支持
8.5.1 移植测试
1.插入板子看能否正确识别信息
2.cat /proc/partitions 查看分区信息
3.挂载U盘。 mkdir /mnt/usb
df -h
8.6 小结
第八章 USB 设备驱动移植相关推荐
- 嵌入式linux usb wifi驱动移植
文档名称:嵌入式linux usb wifi驱动移植 版本历史 版本号 时间 内容 v1.0b001 2012-6-18 初始版本,介绍在嵌入式 ...
- STM32MP157驱动开发——USB设备驱动
STM32MP157驱动开发--USB设备驱动 一.简介 1.电气属性 2.USB OTG 3.STM32MP1 USB 接口简介 4.Type-C 电气属性 二.USB HOST 驱动开发 1.US ...
- Linux USB设备驱动程序设计 和 USB下载线驱动设计
Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...
- usb linux 内核,Linux内核USB驱动架构:USB设备驱动架构.pdf
USB 设备驱动架构 LK 版本:2.6.35.3 2013 年1 月14 日 任务目标: 分析整理插入一个USB 设备的处理过程. USB 设备.配置.接口.设置以及端点的五者关系图: 一个 ...
- usb设备驱动之uvc设备
usb设备驱动之uvc设备 声明:涉及相关内容包括v4l2框架/drivers/media/v4l2-core/,usb设备控制器驱动/drivers/usb/dwc3/,usb composite驱 ...
- 浅谈Linux USB设备驱动
1.USB基础介绍 1-1.USB硬件接口介绍 USB接口在硬件上总共有四根线组成VCC.D+.D-.GND,通过计算D+和D-的差值来确定数据.USB设备在传输速率上可以分为低速(1.5Mbps). ...
- WDF开发USB设备驱动教程(2)
PDF全文下载:http://bbs.driverdevelop.com/read.php?tid-120461.html 3.2 获取描述符 上一小节认识了USB 的描述符后,这一节就来讲如何从 U ...
- WDF开发USB设备驱动教程(1)
PDF下载地址(1.2版):链接地址 CY001开发板讨论帖:链接地址 注:本文档新版本已出,请在博客中查找,或下载PDF全文文档. 链接地址WDF开发USB设备驱动教程 by 张佩 文档说明 作者写 ...
- Linux设备驱动之usb设备驱动详解
原文地址:http://blog.csdn.net/chenjin_zhong/article/details/6329316 1.Linux usb设备驱动框架 USB是通用串行总线的总称,Linu ...
最新文章
- ide 波浪线_零基础学习Python_小波浪
- Docker进阶-资源管理Swarm+Portainer
- 彻底理解链接器:二,符号决议
- 让电流检测更精确的AMR技术
- linux设置新硬盘权限,Linux 下挂载新硬盘以及更改为普通权限
- python beautifulsoup4_Python之Beautiful Soup 4使用实例
- java快速排序代码6_分分钟掌握快速排序(Java / Scala 实现)
- 在图片上加入删除按钮
- 一个珊瑚虫倒下了,千万个珊瑚虫站起来!欢呼吧QQ****下载,不断更新
- html磁贴模板,文本磁贴模板(列表文件夹)(HTML)
- matlab模拟嫦娥奔月,【文章】仿真动画软件设计作品--嫦娥奔月
- 【前端】菜单栏设计(html、css)
- 云和恩墨2022届春季校招正式启动!
- 大数据产品测试----统计类产品测试项目总结
- WEPWPA Cracking on BT5/MAC [转]
- Jarvis OJ平台basic部分wirteup
- 穿越火线活动网页显示Java_Java设计模式-装饰模式:《穿越火线》RMB 玩家的快乐~...
- Java怎么搞安卓日历提醒,Android日历有闹钟提醒功能记事功能等
- 程序员要想突破圈层,请放弃技术优势!
- php smtp 抄送,php带抄送和密件抄送的邮件发送方法_PHP教程
热门文章
- ERROR 1630 (42000): FUNCTION a.avg does not exist. Check the ‘Function Name Parsing and Resolution‘
- Vue 登录密码验证 MD5加密
- 【华人学者风采】汪建军 华北电力大学
- (P20)miniftpd项目实战20:ABOR的实现和NOOP命令和QUIT命令
- 使用PWM控制来实现电压的变化控制
- 使用Tensorflow实现多GPU并行训练
- 声称代码已开源却迟迟没更新,网友等了好几个月,最终一怒之下把作者挂网上
- UGUI - 中设置UISprite图片灰显方法
- 用python分析NBA联盟球员信息,才知道这些秘密!
- 雷达回波脉冲压缩python代码