1. modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 modprobe后面也可以加模块参数

2. prn_example从stdout获取数据然后通过USB发送出去,下面让他将文件中的内容发送出去:
# cat data_file | prn_example -write_data

3.pdev = device_create(usb_gadget_class, NULL, devt, NULL, "g_printer%d", dev->minor); /*这个应该是在gadget类下创建一个device: struct device结构*/

4. 在调用bind后,经过重重函数调用,现在设备终于饱满了,既有配置了,也有接口了,接口里也有相应的端点了。各层的关系也都联系起来了。

5.核心结构体

/*将配置分组到gadget中*/
struct usb_composite_driver {
const char *name;
const struct usb_device_descriptor *dev;
struct usb_gadget_strings **strings;
enum usb_device_speed max_speed;
unsigned needs_serial:; /*用于分配整个设备共享的资源,例如字符串ID,并使用@usb_add_config()添加其配置。
返回负的errno值可能会失败; 它应该在成功初始化时返回零。*/
int (*bind)(struct usb_composite_dev *cdev);
/*与@bind相反*/
int (*unbind)(struct usb_composite_dev *); /*可选的驱动断开方法*/
void (*disconnect)(struct usb_composite_dev *); /* global suspend hooks */
void (*suspend)(struct usb_composite_dev *);
void (*resume)(struct usb_composite_dev *);
/*hidg_driver:指向全局composite_driver_template*/
struct usb_gadget_driver gadget_driver;
};
/*代表一个复合的USB gadget*/
struct usb_composite_dev {
/*只读,作为此gadget的USB外设USB控制器的抽象*/
struct usb_gadget *gadget;
/*用于控制响应; 缓冲区是预先分配的*/
struct usb_request *req;
/*用于OS描述符响应,缓冲区是预先分配的*/
struct usb_request *os_desc_req;
/*当前active的配置*/
struct usb_configuration *config; /* OS String is a custom (yet popular) extension to the USB standard. */
u8 qw_sign[OS_STRING_QW_SIGN_LEN];
u8 b_vendor_code;
struct usb_configuration *os_desc_config;
unsigned int use_os_string:; /* private: */
/* internals */
unsigned int suspended:;
struct usb_device_descriptor desc;
struct list_head configs; /*usb_add_config_only()中将add的config添加到这个链表中*/
struct list_head gstrings;
struct usb_composite_driver *driver;
u8 next_string_id;
char *def_manufacturer; /* the gadget driver won't enable the data pullup
* while the deactivation count is nonzero.
*/
unsigned deactivations; /* the composite driver won't complete the control transfer's
* data/status stages till delayed_status is zero.
*/
int delayed_status; /* protects deactivations and delayed_status counts*/
spinlock_t lock; /* public: */
unsigned int setup_pending:; /*true when setup request is queued but not completed*/
unsigned int os_desc_pending:;
};
/*代表usb从设备的驱动程序 */
struct usb_gadget_driver {
/*描述此gadget功能的字符串*/
char *function; /*String describing the gadget's function*/
/*此驱动能处理的最大速率*/
enum usb_device_speed max_speed;
/*驱动的bind的回调*/
int (*bind)(struct usb_gadget *gadget, struct usb_gadget_driver *driver);
/*驱动程序从gadget解除绑定时调用,通常来自rmmod(报告断开连接后),在允许睡眠的环境中调用*/
void (*unbind)(struct usb_gadget *);
/** @setup:由未被硬件级驱动程序处理的ep0控制请求调用。 大多数调用必须由gadget驱动程序处理,
包括描述符和配置管理。 设置数据的16位成员按USB字节顺序排列。 在in_interrupt被调用; 这可能不
会睡觉。 驱动程序将对ep0的响应排队,或将负数返回到停止。*/
int (*setup)(struct usb_gadget *,const struct usb_ctrlrequest *);
/*@disconnect:在主机断开连接后停止所有传输后调用。 可能在中断上下文中调用; 这可能不能睡眠。
某些设备无法检测到断开连接,因此除非作为控制器关闭的一部分,否则可能无法调用此函数。*/
void (*disconnect)(struct usb_gadget *);
void (*suspend)(struct usb_gadget *);
void (*resume)(struct usb_gadget *);
void (*reset)(struct usb_gadget *); /* FIXME support safe rmmod */ /*===>目前内核不支持安全的rmmod!!!*/
struct device_driver driver; /*应该绑定此驱动程序的UDC名称。 如果udc_name为NULL,则此驱动程序将绑定到任何可用的UDC。*/
char *udc_name;
struct list_head pending; /*挂载在等待udc的链表上*/
unsigned match_existing_only:; /*决定在没有available的UDC时,释放将绑定请求的driver挂载到pending链表上
see usb_gadget_probe_driver()*/
};
/*代表一个usb从设备*/
struct usb_gadget {
/*sysfs_notify()使用的工作队列*/
struct work_struct work;
struct usb_udc *udc;
/*用于访问特定于硬件的操作的函数指针,对于gadget driver来说是只读的*/
const struct usb_gadget_ops *ops; /*指向全局的:renesas_usb3_gadget_ops*/
struct usb_ep *ep0; /*端点0,控制端点*/
struct list_head ep_list; /* of usb_ep, List of other endpoints supported by the device.*/
enum usb_device_speed speed;
enum usb_device_speed max_speed;
enum usb_device_state state;
const char *name;
struct device dev;
unsigned out_epnum; /*分别为输入输出端点数*/
unsigned in_epnum;
unsigned mA;
struct usb_otg_caps *otg_caps; unsigned sg_supported:;
unsigned is_otg:; /*标识是不是otg设备*/
unsigned is_a_peripheral:;
unsigned b_hnp_enable:;
unsigned a_hnp_support:;
unsigned a_alt_hnp_support:;
unsigned hnp_polling_support:;
unsigned host_request_flag:;
unsigned quirk_ep_out_aligned_size:;
unsigned quirk_altset_not_supp:;
unsigned quirk_stall_not_supp:;
unsigned quirk_zlp_not_supp:;
unsigned quirk_avoids_skb_reserve:;
unsigned is_selfpowered:; /*表明此gadget是否为self-powered*/
unsigned deactivated:;
unsigned connected:;
unsigned lpm_capable:;
};

