To understand all the Linux-USB framework, you'll use these resources:
* This source code.
"make pdfdocs",
"usb.pdf" for host side
"gadget.pdf" for peripheral side
* The USB 2.0 specification (from www.usb.org).
* Chip specifications for USB controllers. host controllers (on PCs, servers, and more);
peripheral controllers (in devices with Linux firmware, like printers or cell phones);
hard-wired peripherals like Ethernet adapters.
* Specifications for other protocols implemented by USB peripheral functions.
Some are vendor-specific;
others are vendor-neutral but just standardized outside of the www.usb.org team.
Here is a list of what each subdirectory here is, and what is contained in them.
core/ - This is for the core USB host code, including the usbfs files and the hub class driver ("khubd").
host/ - This is for USB host controller drivers. This includes UHCI, OHCI, EHCI, and others that might
be used with more specialized "embedded" systems.
gadget/ - This is for USB peripheral controller drivers and the various gadget drivers which talk to them.
Individual USB driver directories. A new driver should be added to the first subdirectory in the list below that it fits into.
image/ - This is for still image drivers, like scanners or digital cameras.
input/ - This is for any driver that uses the input subsystem,like keyboard, mice, touchscreens, tablets, etc.
media/ - This is for multimedia drivers, like video cameras,radios, and any other drivers that talk to the v4l subsystem.
net/ - This is for network drivers.
serial/ - This is for USB to serial drivers.
storage/ - This is for USB mass-storage drivers.
atm/ - Automatic
mon/ - Monitor
class/ - This is for all USB device drivers that do not fit into any of the above categories, and work for a range
of USB Class specified devices.
misc/ - This is for all USB device drivers that do not fit into any of the above categories.
驱动结构:
USB 设备驱动 : USB设备和主机通讯 Gadget 驱动 :具体USB设备功能的实现,使设备表现出"网络连接"
"打印机""USB Mass Storage"的特性
USB Core : 定义一些数据结构,宏和功能函数.提供上下层的API Gadget API : Callback API 的简单包装
通过全局变量维护系统的USB信息,HotPlug控制,总线数据传输
USB 主机驱动 : 控制插入的USB设备 UDC 驱动 :控制USB设备和HOST的底层通讯,向上提供Callback API
USB控制器硬件OHCI/EHCI/UHCI <<-->> USB Bus <<-->> USB控制器硬件OHCI/EHCI/UHCI
数据结构的定义: in /kernel/include/linux/usb_ch9.h
/*
* This file holds USB constants and structures that are needed for USB
* device APIs. These are used by the USB device model, which is defined
* in chapter 9 of the USB 2.0 specification. Linux has several APIs in C
* that need these:
*
* - the master/host side Linux-USB kernel driver API;
* - the "usbfs" user space API; and
* - the Linux "gadget" slave/device/peripheral side driver API.
*
* USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
* act either as a USB master/host or as a USB slave/device. That means
* the master and slave side APIs benefit from working well together.
*
* There's also "Wireless USB", using low power short range radios for
* peripheral interconnection but otherwise building on the USB framework.
*/
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor { 设备描述符 如USB扬声器
__u8 bLength; 描述符的长度
__u8 bDescriptorType; 描述符类型的编号
__le16 bcdUSB; USB版本号
__u8 bDeviceClass; USB的设备类code
__u8 bDeviceSubClass; USB的子类code
__u8 bDeviceProtocol; USB的协议code
__u8 bMaxPacketSize0; 默认端口端口0的最大包大小
__le16 idVendor; 厂商编号
__le16 idProduct; 产品编号
__le16 bcdDevice; 设备出厂的编号
__u8 iManufacturer; 描述厂商的字符串的索引
__u8 iProduct; 描述产品的字符串的索引
__u8 iSerialNumber; 描述设备序列号的字符串的索引
__u8 bNumConfigurations; 可能的配置数量
} __attribute__ ((packed));
struct usb_config_descriptor { 多个配置描述符
__u8 bLength; 描述符的长度
__u8 bDescriptorType; 描述符类型的编号
__le16 wTotalLength; 配置 所返回的所有数据的大小
__u8 bNumInterfaces; 配置 所支持的interface数
__u8 bConfigurationValue; Set_Configuration命令需要的参数值
__u8 iConfiguration; 描述该配置的字符串的索引值
__u8 bmAttributes; 供电模式的选择
__u8 bMaxPower; 设备从总线提取的最大电流
} __attribute__ ((packed));
/* 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)
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor { 多个端口描述符
__u8 bLength; 描述符长度
__u8 bDescriptorType; 描述符的类型
__u8 bEndpointAddress; 端点号:0-3是端口点,第7位是方向(0-OUT,1-IN)
__u8 bmAttributes; 端口属性:bit[0:1] 00:控制端点 01:同步传输端点 02:批量传输端点 03:中断端点
__le16 wMaxPacketSize; 数据包的最大容量
__u8 bInterval; 轮询数据传送端点的时间间隔,即中断传送时轮询间隔,此域为1-255
批量和控制传送时,此域忽略
同步传送时,为1
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor { 字符串描述符
__u8 bLength; 描述符长度
__u8 bDescriptorType; 描述符类型
__le16 wData[1]; /* UTF-16LE encoded */
} __attribute__ ((packed));
1,USB主机驱动: OHCI: Open Host Controller Interface,None PC or SiS/ALi chip PC USB
UHCI: Universal,Used by PC USB
EHCI: Enhanced usb2.0
一,数据结构: in /kernel/drivers/usb/core/hcd.h
/*-------------------------------------------------------------------------*/
/*
* USB Host Controller Driver (usb_hcd) framework
*
* Since "struct usb_bus" is so thin, you can't share much code in it.
* This framework is a layer over that, and should be more sharable.
*/
/*-------------------------------------------------------------------------*/
1,struct usb_hcd { /* usb_bus.hcpriv points to this */ 描述USB的Host Controller Driver
/*
* housekeeping 家务管理
*/
struct usb_bus self; /* hcd is-a bus */ 所代表的USB Bus
const char *product_desc; /* product/vendor string */ 产品字符串
char irq_descr[24]; /* driver + bus # */ 驱动+总线
struct timer_list rh_timer; /* drives root-hub polling */ 根hub轮询
struct urb *status_urb; /* the current status urb */ 目前的状态urb
/*
* hardware info/state 硬件资源/状态
*/
const struct hc_driver *driver; /* hw-specific hooks */ 硬件特定的钩子函数,操作HC硬件
unsigned saw_irq : 1;
unsigned can_wakeup:1; /* hw supports wakeup? */
unsigned remote_wakeup:1; /* sw should use wakeup? */
unsigned rh_registered:1; /* is root hub registered? */
/* 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; 支持新的根hub轮询?
unsigned poll_rh:1; /* poll for rh status? */ 轮询根hub状态?
unsigned poll_pending:1; /* status has changed? */ 状态已改变?
int irq; /* irq allocated */ 被分配的irq
void __iomem *regs; /* device memory/io */ 设备的IO内存
u64 rsrc_start; /* memory/io resource start */ IO内存起始地址
u64 rsrc_len; /* memory/io resource length */ IO内存长度
unsigned power_budget; /* in mA, 0 = no limit */ 最大电流
#define HCD_BUFFER_POOLS 4
struct 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)
/* 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).
*/
/* The HC driver's private data is stored at the end of
* this structure. 私有数据
*/
unsigned long hcd_priv[0]
__attribute__ ((aligned (sizeof(unsigned long))));
};
2,struct hc_driver {
const char *description; /* "ehci-hcd" etc */ ehci-hcd等
const char *product_desc; /* product/vendor string */ 产品字符串
size_t hcd_priv_size; /* size of private data */ 私有数据的size
/* irq handler */
irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);中断处理函数
int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ HC的寄存器使用的内存或I/O
#define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */
/* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd); 初始化HCD
int (*start) (struct usb_hcd *hcd); 初始化根Hub
/* NOTE: these suspend/resume calls relate to the HC as
* a whole, not just the root hub; they're for bus glue.
*/
/* called after all devices were suspended */
int (*suspend) (struct usb_hcd *hcd, pm_message_t message);挂起Hub,进入D3(etc)前调用
/* called before any devices get resumed */
int (*resume) (struct usb_hcd *hcd); 进入D0(etc)后,恢复Hub
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd); HCD停止MM和IO
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd); 返回目前帧数
/* manage i/o requests, device state */
int (*urb_enqueue) (struct usb_hcd *hcd, 插入和退出urb队列
struct usb_host_endpoint *ep,
struct urb *urb,
unsigned mem_flags);
int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd, 释放endpoint资源
struct usb_host_endpoint *ep);
/* root hub support */ 根Hub操作
int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
int (*hub_control) (struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int (*hub_suspend)(struct usb_hcd *);
int (*hub_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
void (*hub_irq_enable)(struct usb_hcd *);
/* Needed only if port-change IRQs are level-triggered */
};
/**
* usb_create_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
* @dev: device for this HC, stored in hcd->self.controller
* @bus_name: value to store in hcd->self.bus_name
* Context: !in_interrupt()
*
* Allocate a struct usb_hcd, with extra space at the end for the
* HC driver's private data. Initialize the generic members of the
* hcd structure.
*
* If memory is unavailable, returns NULL.
*/
3,struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name)
/**
* usb_add_hcd - finish generic HCD structure initialization and register
* @hcd: the usb_hcd structure to initialize
* @irqnum: Interrupt line to allocate
* @irqflags: Interrupt type flags
*
* Finish the remaining parts of generic HCD initialization: allocate the
* buffers of consistent memory, register the bus, request the IRQ line,
* and call the driver's reset() and start() routines.
*/
4,int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags)
/**
* usb_remove_hcd - shutdown processing for generic HCDs
* @hcd: the usb_hcd structure to remove
* Context: !in_interrupt()
*
* Disconnects the root hub, then reverses the effects of usb_add_hcd(),
* invoking the HCD's stop() method.
*/
5,void usb_remove_hcd(struct usb_hcd *hcd);
/*
* This is the full ohci controller description
*
* Note how the "proper" USB information is just
* a subset of what the full implementation needs. (Linus)
*/
6,struct ohci_hcd { 作为usb_hcd结构体的hcd_priv
spinlock_t lock;
/*
* I/O memory used to communicate with the HC (dma-consistent)
*/
struct ohci_regs __iomem *regs; 与主机控制器通信的IO内存(DMA 一致)
/*
* main memory used to communicate with the HC (dma-consistent).
* hcd adds to schedule for a live hc any time, but removals finish
* only at the start of the next frame.
*/
struct ohci_hcca *hcca; 与主机控制器通信的主存(DMA 一致)
dma_addr_t hcca_dma;
struct ed *ed_rm_list; /* to be removed */ 将移除的OHCI Endpoint Descriptor (ED)
struct ed *ed_bulktail; /* last in bulk list */ 批量队列尾
struct ed *ed_controltail; /* last in ctrl list */ 控制队列尾
struct ed *periodic [NUM_INTS];/* shadow int_table */ ??
/*
* OTG controllers and transceivers need software interaction;
* other external transceivers should be software-transparent
*/
struct otg_transceiver *transceiver; OTG控制器和收发器需要软件交互,其他的外部收发器应该是软件透明的.
/*
* memory management for queue data structures 队列数据的内存管理
*/
struct dma_pool *td_cache;
struct dma_pool *ed_cache;
struct td *td_hash [TD_HASH_SIZE];
struct list_head pending;
/*
* driver state 状态
*/
int load [NUM_INTS];
u32 hc_control; /* copy of hc control reg */ 主机控制器控制寄存器的复制
unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */ 被保存的寄存器
struct work_struct rh_resume;
struct notifier_block reboot_notifier;
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/
// there are also chip quirks/bugs in init logic
};
7,struct ohci_hcd *hcd_to_ohci(struct usb_hcd *hcd); 内联函数usb_hcd与ohci_hcd的转换,得到私有数据
struct usb_hcd *ohci_to_hcd(const struct ohci_hcd *ohci); 通过conainer_of()从结构体成员获得所在结构体指针
8,static int ohci_init (struct ohci_hcd *ohci); 初始化
static int ohci_run (struct ohci_hcd *ohci) 开启
static void ohci_stop (struct usb_hcd *hcd); 停止
static void ohci_usb_reset (struct ohci_hcd *ohci) 复位
二,S3c2410主机驱动实例:
S3c2410的集成的USB主机控制器兼容并实现OCHI1.0,USB1.1协议层.
0x4900 0000 OHCI HcRevision
HcControl
HcCommonStatus
HcInterruptStatus
HcInterruptDisable
HcHCCA
HcPeriodCuttentED
HcControlHeadED
HcControlCurrentED
HcBulkHeadED
HcBulkCurrentED
HcDoneHead
HcRmInterval
HcFmRemaining
HcFmNumber
HcPeriodicStart
HcLSThreshold
HcRhDescriptorA
HcRhDescriptorB
HcRhStatus
HcRhportStatus1
HcRhPortStatus2
定义:static const struct hc_driver ohci_s3c2410_hc_driver = {
.description = hcd_name,
.product_desc = "S3C24XX OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
* generic hardware linkage 通用硬件连接
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations 基本生命周期操作
*/
.start = ohci_s3c2410_start,
.stop = ohci_stop,
/*
* managing i/o requests and associated device resources I/O操作
*/
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
/*
* scheduling support 调度
*/
.get_frame_number = ohci_get_frame,
/*
* root hub support 根Hub操作
*/
.hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control,
#if defined(CONFIG_USB_SUSPEND) && 0 挂起和恢复
.hub_suspend = ohci_hub_suspend,
.hub_resume = ohci_hub_resume,
#endif
};
实现函数:
static int ohci_s3c2410_start (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
if ((ret = ohci_init(ohci)) < 0)
return ret;
if ((ret = ohci_run (ohci)) < 0) {
err ("can't start %s", hcd->self.bus_name);
ohci_stop (hcd);
return ret;
}
return 0;
}
2,Linux的USB设备驱动
USB设备文件 usbdevfs,usbfs 是动态产生的 /dev/ttyUSBn (串口Major188)
挂载: 在/etc/fstab 加入 none /proc/bus/usb usbfs defaults
或输入: mount -t usbfs none /proc/bus/usb
显示: cat /proc/bus/usb/devices
拓扑,带宽,产品ID,Device Des,Config Des,Interface Des,Endpoint Des,Char Des.
sysfs:/sys/bus/usb ->devices
->drivers -> hub
-> usb
-> usbfs
/sys/devices
/sys/drivers
usb_driver:USB设备驱动描述
/**
* struct usb_driver - identifies USB driver to usbcore
* @owner: Pointer to the module owner of this driver; initialize
* it using THIS_MODULE.
* @name: The driver name should be unique among USB drivers,
* and should normally be the same as the module name.
* @probe: Called to see if the driver is willing to manage a particular
* interface on a device. If it is, probe returns zero and uses
* dev_set_drvdata() to associate driver-specific data with the
* interface. It may also use usb_set_interface() to specify the
* appropriate altsetting. If unwilling to manage the interface,
* return a negative errno value.
* @disconnect: Called when the interface is no longer accessible, usually
* because its device has been (or is being) disconnected or the
* driver module is being unloaded.
* @ioctl: Used for drivers that want to talk to userspace through
* the "usbfs" filesystem. This lets devices provide ways to
* expose information to user space regardless of where they
* do (or don't) show up otherwise in the filesystem.
* @suspend: Called when the device is going to be suspended by the system.
* @resume: Called when the device is being resumed by the system.
* @id_table: USB drivers use ID table to support hotplugging.
* Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
* or your driver's probe function will never get called.
* @driver: the driver model core driver structure.
*
* USB drivers must provide a name, probe() and disconnect() methods,
* and an id_table. Other driver fields are optional.
*
* The id_table is used in hotplugging. It holds a set of descriptors,
* and specialized data may be associated with each entry. That table
* is used by both user and kernel mode hotplugging support.
*
* The probe() and disconnect() methods are called in a context where
* they can sleep, but they should avoid abusing the privilege. Most
* work to connect to a device should be done when the device is opened,
* and undone at the last close. The disconnect code needs to address
* concurrency issues with respect to open() and close() methods, as
* well as forcing all pending I/O requests to complete (by unlinking
* them as necessary, and blocking until the unlinks complete).
*/
struct usb_driver { USB Core 总线部分
struct module *owner; 内核模块
const char *name; 唯一的USB设备名
int (*probe) (struct usb_interface *intf, const struct usb_device_id *id); 探测函数
void (*disconnect) (struct usb_interface *intf); 断开函数
int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); IO控制函数
int (*suspend) (struct usb_interface *intf, pm_message_t message); 挂起
int (*resume) (struct usb_interface *intf); 恢复
const struct usb_device_id *id_table; hotplugging探测设备表
struct device_driver driver; 驱动模块core
};
usb_device
usb_interface
usb_host_interface
usb_host_endpoint
linux下usb驱动编写(内核2.4)——2.6与此接口有区别
我们知道了在Linux下如何去使用一些最常见的USB设备。但对于做系统设计的程序员来说,我们还需要具有驱动程序的阅读、修改和开发能力。
USB骨架程序(usb-skeleton),是USB驱动架构。/driver/usb/usb-skeleton.c
那些linux下不支持的USB设备几乎都是生产厂商特定的产品。他们需要特定的驱动程序。有些生产厂商根本不公开他们的USB协议。因为每一个不同的协议都会产生一个新的驱动程序,所以就有了这个通用的USB驱动骨架程序,它是以pci 骨架为模板的。
如果你准备写一个linux驱动程序,首先要熟悉USB协议规范。还要有USB urbs的概念。
Linux USB 骨架驱动程序:
1,Init,并在USB Core子系统里注册,将这个驱动程序支持那种设备,当被支持的设备从系统插入或拔出时,会有哪些动作等信息都传送到USB Core子系统中.
module_init (usb_skel_init); 初始化包括usb_register
usb_register(&skel_driver);
static struct usb_driver skel_driver = {
name: "skeleton", 对驱动程序进行描述
probe: skel_probe, 函数指针,当设备与在id_table 中变量信息匹配时,此函数被调用。
disconnect: skel_disconnect, 函数指针
fops: &skel_fops,
minor: USB_SKEL_MINOR_BASE,
id_table: skel_table,
};
fops和minor变量是可选的。
大多usb驱动程序钩住另外一个驱动系统,例如SCSI,网络或者tty子系统。这些驱动程序在其他驱动系统中注册,同时任何用户空间的交互操作通 过那些接口提供,比如我们把SCSI设备驱动作为我们USB驱动所钩住的另外一个驱动系统,那么我们此USB设备的read、write等操作,就相应按SCSI设备的 read、write函数进行访问。
但是对于扫描仪等驱动程序来说,并没有一个匹配的驱动系统可以使用,那我们就要自己处理与用户空间的read、write等交互函数。
Usb子系统提供一种方法去注册一个次设备号和file_operations函数指针,这样就可以与用户空间实现方便地交互。
2,probe当usb设备插入时,为了使linux-hotplug(PCI、USB等设备热插拔支持)系统自动装载驱动程序,你需要创建一个MODULE_DEVICE_TABLE。代码如下(这个模块仅支持某一特定设备):
/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_DEVICE宏利用厂商ID和产品ID提供了一个设备的唯一标识。
USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, skel_table);
当插入一个ID匹配的USB设备到USB总线时,驱动会在USB core中注册。驱动程序中probe 函数也就会被调用。
static int skel_probe( struct usb_interface *interface, 接口指针
const struct usb_device_id *id) 接口ID
{
struct usb_skel *dev = NULL; 设备资源
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 = kmalloc(sizeof(*dev), GFP_KERNEL); 申请资源
if (dev == NULL) {
err("Out of memory");
goto error;
}
memset(dev, 0x00, sizeof(*dev)); 初始化资源
kref_init(&dev->kref); 引用计数初始化
dev->udev = usb_get_dev(interface_to_usbdev(interface));usb_device
dev->interface = interface; usb_interface
/* set up the endpoint information */ 设置端点信息
/* use only the first bulk-in and bulk-out endpoints */只使用第一个批量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_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) ) {
/* we found a bulk in endpoint */ 找到一个批量IN端点
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("Could not allocate bulk_in_buffer");
goto error;
}
}
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 */ 找到一个批量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;
}
/* save our data pointer in this interface device */ 把usb_skel保存到interface
usb_set_intfdata(interface, dev);
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &skel_class); 注册设备到USB Core,
1,ask for a minor number.
2,creates the devfs file for the usb device,devfs_mk_cdev().
class_device_create()
3,creates a usb class device in the sysfs tree.
if (retval) {
/* something prevented us from registering this driver */
err("Not able to get a minor for this device.");
usb_set_intfdata(interface, NULL);
goto error;
}
/* let the user know what node this device is now attached to */
info("USB Skeleton device now attached to USBSkel-%d", interface->minor);
return 0;
error:
if (dev)
kref_put(&dev->kref, skel_delete);
return retval;
}
/* Structure to hold all of our device specific stuff */
struct usb_skel { 自定义的数据结构usb_skel
struct usb_device *udev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
struct kref kref;
};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with devfs and the driver core
*/
static struct usb_class_driver skel_class = {
.name = "usb/skel%d",
.fops = &skel_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
.minor_base = USB_SKEL_MINOR_BASE,
};
static struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
};
驱动程序需要确认插入的设备是否可以被接受,如果不接受,或者在初始化的过程中发生任何错误,probe函数返回一个NULL值。否则返回一个含有设备驱动程序状 态的指针。通过这个指针,就可以访问所有结构中的回调函数。
3, 如果设备从usb总线拔掉,设备指针会调用disconnect函数。驱动程序就需要清除那些被分配了的所有私有数据、关闭urbs,并且释放设备文件devfs句柄。
usb_set_intfdata(interface, NULL);
usb_deregister_dev(interface, &skel_class);
kref_put(&dev->kref, skel_delete);
4,注销,当要从系统卸载驱动程序时,需要注销usb子系统。即需要usb_unregister函数处理:
module_exit(usb_skel_exit);
static void __exit usb_skel_exit(void)
{
/* deregister this driver with the USB subsystem */
usb_deregister(&skel_driver);
}
5,skeleton驱动就已经和设备绑定上了,任何用户态程序要操作此设备都可以通过file_operations结构所定义的函数进行了。
static struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
};
1,static int skel_open(struct inode *inode, struct file *file)
struct usb_skel *dev;
dev = usb_get_intfdata(interface);
/* increment our usage count for the device */
kref_get(&dev->kref);
/* save our object in the file's private structure */
file->private_data = dev;
2,static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
dev = (struct usb_skel *)file->private_data;
/* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg(dev->udev, 对usb设备进行一次读或写,这个函数能够不需要创建urbs和操作urb函数
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
&bytes_read, 10000);
3,static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) 利用urbs批量写
/* 建立一个urb及其buffer,复制user_buffer到urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
if (copy_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
goto error;
}
/* 设定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;
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
/* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb);
exit:
return count;
4,static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
skel_write_bulk的回调函数
5,static void skel_delete(struct kref *kref)
6,static int skel_release(struct inode *inode, struct file *file)
7,USB请求块 urbs
数据结构分析:
/usb/core
config.c
void usb_release_interface_cache(struct kref *ref)
int usb_get_configuration(struct usb_device *dev)
void usb_destroy_configuration(struct usb_device *dev)
buffer.c
int hcd_buffer_create ( struct usb_hcd *hcd )
void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, unsigned mem_flags, dma_addr_t *dma )
void hcd_buffer_free ( struct usb_bus *bus,size_t size, void *addr,dma_addr_t dma )
void hcd_buffer_destroy ( struct usb_hcd *hcd )
devices.c
void usbfs_conn_disc_event(void)
struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
.open = usb_device_open,
.release = usb_device_release,
};
devio.c
struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
.ioctl = usbdev_ioctl,
.open = usbdev_open,
.release = usbdev_release,
};
file.c
int usb_major_init(void)
void usb_major_cleanup(void)
int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver)
void usb_deregister_dev(struct usb_interface *intf, struct usb_class_driver *class_driver)
inode.c
void usbfs_update_special (void)
void usbfs_add_bus(struct usb_bus *bus)
void usbfs_remove_bus(struct usb_bus *bus)
void usbfs_add_device(struct usb_device *dev)
void usbfs_remove_device(struct usb_device *dev)
int __init usbfs_init(void)
void usbfs_cleanup(void)
sysfs.c
void usb_create_sysfs_dev_files (struct usb_device *udev)
void usb_remove_sysfs_dev_files (struct usb_device *udev)
void usb_create_sysfs_intf_files (struct usb_interface *intf)
void usb_remove_sysfs_intf_files (struct usb_interface *intf)
message.c
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)
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
int usb_sg_init (
struct usb_sg_request *io,
struct usb_device *dev,
unsigned pipe,
unsigned period,
struct scatterlist *sg,
int nents,
size_t length,
unsigned mem_flags
)
void usb_sg_wait (struct usb_sg_request *io)
void usb_sg_cancel (struct usb_sg_request *io)
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
int usb_get_string(struct usb_device *dev, unsigned short langid,
unsigned char index, void *buf, int size)
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
int usb_get_status(struct usb_device *dev, int type, int target, void *data)
int usb_clear_halt(struct usb_device *dev, int pipe)
void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
void usb_disable_device(struct usb_device *dev, int skip_ep0)
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
int usb_reset_configuration(struct usb_device *dev)
int usb_set_configuration(struct usb_device *dev, int configuration)
urb.c
void usb_init_urb(struct urb *urb)
void usb_free_urb(struct urb *urb)
int usb_submit_urb(struct urb *urb, unsigned mem_flags)
int usb_unlink_urb(struct urb *urb)
void usb_kill_urb(struct urb *urb)
usb.c
int usb_register(struct usb_driver *new_driver)
void usb_deregister(struct usb_driver *driver)
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,unsigned int altnum)
int usb_driver_claim_interface(struct usb_driver *driver,struct usb_interface *iface, void* priv)
void usb_driver_release_interface(struct usb_driver *driver,struct usb_interface *iface)
const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
struct usb_device *usb_get_dev(struct usb_device *dev)
void usb_put_dev(struct usb_device *dev)
void usb_put_intf(struct usb_interface *intf)
void usb_lock_device(struct usb_device *udev)
int usb_trylock_device(struct usb_device *udev)
int usb_lock_device_for_reset(struct usb_device *udev,
void usb_unlock_device(struct usb_device *udev)
void usb_lock_all_devices(void)
void usb_unlock_all_devices(void)
struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
int usb_get_current_frame_number(struct usb_device *dev)
int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
void *usb_buffer_alloc (struct usb_device *dev, size_t size,unsigned mem_flags,dma_addr_t *dma )
void usb_buffer_free (
struct usb_device *dev,
size_t size,
void *addr,
dma_addr_t dma
)
int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,struct scatterlist *sg, int nents)
void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,struct scatterlist *sg, int n_hw_ents)
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.hotplug = usb_hotplug,
.suspend = usb_generic_suspend,
.resume = usb_generic_resume,
};
int usb_disabled(void)
hub.c
void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
void usb_set_device_state(struct usb_device *udev,enum usb_device_state new_state)
void usb_disconnect(struct usb_device **pdev)
int usb_new_device(struct usb_device *udev)
int usb_suspend_device(struct usb_device *udev, pm_message_t state)
int usb_resume_device(struct usb_device *udev)
void usb_resume_root_hub(struct usb_device *hdev)
int usb_suspend_device(struct usb_device *udev, pm_message_t state)
int usb_hub_init(void)
void usb_hub_cleanup(void)
int usb_reset_device(struct usb_device *udev)
hcd.c
struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,struct device *dev, char *bus_name)
创建一个usb_hcd结构体并初始化.
usb_hcd,usb_bus,hc_driver,timer_list,device
usb_devmap,usb_operations,usb_device,dentry,class_device,mon_bus
int usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags)
复位 retval = hcd->driver->reset(hcd)
定位一段usb DMA, retval = hcd_buffer_create(hcd)
register the bus, usb_register_bus(&hcd->self)
request the IRQ line, request_irq(irqnum, &usb_hcd_irq, irqflags,hcd->irq_descr, hcd))
start(). rhdev = usb_alloc_dev(NULL, &hcd->self, 0) hcd->driver->start(hcd)
usb_device
void usb_remove_hcd(struct usb_hcd *hcd)
usb_disconnect(&hcd->self.root_hub);
free_irq(hcd->irq, hcd);
usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd);
void usb_hcd_poll_rh_status(struct usb_hcd *hcd) Root hub中断后的定时传输函数
static void rh_timer_func (unsigned long _hcd)
{
usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
}
struct usb_bus *usb_bus_get(struct usb_bus *bus)
void usb_bus_put(struct usb_bus *bus)
int usb_host_init(void)
void usb_enable_root_hub_irq (struct usb_bus *bus)
long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
void usb_hc_died (struct usb_hcd *hcd)
void usb_put_hcd (struct usb_hcd *hcd)
int usb_mon_register (struct usb_mon_operations *ops)
void usb_mon_deregister (void)
hcd-api.c
int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
void usb_hcd_pci_remove (struct pci_dev *dev)
int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
int usb_hcd_pci_resume (struct pci_dev *dev)
/usb/host
/usb/gadget
3,USB固件驱动
UDC
Gadger API
Gadget