Linux USB gadget設(shè)備驅(qū)動(dòng)解析(4)--編寫一個(gè)gadget驅(qū)動(dòng)
value = min(w_length, (u16) sizeof device_desc);
memcpy(req->buf, device_desc, value);
break;
case USB_DT_CONFIG: //獲取配置,注意:會(huì)根據(jù)fs_loopback_function讀取到接口、端點(diǎn)描述符,注意通過config_buf完成讀取數(shù)據(jù)及數(shù)量的統(tǒng)計(jì)。
value = config_buf(gadget, req->buf,
w_value >> 8,
w_value 0xff);
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
value = usb_gadget_get_string(stringtab,
w_value 0xff, req->buf);
if (value >= 0)
value = min(w_length, (u16) value);
break;
}
break;
case USB_REQ_SET_CONFIGURATION:
if (ctrl->bRequestType != 0)
goto unknown;
spin_lock(dev->lock);
value = zero_set_config(dev, w_value);//激活相應(yīng)的端點(diǎn)
spin_unlock(dev->lock);
break;
default:
unknown:
printk(
unknown control req%02x.%02x v%04x i%04x l%dn,
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
}
/* respond with data transfer before status phase */
if (value >= 0) {
req->length = value;
req->zero = value w_length;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);//通過端點(diǎn)0完成setup
if (value 0) {
printk(ep_queue --> %dn, value);
req->status = 0;
zero_setup_complete(gadget->ep0, req);
}
}
/* device either stalls (value 0) or reports success */
return value;
}
static void zero_unbind(struct usb_gadget *gadget) //解除綁定
{
struct zero_dev *dev = get_gadget_data(gadget);
printk(unbindn);
unregister_chrdev_region (MKDEV (usb_zero_major, 0), 1);
cdev_del ((dev->cdev));
/* we've already been disconnected ... no i/o is active */
if (dev->req) {
dev->req->length = USB_BUFSIZ;
free_ep_req(gadget->ep0, dev->req);
}
kfree(dev);
set_gadget_data(gadget, NULL);
}
static int __init zero_bind(struct usb_gadget *gadget) //綁定過程
{
struct zero_dev *dev;
struct usb_ep *ep;
int gcnum;
usb_ep_autoconfig_reset(gadget);
ep = usb_ep_autoconfig(gadget, fs_sink_desc);//根據(jù)端點(diǎn)描述符及控制器端點(diǎn)情況,分配一個(gè)合適的端點(diǎn)。
if (!ep)
goto enomem;
EP_OUT_NAME = ep->name; //記錄名稱
gcnum = usb_gadget_controller_number(gadget);//獲得控制器代號(hào)
if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);//賦值設(shè)備描述符
else {
pr_warning(%s: controller '%s' not recognizedn,
shortname, gadget->name);
device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL); //分配設(shè)備結(jié)構(gòu)體
if (!dev)
return -ENOMEM;
spin_lock_init(dev->lock);
dev->gadget = gadget;
set_gadget_data(gadget, dev);
dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);//分配一個(gè)請(qǐng)求
if (!dev->req)
goto enomem;
dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
if (!dev->req->buf)
goto enomem;
dev->req->complete = zero_setup_complete;
dev->out_ep=ep; //記錄端點(diǎn)(就是接收host端數(shù)據(jù)的端點(diǎn))
printk(name=%sn,dev->out_ep->name); //打印出這個(gè)端點(diǎn)的名稱
ep->driver_data=dev;
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
usb_gadget_set_selfpowered(gadget);
gadget->ep0->driver_data = dev;
snprintf(manufacturer, sizeof manufacturer, %s %s with %s,
init_utsname()->sysname, init_utsname()->release,
gadget->name);
/**************************字符設(shè)備注冊(cè)*******************/
dev_t usb_zero_dev = MKDEV (usb_zero_major, 0);
int result = register_chrdev_region (usb_zero_dev, 1, usb_zero);
if (result 0)
{
printk (KERN_NOTICE Unable to get usb_transfer region, error %dn,result);
return 0;
}
usb_zero_setup_cdev (dev, 0);
return 0;
enomem:
zero_unbind(gadget);
return -ENOMEM;
}
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver zero_driver = { //gadget驅(qū)動(dòng)的核心數(shù)據(jù)結(jié)構(gòu)
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
#endif
.function = (char *) longname,
.bind = zero_bind,
.unbind = __exit_p(zero_unbind),
.setup = zero_setup,
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)linux相關(guān)文章:linux教程
評(píng)論