我们发现这些bind就是一个目的,初始化struct usb_composite_dev结构,使其逐渐丰满。因为这个结构代表一个USB设备。
经过合适的初始化后设备才能正确的工作。经过重重初始化,三层总算整合在了一起了。这三层最终形成了一个饱满的
struct usb_composite_dev结构。这个结构包含USB设备运行各种信息。包括:配置,接口,端点等。

6.作为host称为USB主机控制器驱动,作为gadget时称为USB设备控制器驱动(UDC)

7.USB设备控制器驱动,需要关心四个核心的数据结构,这些数据结构包括描述一个USB设备控制器的usb_gadget、UDC操作usb_gadget_ops、
描述一个端点的usb_ep以及描述端点操作的usb_ep_ops结构体。UDC驱动围绕这些数据结构及其成员函数展开

8.打印机的设备位置为:# ls -l /devices/virtual/usb_printer_gadget/

9.由于普通USB设备只有一个上游端口,因此它们只有一个这样的驱动程序。 控制器驱动程序可以支持任意数量的不同gadget驱动程序,
但一次只能使用其中一个。

10.host端驱动与USB主机控制器驱动的交互通过 struct urb, 而作为gadget时,驱动与USB设备控制器之间的交互使用 struct usb_request来 ########
描述一次IO请求。

11.内核文档翻译:
https://01.org/linuxgraphics/gfx-docs/drm/driver-api/usb/gadget.html?highlight=usb_composite_probe#c.usb_composite_probe
gadget驱动的生命周期
gadget驱动程序向硬件发出端点I/O请求,而无需了解硬件的许多细节,但驱动程序设置/配置代码需要处理一些差异。 像这样使用API:

