最常用的设备却不懂它的工作原理,岂不是最大的不尊敬,感谢USB为我们带来的便利;
今天也要继续坚定的前行的…
文章目录
- [0x100] 特征与概念
- [0x110] USB接口特征
- [0x120] USB驱动类型
- [0x130] USB设备基本组成
- [0x131] 端点[struct usb_host_endpoint]
- [0x132] 接口[struct usb_host_interface]
- [0x133] 配置规则[struct usb_host_config]
- [0x140] USB request Block [struct urb]
- [0x200]相关数据结构
- [0x210] USB 端点描述结构
- [0x220] USB 接口描述结构
- [0x230] USB 接口配置结构
- [0x240] USB urb结构
- [0x250]用户空间USB设备列表
- [0x260]USB驱动数据结构
- [0x270]USB设备 字符设备类结构
- [0x300]USB request Block
- [0x400] USB驱动程序
- [0x410] 填充USB设备列表[struct usb_device_id]
- [0x420] 注册与注销驱动程序到核心
- [0x430] 新插入设备获取读写端点
- [0x440] USB接口 获取与保存 USB端点数据
- [0x450] USB接口设备注册与注销
- [0x460] 分配urb端口
- [0x500] 非urb驱动程序
[0x100] 特征与概念
[0x110] USB接口特征
- 主从树形点对点结构,主机控制器轮询连接,从机控制器回应数据;
- 四线结构双线传输,地线、电源、接收信号线、发送信号线;
- 非结构类型的通讯方式,屏蔽了下层的硬件设备,以串行数据流的方式来传输数据;
- 支持热插拔功能;
[0x120] USB驱动类型
- USB设备驱动 :宿主机控制硬件作为USB设备与主机通信;
- USB器件驱动 :USB设备如何控制连接到计算机,之前只能传送数据,现在可以传送指令,由器件驱动去执行;
[0x130] USB设备基本组成
[0x131] 端点[struct usb_host_endpoint]
- 定义 :单方向传输数据的管道类通道,共有四种类型;
- 控制端点 :配置新入设备初始化,获取设备状态信息,向设备发送命令;
- 中断端点 :用于接收少量高频率的数据,如 键盘、鼠标等等;
- 批量端点 :不可靠的异步大量数据传输,;
- 实时端点 :可靠恒定速率大量数据传输,用于高实时的数据传输;
[0x132] 接口[struct usb_host_interface]
- 定义 :同逻辑类型USB端口的绑定抽象
- 不同的接口执行不同的单一逻辑职能,不同的带宽
- 每个接口可以拥有多个可选配置
- 接口的计数从0开始计数;
- 实际驱动程序中要使用的结构 struct usb_device 而不是结构结构体本身;
[0x133] 配置规则[struct usb_host_config]
- USB 设备捆绑多个接口,接口捆绑多个配置
- 一个接口只可以激活一个配置,设备可以绑定多个接口,一次有多个配置;
- 需要绑定到接口使用,不能单独使用
[0x140] USB request Block [struct urb]
- 定义:异步向指定设备的指定端口发送/接收数据;
- 每个端口可以接收多个urb的数据收发,也可以多个端口共享一个urb;
- 一种端口间的异步通讯机制;
[0x200]相关数据结构
[0x210] USB 端点描述结构
#include <linux/usb.h>
*/struct usb_host_endpoint { /*描述了USB端点组成信息*/
struct usb_endpoint_descriptor /*USB标准数据结构*/
{
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress; /*8位 表示端点的USB地址,包括了方向和位置标识*/
__u8 bmAttributes; /*8位 表示端点的类型属性*/
__le16 wMaxPacketSize; /*16位 数据块限定大小*/
__u8 bInterval; /*与中断类型端点关联使用,端点的请求中断的间隔*/
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed))desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct list_head urb_list; /*URB队列头*/
void *hcpriv; /*DMA队列头*/
struct ep_device *ep_dev; /*设备文件系统信息*/
/*描述接口的作用 没啥用*/
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled; /*端点URB 激活提交*/
};
/*端点的类型属性*/
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /*掩码bmAttributes用来获取当前位*/
#define USB_ENDPOINT_XFER_CONTROL 0 /*控制端点*/
#define USB_ENDPOINT_XFER_ISOC 1 /*实时端点*/
#define USB_ENDPOINT_XFER_BULK 2 /*批量端点*/
#define USB_ENDPOINT_XFER_INT 3 /*中断端点*/
[0x220] USB 接口描述结构
#include <linux/usb.h>
struct usb_interface {
struct usb_host_interface *altsetting; /*接口结构数组 用于记录可选的接口信息数组 无序*/
struct usb_host_interface *cur_altsetting; /* 当前接口激活的可选设置 */
unsigned num_altsetting; /* 可选设置的数量 */
struct usb_interface_assoc_descriptor *intf_assoc; /*组接口配置绑定*/
/*驱动程序包含了USB设备的主设备号,该选项表示为接口的次设备号 */
int minor;
enum usb_interface_condition condition; /* 接口绑定状态*/
/*操作配置功能参数位*/
unsigned sysfs_files_created:1; /* 文件系统已存在该设备文件*/
unsigned ep_devs_created:1; /* 终端设备已存在*/
unsigned unregistering:1; /* 进程未注册*/
unsigned needs_remote_wakeup:1; /* 驱动远程唤醒*/
unsigned needs_altsetting0:1; /* 开启抑制altsetting 0 */
unsigned needs_binding:1; /* 需要延迟绑定*/
unsigned reset_running:1;
unsigned resetting_device:1; /*重置后带宽重分配*/
struct device dev;
struct device *usb_dev;
atomic_t pm_usage_cnt; /*引用变量 用于确定接口是否正在使用*/
struct work_struct reset_ws; /*工作队列结构*/
};
[0x230] USB 接口配置结构
#include <linux/usb.h>
struct usb_host_config {
/*配置参数信息*/
struct usb_config_descriptor desc;
char *string;
/*接口描述绑定数组 无序*/
struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];
/*接口参数信息绑定数组 无序*/
struct usb_interface *interface[USB_MAXINTERFACES];
struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
unsigned char *extra; /* Extra descriptors */
int extralen;
};
[0x240] USB urb结构
#include <linux/usb.h>
struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
void *hcpriv; /* private data for host controller */
atomic_t use_count; /* concurrent submissions counter */
atomic_t reject; /* submissions will fail */
int unlinked; /* unlink error code */
/* 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; /* 需要绑定Urb的USB设备结构,必须由对应的USB驱动初始化 */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* 需要绑定Urb的USB端点属性,决定了传输数据的方向 */
unsigned int stream_id; /* (in) stream ID */
int status; /* 实时端口状态 */
unsigned int transfer_flags; /* urb端口传输类型标识*/
void *transfer_buffer; /* 普通数据缓冲区中转 必须使用kmalloc 建立空间*/
dma_addr_t transfer_dma; /* DMA作为数据缓冲区中转 */
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; /* 传输数据缓冲区大小*/
u32 actual_length; /* (return) actual transfer length */
unsigned char *setup_packet; /* 设置数据包指针,优先于普通缓冲区中数据传送到目标,只允许控制类型端口使用 */
dma_addr_t setup_dma; /* 设置数据包指针,优先于DMA缓冲区中数据传送到目标,只允许控制类型端口使用 */
int start_frame; /* 仅实时类型数据包使用,起始帧数量 */
int number_of_packets; /* (in) number of ISO packets */
int interval; /* urb发送到USB核心之前设置,处理终端间隔 仅对中断类型端口与实时端口有效 */
int error_count; /* USB核心设置,报告实时端口传输结束后的实时传输错误数量 */
void *context; /* 终结传输无数据小包位置 */
usb_complete_t complete; /* 终结函数指针 void (*usb_complete_t)(struct urb *);控制权返回驱动*/
struct usb_iso_packet_descriptor /*可以一次定义多个实时传输 */
{
unsigned int offset;
unsigned int length; /* expected length */
unsigned int actual_length;
int status;
};
};
[0x250]用户空间USB设备列表
#include <linux/usb.h>
struct usb_device_id {
/*用来匹配识别USB设备方式 不直接设置 #include linux/mod_devicetable.h USB_DEVICE_*()*/
__u16 match_flags;
__u16 idVendor; /*设备厂商编号*/
__u16 idProduct; /*产品型号*/
__u16 bcdDevice_lo; /*设备特征版本编号最小值*/
__u16 bcdDevice_hi; /*设备特征版本编号最大值*/
/* Used for device class matches */
__u8 bDeviceClass; /*设备主类编号*/
__u8 bDeviceSubClass; /*绑定主类的设备次类编号*/
__u8 bDeviceProtocol; /*绑定主类的设备协议编号*/
/* Used for interface class matches */
__u8 bInterfaceClass; /*接口主类编号*/
__u8 bInterfaceSubClass; /*绑定主类的接口次类编号*/
__u8 bInterfaceProtocol; /*绑定主类的接口协议编号*/
/* not matched against */
kernel_ulong_t driver_info; /*驱动描述或者设备描述标识*/
};
[0x260]USB驱动数据结构
#include <linux/usb.h>
struct usb_driver {
/*驱动程序标识名称,应该与模块名称一致*/
const char *name;
/*探测函数指针 可选配置*/
int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);
/*设备断开连接或者驱动程序没有加载的清理工作*/
void (*disconnect) (struct usb_interface *intf);
/*USBfs 配置函数,用于驱动程序与用户空间的通信*/
int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,void *buf);
/*USB核心设备抑制、唤醒、重置替代唤醒 处理函数回调*/
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf);
/*重置检测URB激活状态*/
int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf);
/*USB外设列表*/
const struct usb_device_id *id_table;
struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int soft_unbind:1;
};
[0x270]USB设备 字符设备类结构
struct usb_class_driver {
char *name; //sysfs 中设备路径名
char *(*devnode)(struct device *dev, umode_t *mode); //为设备创建devfs文件处理函数
const struct file_operations *fops; //设备文件操作函数集
int minor_base; //次设备号起始值
};
[0x300]USB request Block
[0x310] urb生命周期
[0x320] urb端点属性
[0x321] urb端口类型与传输方向标识[unsigned int pipe]
功能 | 操作位 | 描述 |
---|---|---|
数据方向 | 【bit 7】 | 0 = 主机->设备 1 = 设备到主机 |
设备编号 | 【bits 08-14】 | 位地址指导来自于uhci-hcd控制器 |
端点编号 | 【bits 15-18】 | 位地址指导来自于uhci-hcd控制器 |
端点类型 | 【bits 30-31】 | (00 = 实时, 01 = 中断,10 = 控制命令, 11 = 异步批量) |
#include <linux/usb.h>
#define PIPE_ISOCHRONOUS 0 /*实时端口类型*/
#define PIPE_INTERRUPT 1 /*中断端口类型*/
#define PIPE_CONTROL 2 /*控制端口类型*/
#define PIPE_BULK 3 /*异步批量端口*/
#define USB_DIR_OUT 0 /* 主机向USB外设发送数据标识 */
#define USB_DIR_IN 0x80 /* 外设向USB宿主机发送数据标识 */
#define usb_pipein(pipe) ((pipe) & USB_DIR_IN) /*设备向主机送数据*/
#define usb_pipeout(pipe) (!usb_pipein(pipe)) /*主机向外设送数据*/
#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) /*获取USB设备编号 bit08-bit14*/
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) /*获取USB端口编号 bit15-bit18*/
#define usb_pipetype(pipe) (((pipe) >> 30) & 3) /*端口类型决定传输数据类型*/
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS) /*设置 实时类型端口*/
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT) /*设置 中断类型端口*/
#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL) /*设置 控制类型端口*/
#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK) /*设置 批量类型端口*/
/* Create various pipes... */
#define usb_sndctrlpipe(usb_device, endpoint) \ /*设置 控制类型 发送端口*/
((PIPE_CONTROL << 30) | __create_pipe(usb_device, endpoint))
#define usb_rcvctrlpipe(usb_device, endpoint) \ /*设置 控制类型 接收端口*/
((PIPE_CONTROL << 30) | __create_pipe(usb_device, endpoint) | USB_DIR_IN)
#define usb_sndisocpipe(usb_device, endpoint) \ /*设置 实时类型 发送端口*/
((PIPE_ISOCHRONOUS << 30) | __create_pipe(usb_device, endpoint))
#define usb_rcvisocpipe(usb_device, endpoint) \ /*设置 实时类型 接收端口*/
((PIPE_ISOCHRONOUS << 30) | __create_pipe(usb_device, endpoint) | USB_DIR_IN)
#define usb_sndbulkpipe(usb_device, endpoint) \ /*设置 批量类型 发送端口*/
((PIPE_BULK << 30) | __create_pipe(usb_device, endpoint))
#define usb_rcvbulkpipe(usb_device, endpoint) \ /*设置 批量类型 接收端口*/
((PIPE_BULK << 30) | __create_pipe(usb_device, endpoint) | USB_DIR_IN)
#define usb_sndintpipe(usb_device, endpoint) \ /*设置 中断类型 发送端口*/
((PIPE_INTERRUPT << 30) | __create_pipe(usb_device, endpoint))
#define usb_rcvintpipe(usb_device, endpoint) \ /*设置 中断类型 接收端口*/
((PIPE_INTERRUPT << 30) | __create_pipe(usb_device, endpoint) | USB_DIR_IN)
/*核心函数实现*/
static inline unsigned int __create_pipe(struct usb_device *dev,unsigned int endpoint)
{
return (dev->devnum << 8) | (endpoint << 15);
}
[0x322] urb端口传输类型标识[unsigned int transfer_flags]
#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */
#define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */
#define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */
#define URB_NO_FSBR 0x0020 /* UHCI-specific */
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interruptneeded */
#define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */
/* The following flags are used internally by usbcore and HCDs */
#define URB_DIR_IN 0x0200 /* Transfer from device to host */
#define URB_DIR_OUT 0
#define URB_DIR_MASK URB_DIR_IN
功能 | 描述 |
---|---|
URB_SHORT_NOT_OK | 对于外设向主机传送的短数据,将被USB核心认定为错误 |
URB_ISO_ASAP | 只有实时类型的端口 强制等待指定start_frame |
URB_NO_TRANSFER_DMA_MAP | USB核心向DMA缓冲区传输数据,即向transfer_dma而不是transfer_buffer |
URB_NO_FSBR | 主控器设置的标识位,不执行前端总线回收逻辑 |
URB_ZERO_PACKET | 主机到外设发送数据时,使用无数据小数据包结束发送 |
URB_NO_INTERRUPT | 目标设备不会产生中断,通常用于USB核心到DMA缓冲区传输数据 |
URB_FREE_BUFFER | 清空Urb端口的传输缓冲区 |
[0x330] urb函数接口
[0x331] 创建与销毁urb结构空间
Func :创建一个urb端口结构
args1:实时包计数;
args2:用于kmalloc 内存分配的类型标识,通常GFP_kernel;
retal :成功返回struct urb 地址 失败 为NULL
/*implement drivers/usb/core/urb.c*/
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;
urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
printk(KERN_ERR "alloc_urb: kmalloc failed\n");
return NULL;
}
usb_init_urb(urb);
return urb;
}
/*销毁urb结构空间*/
void usb_free_urb(struct urb *urb)
{
if (urb)
kref_put(&urb->kref, urb_destroy);
}
- 不可以手动创建struct urb,会破坏USB核心的引用计数机制;
- 如果不想创建实时类型端口,第一个参数应该为0;
[0x332] 填充不同类型的urb端口
参数 | 描述 | 需配置端口类型 |
---|---|---|
struct urb *urb | 初始化urb指针 详见[0x331]创建urb | 通用标准 |
struct usb_device *dev | USB外设结构 | 通用标准 |
unsigned int pipe | 发送方向与端口类型,详见[0x321] urb端口类型与传输方向标识 | 通用标准 |
void *transfer_buffer | 数据缓冲区,必须是kmalloc创建的位置 | 通用标准 |
int buffer_length | 数据缓冲区大小 | 通用标准 |
usb_complete_t complete_fn | urb 结束后的销毁规程函数指针 | 通用标准 |
void *context | 置零的小数据块用于结束发送 | 通用标准 |
int interval | urb允许中断间隔 | 终端端口与实时端口 |
unsigned char *setup_packet, | 发送至端点的配置数据的地址 | 控制端口 |
unsigned int transfer_flags | 传输类型标识 详见 [0x322] urb端口传输类型标识 | 实时端口 |
int number_of_packets | 实时包数量 | 实时端口 |
struct usb_iso_packet_descriptor iso_frame_desc[0] | 定义多个实时传输实例 | 实时端口 |
#include <linux/usb.h>
/*创建批量urb*/
static inline void usb_fill_int_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context,
int interval)
/*创建批量urb*/
static inline void usb_fill_bulk_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
/*创建控制urb*/
static inline void usb_fill_control_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
/*创建实时urb,抱歉没有 随便其他人做的驱动找的*/
urb->complete = urb_complete_iso; /* handler */
urb->dev = udev;
urb->context = video->front;
urb->pipe = usb_rcvisocpipe(udev, video->endpoint_addr);
urb->interval = 1;
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->number_of_packets = PK_PER_URB;
urb->transfer_buffer = mem;
urb->transfer_buffer_length = PK_PER_URB * ISO_PKT_SIZE;
for (j = 0; j < PK_PER_URB; j++) {
urb->iso_frame_desc[j].offset = ISO_PKT_SIZE * j;
urb->iso_frame_desc[j].length = ISO_PKT_SIZE;
}
[0x333] 注册urb端口
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
Func :将urb数据结构提交到USB核心注册端口设备,允许在中断上下文使用,控制权到USB核心;
args1:初始化urb指针 详见[0x331]创建urb;
args2:用于kmalloc 内存分配的类型标识,
根据不同使用环境 不同 不允许休眠=GFP_ATOMIC 块设备路径 GFP_NOIO其它都是GFP_KERNEL;
retal :正确返回0 错误错误码
[0x334]初始化与释放 urb 缓冲区
/*创建一个 DMA urb 缓冲区*/
static inline void *
usb_buffer_alloc(struct usb_device *dev, size_t size,gfp_t mem_flags, dma_addr_t *dma)
{
return usb_alloc_coherent(dev, size, mem_flags, dma);
}
/*销毁一个 DMA urb 缓冲区*/
static inline void usb_buffer_free(struct usb_device *dev, size_t size,void *addr, dma_addr_t dma)
{
return usb_free_coherent(dev, size, addr, dma);
}
[0x335] 取消urb端口
- urb端口提交成功 ,可以查看 struct urb 结构中 status 状态值,0为成功,错误则返回错误码;
- 驱动解除提交urb ;
/*断开当前USB设备*/
void usb_kill_urb(struct urb *urb)
{
might_sleep();
if (!(urb && urb->dev && urb->ep))
return;
atomic_inc(&urb->reject);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
atomic_dec(&urb->reject);
}
/*解链接 urb端口 后由驱动程序的usb_complete_t complete_fn释放 需要设置transfer_flags|=URB_ASYNC_UNLINK */
nt usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
if (!urb->dev)
return -ENODEV;
if (!urb->ep)
return -EIDRM;
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
[0x400] USB驱动程序
[0x410] 填充USB设备列表[struct usb_device_id]
/*填充厂商编号和产品编号来填充struct usb_device_id*/
#define USB_DEVICE(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
.idProduct = (prod)
/*填充厂商编号、产品编号、接口协议*/
#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
.idVendor = (vend), \
.idProduct = (prod), \
.bInterfaceProtocol = (pr)
/*填充设备主类、设备次类、设备协议*/
#define USB_DEVICE_INFO(cl, sc, pr) \
.match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
.bDeviceClass = (cl), \
.bDeviceSubClass = (sc), \
.bDeviceProtocol = (pr)
/*填充接口主类、接口次类、接口协议*/
#define USB_INTERFACE_INFO(cl, sc, pr) \
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
.bInterfaceClass = (cl), \
.bInterfaceSubClass = (sc), \
.bInterfaceProtocol = (pr)
- USB核心单线程发现设备–>检查获取设备信息–>添加到usb_device_id–>通知USB集线器
- 传递设备信息–>启动探测函数
- 匹配驱动程序–>初始化USB设备结构
[0x420] 注册与注销驱动程序到核心
- 需要在模块初始化的过程中完成,并 需要填充struct usb_driver
- 本函数会填充new_driver->drvwrap, 并在USB核心分配主设备号,来标识驱动程序;
/*注册上层宏接口*/
#define usb_register(driver) usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
/*将驱动程序注册到USB子系统中*/
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,const char *mod_name)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
/*设置为接口驱动=0 设备驱动 = 非0*/
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = (char *) new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
/*核心函数 struct device_driver*/
retval = driver_register(&new_driver->drvwrap.driver);
if (retval)
goto out;
usbfs_update_special();
retval = usb_create_newid_files(new_driver);
if (retval)
goto out_newid;
pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);
out:
return retval;
out_newid:
driver_unregister(&new_driver->drvwrap.driver);
printk(KERN_ERR "%s: error %d registering interface "
" driver %s\n",
usbcore_name, retval, new_driver->name);
goto out;
}
/*注销USB驱动程序核心函数*/
void usb_deregister(struct usb_driver *driver)
{
pr_info("%s: deregistering interface driver %s\n",
usbcore_name, driver->name);
usb_remove_newid_files(driver);
/*核心函数 struct device_driver*/
driver_unregister(&driver->drvwrap.driver);
usb_free_dynids(driver);
usbfs_update_special();
}
[0x430] 新插入设备获取读写端点
- USB核心 调用USB集线器线程 启动探测函数;
- 检查新插入的设备信息是否匹配当前的驱动程序;
- 确定新插入设备是否为 输入输出端点,并保存端点地址到USB设备结构中;
struct usb_interface_descriptor endpoint;
/*获取当前接口中的多个端口配置*/
struct usb_host_interface * iface_desc = interface->cur_altsetting;
/*获取最大端点数量遍历端点*/
for(i = 0;i < iface_desc->desc.bNumEndpoints;++i)
{
/*获取接口中端口描述*/
endpoint = &iface_desc->endpoint[i].desc;
/*当输入端口地址未指定时,查找批量IN类型的端点*/
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;
/*指定USB设备使用该端点*/
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;
}
/*当输出端口地址未指定时,查找批量OUT类型的端点*/
if(!dev->bulk_in_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;
}
[0x440] USB接口 获取与保存 USB端点数据
/*将之前获取的读写端口 USB设备结构体中数据保存到USB接口结构中*/
static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
{
dev_set_drvdata(&intf->dev, data);
}
/*获取USB接口中的数据*/
static inline void *usb_get_intfdata(struct usb_interface *intf)
{
return dev_get_drvdata(&intf->dev);
}
[0x450] USB接口设备注册与注销
- 注册成字符设备与注销
- 有了 struct usb_interface 其中的读写端口
- 还需要 struct usb_class_driver USB接口字符驱动转换结构
/*注册函数*/
int usb_register_dev(struct usb_interface *intf,struct usb_class_driver *class_driver)
{
int retval;
int minor_base = class_driver->minor_base;
int minor;
char name[20];
char *temp;
#ifdef CONFIG_USB_DYNAMIC_MINORS
minor_base = 0;
#endif
if (class_driver->fops == NULL)
return -EINVAL;
if (intf->minor >= 0)
return -EADDRINUSE;
retval = init_usb_class();
if (retval)
return retval;
dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
down_write(&minor_rwsem);
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
if (usb_minors[minor])
continue;
usb_minors[minor] = class_driver->fops;
intf->minor = minor;
break;
}
up_write(&minor_rwsem);
if (intf->minor < 0)
return -EXFULL;
/* create a usb class device for this usb interface */
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
temp = strrchr(name, '/');
if (temp && (temp[1] != '\0'))
++temp;
else
temp = name;
intf->usb_dev = device_create(usb_class->class, &intf->dev,
MKDEV(USB_MAJOR, minor), class_driver,
"%s", temp);
if (IS_ERR(intf->usb_dev)) {
down_write(&minor_rwsem);
usb_minors[minor] = NULL;
intf->minor = -1;
up_write(&minor_rwsem);
retval = PTR_ERR(intf->usb_dev);
}
return retval;
}
/*如果使用上述函数注册USB接口设备 就要用这个注销才能执行断开操作*/
void usb_deregister_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver)
{
if (intf->minor == -1)
return;
dbg ("removing %d minor", intf->minor);
down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL;
up_write(&minor_rwsem);
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
intf->usb_dev = NULL;
intf->minor = -1;
destroy_usb_class();
}
- 断开USB设备清理
static void skel_disconnect(struct usb_interface *interface)
{
struct usb_skel *dev;
int minor = interface->minor;
/*获取设备信息*/
dev = usb_get_intfdata(interface);
/*清理接口信息*/
usb_set_intfdata(interface, NULL);
/* 返还次设备编号 */
usb_deregister_dev(interface, &skel_class);
/* prevent more I/O from starting */
mutex_lock(&dev->io_mutex);
dev->interface = NULL;
mutex_unlock(&dev->io_mutex);
/*删除urb请求端口*/
usb_kill_anchored_urbs(&dev->submitted);
/* 降低引用计数 */
kref_put(&dev->kref, skel_delete);
dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
}
[0x460] 分配urb端口
- [0x331] 创建urb结构空间
- [0x334] 初始化 urb 缓冲区
- [0x332] 填充不同类型的urb端口
- [0x333] 注册urb端口
- [0x334] 释放 urb 缓冲区
[0x500] 非urb驱动程序
- 当只需要简单的发送数据时,可以使用以下函数接口;
- 不能使用在中断上下文,该函数有可能休眠;
- 创建大量数据传输端口
int
usb_bulk_msg(struct usb_device *usb_dev,
unsigned int pipe,void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
struct usb_host_endpoint *ep;
ep = usb_pipe_endpoint(usb_dev, pipe);
if (!ep || len < 0)
return -EINVAL;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT) {
pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
usb_fill_int_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL,
ep->desc.bInterval);
} else
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
return usb_start_wait_urb(urb, timeout, actual_length);
}
Func : 创建一个批量的urb指向发送目标USB设备的 usb_device;
args1 : 目标USB设备属性指针;
args2 : 设置批量发送特定端点标识
args3 : 数据缓冲区指针
args4 : 缓冲区大小
args5 : 传输后最终位置的数据指针
args6 : 等待超时时间
retval : 回值为0 如果调用成功 错误 为错误码
- 创建控制信息传输端口
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data,
__u16 size, int timeout)
{
struct usb_ctrlrequest *dr;
int ret;
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr)
return -ENOMEM;
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size);
/* dbg("usb_control_msg"); */
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
Func : 创建一个控制类型的urb指向发送目标USB设备的 usb_device;
args1 : 目标USB设备属性指针;
args2 : 设置控制信息发送特定端点标识;
args3 : 控制信息USB请求值;
args4 : 控制信息USB请求类型值;
args5 : 控制信息USB请求消息值;
args6 : 控制信息USB请求索引值;
args7 : 传输数据缓冲区;
args8 : 传输数据缓冲区大小;
args9 : 等待计时器;
retval : 如果调用成功 返回实际 传输字节数 错误 = 负数错误码;