首先,我不是做驱动的开发人员。所以只能用自娱自乐来表示我的行为。
我不知道udc和gadget驱动是不是冷门的驱动,资料真是不多。我之前买了一本书,上面说到这些,就教你如何调试已写好的驱动。这样也可以写书,太坑了吧!我随便从网上搜搜都能写的比他好。难道现在的育人机构为了钱都变成了坑人机构。
我以前就希望把自己写过的驱动总结成一个模板,让人能直观的看出linux提供的接口要我们做什么甚至怎么做。虽然做这个比较难,但我还是成功的欺骗了自己,可以做到。
这是自娱自乐第一期,可能废话多了一点,请大家原谅。现在说这个模板。这个是一个未做实际应用的模板,只是编译通过,除了没实践,还缺少DMA和USB的请求类型处理样例。后期我会用它做一个驱动,不断的完善。现在这个应该在理论和实践之间的东西。
常用结构体(别人写的,不是linux-3.2.36,不过差不多)
========================================================USB UDC与gadget驱动=========================================================
/*
*linux内核中usb设备侧驱动程序分为3个层次:UDC驱动、Gadget API和Gadget驱动程序,UDC驱动程序直接访问硬件usb控制器OHCI/EHCI/UHCI,作为usb设备和主机间的底层通信,向上层
*提供与硬件相关操作的回调函数。当前Gadget API是对UDC驱动程序回调函数的简单包装。Gadget驱动程序具体控制系统作为usb设备时的相关功能的实现,使设备表现出“网络连接”、“打印机”
*或“USB Mass Storage”等特性。
*
* 这里的USB设备控制器(UDC)驱动指作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将USB设备依附于一个USB主机控制器上:比如当某运行linux的手机作为PC
*的U盘时,手机的底层USB控制器行使USB设备控制器的功能,这时候运行在底层的是UDC驱动,而手机成为U盘,在UDC驱动之上仍然需要另一个驱动,对于USB大容量存储器为file storage驱动,这一
*驱动称为gadget驱动(总之是一个运行linux的系统的usb接口作为另一个linux系统的设备)。usb设备驱动调用usb核心提供的API,因此具体驱动与SOC无关。同样,usb gadget驱动调用通用的gadget API
*因此具体gadget驱动也变得与SOC无关。
*UDC驱动和gadget驱动都位于内核的drivers/usb/gadget目录下,S3C2410对应的UDC驱动为s3c2410_udc.c。ether.c、f_serial.c、file_storage.c等文件实现了一些gadget驱动
*/
#include <linux/gadget.h>
-----------------------------------------------------------struct usb_gadget------------------------------------------------------
struct usb_gadget { //描述USB设备控制器
/* readonly to gadget driver */ //针对gadget驱动只读
const struct usb_gadget_ops *ops; //访问硬件函数
struct usb_ep *ep0; //端点0,setup使用
struct list_head ep_list; /* of usb_ep */ //其他端点列表
enum usb_device_speed speed;
unsigned is_dualspeed:1;
unsigned is_otg:1;
unsigned is_a_peripheral:1;
unsigned b_hnp_enable:1; //A-HOST使能了HNP支持
unsigned a_hnp_support:1; //A-HOST支持HNP
unsigned a_alt_hnp_support:1;
const char *name;
struct device dev;
};
------------------------------------------------------struct usb_gadget_ops-------------------------------------------------------
struct usb_gadget_ops { //硬件操作函数
int (*get_frame)(struct usb_gadget *);
int (*wakeup)(struct usb_gadget *);
int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
int (*vbus_session) (struct usb_gadget *, int is_active);
int (*vbus_draw) (struct usb_gadget *, unsigned mA);
int (*pullup) (struct usb_gadget *, int is_on);
int (*ioctl)(struct usb_gadget *,
unsigned code, unsigned long param);
};
-----------------------------------------------------struct usb_gadget_driver----------------------------------------------------
struct usb_gadget_driver { //描述gadget驱动
char *function; //描述gadget功能的字符串
enum usb_device_speed speed;
int (*bind)(struct usb_gadget *); //当驱动和gadget绑定时调用
void (*unbind)(struct usb_gadget *);
int (*setup)(struct usb_gadget *, //处理硬件驱动未处理的端点0请求
const struct usb_ctrlrequest *);
void (*disconnect)(struct usb_gadget *);
void (*suspend)(struct usb_gadget *);
void (*resume)(struct usb_gadget *);
/* FIXME support safe rmmod */
struct device_driver driver;
};
-----------------------------------------------------struct usb_request----------------------------------------------------------
struct usb_request { //表示一个传输请求的usb_request(与从机端看到的urb相似)
void *buf;
unsigned length;
dma_addr_t dma;
unsigned no_interrupt:1;
unsigned zero:1;
unsigned short_not_ok:1;
void (*complete)(struct usb_ep *ep,
struct usb_request *req);
void *context;
struct list_head list;
int status;
unsigned actual;
};
----------------------------------------------------------struct usb_ep---------------------------------------------------------
struct usb_ep { //描述一个端点
void *driver_data;
const char *name;
const struct usb_ep_ops *ops;
struct list_head ep_list;
unsigned maxpacket:16;
};
------------------------------------------------------struct usb_ep_ops---------------------------------------------------------
struct usb_ep_ops { //描述端点操作
int (*enable) (struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc);
int (*disable) (struct usb_ep *ep);
struct usb_request *(*alloc_request) (struct usb_ep *ep,
gfp_t gfp_flags);
void (*free_request) (struct usb_ep *ep, struct usb_request *req);
int (*queue) (struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags);
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
int (*set_halt) (struct usb_ep *ep, int value);
int (*set_wedge) (struct usb_ep *ep);
int (*fifo_status) (struct usb_ep *ep);
void (*fifo_flush) (struct usb_ep *ep);
};
--------------------------------------------------------------------------------------------------------------------------------
/*
*UDC和gadget驱动围绕上述数据结构及其成员函数而展开。
*在具体的UDC驱动中,需要封装usb_gadget和每个端点usb_ep,实现端点usb_ep_ops,完成usb_request。另外usb_gadget_register_driver和usb_gadget_unregister_driver这两个API需要由UDC
*驱动提供,gadget驱动会调用它们。
*/
int usb_gadget_register_driver(struct usb_gadget_driver *driver); //注册,在加载模块中调用,该函数中会调用driver->bind()函数,将usb_gadget_driver与具体的gadget绑定
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); //注销,在卸载模块中调用,告诉UDC驱动不再投入工作,如果UDC正在和USB主机连接,会先调用driver->disconnect()
//函数,而后会调用unbind()函数
//在linux/usb/gadget.h中,封装了一些常用的API:
int usb_ep_enable(struct usb_ep *ep,const struct usb_endpoint_descriptor *desc); //使能端点 ,该函数会调用struct usb_ep_ops->enable()
int usb_ep_disable(struct usb_ep *ep); //禁止端点,该函数会调用struct usb_ep_ops->disable()
struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,gfp_t gfp_flags); //分配一个依附于某端点的 usb_request,该函数会调用struct usb_ep_ops->usb_request()
void usb_ep_free_request(struct usb_ep *ep,struct usb_request *req); //释放一个依附于某端点的 usb_request,该函数会调用struct usb_ep_ops->free_request()
int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags);//提交usb_request,该函数告诉UDC完成usb_request(读写buffer),当请求被完成后,该请求对应的completion函数会被调用,
//该函数会调用struct usb_ep_ops->queue(),该函数告诉UDC完成usb_request(读写buffer),当请求完成后,该请求对应的completion函数会被调用
int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req); //取消usb_request,该函数会调用struct usb_ep_ops->dequeue()
端点FIFO管理:
int usb_ep_fifo_status(struct usb_ep *ep); //该函数会调用truct usb_ep_ops->fifo_status返回目前FIFO中的字节数
void usb_ep_fifo_flush(struct usb_ep *ep); //该函数会调用truct usb_ep_ops->fifo_flush,以flush(冲洗)掉FIFO中的数据
int usb_gadget_frame_number(struct usb_gadget *gadget); //它调用gadget->ops->get_frame(gadget)返回目前的帧号
/*
*S3C2410的UDC驱动在 /driver/usb/gadget/s3c2410_udc.c
*/
/-----------------------------------------------------------------------------------------------------------------------------/
看请求队列的处理
struct xxxxx_request
{
structlist_head queue; /* ep'srequests */
structusb_request req; //对应主机端看到的urb
};
struct