1.为特定设备端USB控制器硬件注册驱动程序,例如PCI PDA(USB 2.0)上的net2280,Linux PDA中的sa11x0或pxa25x,依此类推。 此时,
设备逻辑上处于USB ch9初始状态(已连接attached),没有电源且无法使用(因为它还不支持枚举)。 任何主机都不应该看到该设备,
因为即使VBUS电源可用,它也不会激活主机用来检测设备的数据线上拉。
2.注册实现某些更高级别设备功能的gadget驱动程序。 然后将bind()绑定到usb_gadget,它会在检测到VBUS后的某个时间激活数据线上拉。
3.硬件驱动程序现在可以开始枚举。 它处理的步骤是接受USB电源和set_address请求。 其他步骤由gadget驱动程序处理。 如果在主机开
始枚举之前卸载gadget驱动程序模块,则跳过步骤7之前的步骤。
4.gadget驱动程序的setup()调用返回usb描述符,既基于总线接口硬件提供的内容,也基于正在实现的功能。 这可能涉及备用设置或配置,
除非硬件阻止此类操作。 对于OTG设备,每个配置描述符包括OTG描述符。
5.当USB主机发出set_configuration调用时,gadget驱动程序处理枚举的最后一步。 它使能该配置中使用的所有端点,使所有接口都处于
默认设置。 这涉及使用硬件端点列表,根据端点描述符启用每个端点。 它还可能涉及使用usb_gadget_vbus_draw()来从VBUS中获取更多的
电流(可选Rcar3没有实现),如该配置所允许的那样。 对于OTG设备,设置配置还可能涉及通过用户界面报告HNP功能。
6.执行实际工作并执行数据传输,可能涉及更改接口设置或切换到新配置,直到设备与主机断开连接disconnect()。 将任意数量的传输请求
排队到每个端点。 在断开连接之前,它可能会被suspend和resume几次。 断开连接时,驱动程序将返回步骤3(上方)。
7.卸载gadget驱动程序模块时,驱动程序的unbind()将会被回调。 这样可以控制器驱动程序被卸载。

驱动程序通常会被安排,以便只加载gadget驱动程序模块(或将其静态链接到Linux内核)允许外围设备被枚举,但某些驱动程序将推迟枚举,
直到某些更高级别的组件(如用户模式守护程序)使能它。 请注意,在此最低级别,没有关于如何实现ep0配置逻辑的策略,除了它应遵守
USB规范。 这些问题属于gadget驱动程序领域,包括了解某些USB控制器强加的实施限制,或者了解复合设备可能恰好通过集成可重用组件来
构建。

请注意,OTG设备的上述生命周期可能略有不同。 除了在每个配置中提供额外的OTG描述符之外,只有与HNP相关的差异对于驱动程序代码特
别可见。 它们涉及SET_CONFIGURATION请求期间的报告要求,以及在某些挂起回调期间调用HNP的选项。 此外,SRP稍微改变了
usb_gadget_wakeup的语义。

struct usb_request 描述一次IO请求。

12.Gadget 功能驱动层, Gadget功能驱动层是USB Gadget软件结构的最上层。主要是实现USB设备的功能,
这一层通常与linux内核的其他子系统有密切的联系。

13.mod_gadget.c:这个是2.0的UDC驱动,renesas_usb3.c: 应该3.0的usb gadget的UDC驱动。

14.UDC层还需要提供USB设备的中断处理程序,中断处理尤其重要。因为所有的USB传输都是由主机发起,而有没有USB传输完全由USB中断判
定,所以USB中断处理程序是整个软件架构的核心。

15.在用户程序中,select()和poll()本质上是一样的, 不同只是引入的方式不同,前者是在BSD UNIX中引入的,后者是在System V中引入的。
用的比较广泛的是select

16.DECLARE_USB_FUNCTION_INIT(printer, gprinter_alloc_inst, gprinter_alloc);

