-
USB
设备驱动程序
-USB Gadget
Driver(4)
Gadget
功能层
Gadget
功能层完成
USB
设备的具体功
能,其表现的形式各不相同,如键盘、鼠标、存储和网卡等
等。
功能层不仅涉及到
Gadget
驱动相关的内容,
还涉及到其
功能相关的内核子系统
。如存储还涉及到内核存储子系统,
网卡还涉及到网络驱动子系统。因此,
Gadget
功能的代码非
常复杂。这里以
zero.c
为例,这个模块只是简单地将接收的
数据回显回去。
一、数据结构
首先需要实现
usb_compos
ite_driver
函数集:
static struct
usb_composite_driver zero_driver =
{
.name =
.dev =
&device_desc,
.strings =
dev_strings,
.bind =
zero_bind,
.unbind =
zero_unbind,
.suspend =
zero_suspend,
.resume =
zero_resume,
};
二、主要函数
这个模块的实现就是这
么简单:
static int
__init init(void)
{
return
< br>usb_composite_register(&zero_driver);
}
module_init(init);
static void
__exit cleanup(void)
{
usb_composite_unregister(&a
mp;zero_driver);
}
<
/p>
Bind
函数是功能层需要实现与设备层关联的重要函
数:
static int __init zero_bind(struct
usb_composite_dev
*cdev)
{
int
gcnum;
struct usb_gadget *gadget =
cdev->gadget; //Gadget
设备
int id;
/*
Allocate string descriptor numbers ...
note that string
* contents can be
overridden
by the composite_dev glue.
*/
/*
分配字符串描述符的
id
,并赋值给设备描述
符中字符串索引
*/
id = usb_string_id(cdev);
strings_dev[STRING_MANUFACTURER_IDX].id
= id;
device_acturer = id;
id =
usb_string_id(cdev); i
strings_dev[STRING_PRODUCT_IDX].id =
id;
device_ct = id;
id =
usb_string_id(cdev);
strings_dev[STRING_SERIAL_IDX].id = id;
device_lNumber
= id;
p>
/*
设置挂起
后,设备自动恢复的定时器<
/p>
*/
setup_timer(&autoresume_timer,
zero_autoresume,
(unsigned long) cdev);
/*
核心代码,实现
功能
*/
if (loopdefault)
{
loopback_add(cdev,
autoresume != 0);
//
数据简单回显功能
if
(!gadget_is_sh(gadget))
sourcesink_add(cdev, autoresume != 0);
}
else
{
sourcesink_add(cdev,
autoresume != 0);
if
(!gadget_is_sh(gadget))
loopback_add(cdev, autoresume != 0);
}
/*
初始化设备描述符
*/
gcnum =
usb_gadget_controller_number(gadget);
if
(gcnum >= 0)
device_ice = cpu_to_le16(0x0200 +
gcnum);
else {
device_ice
=
cpu_to_le16(0x9999);
}
return
0;
}
/*
增加数据简单回显功能
*/
int __init
loopback_add(struct usb_composite_dev
*cdev, bool
autoresume)
{
int id;
/*<
/p>
获取字符串描述符
id
索引
*/
id = usb_string_id(cdev);
strings_loopback[0].id = id;
loopback_face = id;
loopback_guration = id;
/* support autoresume for
remote wakeup testing */
if
(autoresume)
sourcesink_ibutes |=
USB_CONFIG_ATT_WAKEUP;
/* support OTG
systems */
if
(gadget_is_otg(cdev->gadget))
{
loopback_ptors = otg_desc;
loopback_ibutes |=
USB_CONFIG_ATT_WAKEUP;
}
return
usb_add_config(cdev,
&loopback_driver);
//
增加一个配
置
}
/*loopback
配置
*/
static struct
usb_configuration
loopback_driver = {
.label
=
.strings =
loopback_strings,
.bind =
loopback_bind_config,
.bC
onfigurationValue =
2,
.bmAttributes =
USB_CONFIG_ATT_SELFPOWER,
/*
.iConfiguration = DYNAMIC */
};
将增加配置的
usb_add_config
< br>函数中会调用其
bind
函数,即
loopback_bind_config
函数,来分配这个配置所需要的资源。<
/p>
struct f_loopback {
struct
usb_function function;
struct
usb_ep
*in_ep;
struct usb_ep
*out_ep;
};
static int __init
loopback_bind_config(struct
usb_configuration *c)
{
struct
f_loopback *loop;
int
status;
loop =
kzalloc(sizeof *loop, GFP_KERNEL); //
p>
分配一个
loop
结构
if (!loop)
return -ENOMEM;
/*
初始化
一个功能
*/
loop-> =
loop->ptors =
fs_loopback_descs;
loop-> = loopback_bind;
loop-> = loopback_unbind;
loop->_alt =
loopback_set_alt;
loop->e = loopback_disable;
status =
usb_add_function(c, &loop->function);
//
加入
这个功能
if (status)
kfree(loop);
return status;
}
<
/p>
在
usb_add_function
函
数中,
又会调用这个功能的
bind
函
数,
即
loopback_bind
函
数:
static int __init
loopback_bind(struct usb_configuration
*c, struct usb_function
*f)
{
struct usb_composite_dev
*cdev = c->cdev;
struct
f_loopback *loop =
func_to_loop(f);
int id;
/* allocate
interface ID(s) */
id = usb_interface_id(c,
f); //
分配一个接口
id
if (id < 0)
return
id;
loopback_faceNumber
= id;
/* allocate
endpoints */
/*
返回一个输入端点
*/
loop->in_ep =
usb_ep_autoconfig(cdev->gadget,
&fs_loop_source_desc);
if
(!loop->in_ep)
{
autoco
nf_fail:
ERROR(cdev,
cdev->gadget->name);
return -ENODEV;
}
loop->in_ep->driver_data = cdev;
/* claim */