DECLARE_USB_FUNCTION_INIT(printer, gprinter_alloc_inst, gprinter_alloc);
/*==========================上面等效下面======================================*/
static struct usb_function_driver printerusb_func = {
.name = "printer",
.mod = THIS_MODULE,
.alloc_inst = gprinter_alloc_inst,
.alloc_func = gprinter_alloc,
};
MODULE_ALIAS("usbfunc:printer"); /*用它来加载驱动模块*/ static int __init printermod_init(void)
{
return usb_function_register(&printerusb_func);
}
static void __exit printermod_exit(void)
{
usb_function_unregister(&printerusb_func);
}
module_init(printermod_init);
module_exit(printermod_exit);
module_usb_composite_driver(printer_driver);
/*-------module_usb_composite_driver(printer_driver);等效如下----------*/
static int __init printer_driver_init(void)
{
return usb_composite_probe(&printer_driver);
}
module_init(printer_driver_init);
static void __exit printer_driver_exit(void)
{
usb_composite_unregister(&printer_driver);
}
module_exit(printer_driver_exit); /*----------------------------------------------------------------------*/

17.module_param_named(maximum_line_test, max_test, int, 0); 此定义下,该参数的外部可见参数名为:maximum_line_test,内部全局变量名为:max_test */

18.usb2.0的gadget的UDC注册过程:

usbhs_probe  //[usb/renesas_usbhs/common.c]
usbhs_mod_probe //[usb/renesas_usbhs/mod.c]
usbhs_mod_gadget_probe //[usb/renesas_usbhs/mod_gadget.c]
usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) //[usb/gadget/udc/core.c] 将新gadget添加到udc类驱动程序列表中
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
udc->dev.class = udc_class;
udc->dev.groups = usb_udc_attr_groups;
list_add_tail(&udc->list, &udc_list); 将此udc放到全局链表udc_list中
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;
check_pending_gadget_drivers(udc) //[usb/gadget/udc/core.c] 匹配一个usb_gadget_driver
list_for_each_entry(driver, &gadget_driver_pending_list, pending) //在gadget_driver_pending_list查找pending的usb_gadget_driver
if (!driver->udc_name || strcmp(driver->udc_name, dev_name(&udc->dev)) == ) //usb_udc和usb_gadget_driver通过名字进行匹配
ret = udc_bind_to_driver(udc, driver); =====>UDC也是以一个usb_gadget的形式注册的。
19.f_printer.c中function注册过程:
DECLARE_USB_FUNCTION_INIT
int __init printermod_init(void)
usb_function_register(&printerusb_func) //这个注册仅仅是将usb_function_driver放到全局链表func_list中
list_add_tail(&newf->list, &func_list); //[usb/gadget/functions.c]

20.printer.c中:

printer_driver_init
usb_composite_probe(struct usb_composite_driver *driver); //传参为全局变量&printer_driver
driver->gadget_driver = composite_driver_template;
由usb_composite_driver构造出一个usb_gadget_driver
usb_gadget_probe_driver(struct usb_gadget_driver *driver) //传参为构造出来的usb_gadget_driver
它里面去匹配已经注册的UDC,若匹配不到就挂载在gadget_driver_pending_list上。
list_for_each_entry(udc, &udc_list, list) //在udc_list上查找已经注册的usb_udc
list_add_tail(&driver->pending, &gadget_driver_pending_list); //若匹配不到就将usb_gadget_driver放到链表gadget_driver_pending_list中。
udc_bind_to_driver(udc, driver); //若找到就将此usb_udc绑定到usb_gadget_driver中
udc->driver = driver;
driver->bind(udc->gadget, driver); //调用usb_gadget_driver的bind(),也就是composite_bind,是模板composite_driver_template中的,
参数是usb_gadget和usb_gadget_driver
struct usb_composite_dev *cdev = kzalloc(sizeof *cdev, GFP_KERNEL); //分配一个usb_composite_dev结构
cdev->gadget = usb_gadget;
composite_dev_prepare(struct usb_composite_driver *composite, struct usb_composite_dev *cdev)
cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); //预先分配ep0使用的req
cdev->req->complete = composite_setup_complete; //指定ep0的完成回调函数
usb_ep_autoconfig_reset(gadget); //执行一次端点的rest
composite->bind(cdev); //调用usb_composite_driver的bind(),也就是printer_bind,其调用流程如① ###########
update_unchanged_dev_desc(usb_device_descriptor *new, usb_device_descriptor *old) //更新设备描述符
usb_gadget_udc_start(udc); //使能usb设备控制器
udc->gadget->ops->udc_start(udc->gadget, udc->driver) //也就是调用usbhsg_gadget_ops.usbhsg_gadget_start,做一些设备控制器的初始化
usbhsg_try_start
usbhsg_update_pullup
usb_udc_connect_control(udc);
usb_gadget_connect
gadget->ops->pullup(gadget, ); //也就是调用usbhsg_gadget_ops.pullup,使能Dp上拉
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); //上报App printer.c中的usb_composite_driver.bind的调用流程:
printer_bind //① ###########
usb_get_function_instance("printer");
try_get_usb_function_instance(name);
list_for_each_entry(fd, &func_list, list) 在全局链表func_list中通过name查找之前使用
fi = fd->alloc_inst(); 找到对应的usb_function_driver并调用其alloc_inst()
fi->fd = fd; return fi; 然后fi->fd指向找到的usb_function_driver结构体。
usb_string_ids_tab(cdev, strings); //[usb/gadget/functions.c] 为每一个字符串都分配一个唯一的id,然后将这些id赋值给
usb_device_descriptor中的iManufacturer,iProduct,iSerialNumber。
gadget_is_otg //判断是不是otg,如果是,还要为其分配otg描述符 usb_otg_descriptor_alloc
usb_add_config(cdev, &printer_cfg_driver, printer_do_config);
usb_add_config_only(cdev, config); //将此config添加到usb_composite_dev cdev->configs中
printer_do_config //执行这个回调
usb_ep_autoconfig_reset
usb_gadget_set_selfpowered
f_printer = usb_get_function(fi_printer);
f = fi->fd->alloc_func(fi); //调用usb_function_instance的usb_function_driver的alloc_func,应该就
是gprinter_alloc,获取到一个usb_function
gprinter_alloc中初始化usb_function的各个成员函数(bind,unbind,setup,set_alt),做一些链表的初始化
f->fi = fi; return f; //usb_function的usb_function_instance指向此fi
status = usb_add_function(c, f_printer);
list_add_tail(&function->list, &config->functions); //将此usb_function挂接在usb_configuration的functions链表上
function->bind(config, function) //调用function的bind进行绑定,也即是printer_func_bind
usb_interface_id //分配一个没有使用的接口id
in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc); //根据端点描述符自动分配IN/OUT端点
out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
usb_assign_descriptors //对usb_function中的各个描述符赋值
for (i = ; i < dev->q_len; i++) //为in_ep/out_ep分配usb_request,并将其插入队列中
req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
list_add(&req->list, &dev->tx_reqs);
req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
list_add(&req->list, &dev->rx_reqs);
device_create(usb_gadget_class, NULL, devt, NULL, "g_printer%d", dev->minor); //创建设备类,为创建设备文件做准备
cdev_init(&dev->printer_cdev, &printer_io_operations); //在bind()中指定对用户空间的接口printer_io_operations
ret = cdev_add(&dev->printer_cdev, devt, );
usb_ep_autoconfig_reset(cdev->gadget); //执行一次reset ep的操作
usb_composite_overwrite_options //用来以实际的值覆盖USB_GADGET_COMPOSITE_OPTIONS中的模块参数声明。
												

USB gadget 驱动 printer.c 分析的更多相关文章

  1. Linux下 USB设备驱动分析(原创)

    之前做过STM32的usb HID复合设备,闲来看看linux下USB设备驱动是怎么一回事, 参考资料基于韦东山JZ2440开发板,以下,有错误欢迎指出. 1.准备知识 1.1USB相关概念: USB ...

  2. USB键盘驱动分析

    简介 本文介绍USB驱动程序编写的流程,分析一个键盘的USB程序,基于linux-2.6.39 USB驱动概要 分层 主机层面的USB驱动的整体架构可以分成4层,自顶到下依次是 1.USB设备驱动:本 ...

  3. Linux USB ECM Gadget 驱动介绍

    ​1 USB ECM介绍 USB ECM,属于USB-IF定义的CDC(Communication Device Class)下的一个子类:Ethernet Networking Control Mo ...

  4. Linux usb子系统(一) _写一个usb鼠标驱动

    USB总线是一种典型的热插拔的总线标准,由于其优异的性能几乎成为了当下大小设备中的标配. USB的驱动可以分为3类:SoC的USB控制器的驱动,主机端USB设备的驱动,设备上的USB Gadget驱动 ...

  5. debian下使用dynamic printk分析usb转串口驱动执行流程

    看了一篇文章<debug by printing>,文中提到了多种通过printk来调试驱动的方法,其中最有用的就是"Dynamic debugging". “Dyna ...

  6. Linux gadget驱动分析1------驱动加载过程

    为了解决一个问题,简单看了一遍linux gadget驱动的加载流程.做一下记录. 使用的内核为linux 2.6.35 硬件为芯唐NUC950. gadget是在UDC驱动上面的一层,如果要编写ga ...

  7. Android USB驱动源码分析(-)

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

  8. [置顶] 自娱自乐6之Linux gadget驱动5(自编gadget驱动,包涵与之通讯的主机usb驱动,已调试通过)

    这个代码调试,你首先要保证你的udc驱动没用问题,这个有些矛盾,应为我本来要用gadget驱动来调试udc驱动,结果反过来了. 这是在zero基础改的,大概的改动 1. 去掉loop. 2. sink ...

  9. Linux 串口、usb转串口驱动分析(2-2) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...

随机推荐

  1. Nikita and stack CodeForces - 756C (栈,线段树二分)

    大意: 给定m个栈操作push(x)或pop(), 栈空时pop()无作用, 每个操作有执行的时间$t$, 对于每个$0 \le i \le m$, 输出[1,i]的栈操作按时间顺序执行后栈顶元素. ...

  2. Hackintosh Power Management

    Also, be aware that hibernation (suspend to disk or S4 sleep) is not supported on hackintosh. You sh ...

  3. Mac无法写入移动硬盘,Mac移动硬盘不能写

    对于使用 Mac 的朋友,有时候难免需会使用移动硬盘.一般的移动硬盘的容量都比较大,再加上国内大多数人使用的都是 Windows 系统,为了通用与方便,所以硬盘的分区一般都是 NTFS 格式的.对于 ...

  4. JAVA 中CLOB与Clob有区别

    在JAVA中CLOB与Clob是有区别的类型. (oracle.jdbc.internal.OracleCallableStatement)OracleCallableStatement能接收CLOB ...

  5. HMM模型和Viterbi算法

    https://www.cnblogs.com/Denise-hzf/p/6612212.html 一.隐含马尔可夫模型(Hidden Markov Model) 1.简介 隐含马尔可夫模型并不是俄罗 ...

  6. laravel通过Eloquent ORM实现CURD

    //Eloquent ORM public function orm1() { //all(); 返回所有数据: /*$students=Student::all(); dd($students);* ...

  7. learning docker steps(6) ----- docker 镜像加速

    http://www.docker-cn.com/registry-mirror 通过 Docker 官方镜像加速,中国区用户能够快速访问最流行的 Docker 镜像.该镜像托管于中国大陆,本地用户现 ...

  8. EHlib在数据单元中显示字段值为图形。

    -[定制网格数据单元]  在数据单元中显示字段值为图形.  TDBGridEh allows to show bitmaps from TImageList component depending o ...

  9. java 继承 初始化顺序

    面向对象三大特性: 封装,继承,多态 java 继承初始化顺序 先初始化父类对象, 在父类对象中先初始化父类属性,再初始化父类的构造方法,然后初始化子类对象,初始化子类对象的属性,初始化子类的构造方法 ...

  10. 第三视角团队:项目UML设计(团队)

    项目UML设计(团队) 团队信息 团队名:第三视角 各成员学号及姓名 姓名 学号 博客链接 张扬(组长) 031602345 http://www.cnblogs.com/sxZhangYang/p/ ...