usb_control_msg
来源:互联网 发布:手绘板绘图软件 编辑:程序博客网 时间:2024/05/16 09:16
调用实例
static int set_port_feature(struct usb_device *hdev, int port1, int feature)
{
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature,
port1, NULL, 0, 1000);
}
{
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature,
port1, NULL, 0, 1000);
}
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)
{
struct usb_ctrlrequest * dr;
int ret;
dr = kmalloc( sizeof ( struct usb_ctrlrequest), GFP_NOIO);
if ( ! dr)
return - ENOMEM;
dr - > bRequestType = requesttype;
dr - > bRequest = request;
dr - > wValue = cpu_to_le16(value);
dr - > wIndex = cpu_to_le16(index);
dr - > wLength = cpu_to_le16(size);
/* dbg("usb_control_msg"); */
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
EXPORT_SYMBOL_GPL(usb_control_msg);
__u8 requesttype, __u16 value, __u16 index, void * data,
__u16 size, int timeout)
{
struct usb_ctrlrequest * dr;
int ret;
dr = kmalloc( sizeof ( struct usb_ctrlrequest), GFP_NOIO);
if ( ! dr)
return - ENOMEM;
dr - > bRequestType = requesttype;
dr - > bRequest = request;
dr - > wValue = cpu_to_le16(value);
dr - > wIndex = cpu_to_le16(index);
dr - > wLength = cpu_to_le16(size);
/* dbg("usb_control_msg"); */
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
EXPORT_SYMBOL_GPL(usb_control_msg);
static int usb_internal_control_msg(struct usb_device *usb_dev,
unsigned int pipe,
struct usb_ctrlrequest *cmd,
void *data, int len, int timeout)
{
struct urb *urb;
int retv;
int length;
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
unsigned int pipe,
struct usb_ctrlrequest *cmd,
void *data, int len, int timeout)
{
struct urb *urb;
int retv;
int length;
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;
urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
printk(KERN_ERR "alloc_urb: kmalloc failed\n");
return NULL;
}
usb_init_urb(urb);
return urb;
}
EXPORT_SYMBOL_GPL(usb_alloc_urb);
{
struct urb *urb;
urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
printk(KERN_ERR "alloc_urb: kmalloc failed\n");
return NULL;
}
usb_init_urb(urb);
return urb;
}
EXPORT_SYMBOL_GPL(usb_alloc_urb);
static inline void usb_fill_control_urb(struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
{
urb->dev = dev;
urb->pipe = pipe;
urb->setup_packet = setup_packet;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete_fn;
urb->context = context;
}
struct usb_device *dev,
unsigned int pipe,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete_fn,
void *context)
{
urb->dev = dev;
urb->pipe = pipe;
urb->setup_packet = setup_packet;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
urb->complete = complete_fn;
urb->context = context;
}
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
struct api_context ctx;
unsigned long expire;
int retval;
init_completion(&ctx.done);
urb->context = &ctx;
urb->actual_length = 0;
retval = usb_submit_urb(urb, GFP_NOIO);
if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
if (!wait_for_completion_timeout(&ctx.done, expire)) {
usb_kill_urb(urb);
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%u/%u\n",
current->comm,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
} else
retval = ctx.status;
out:
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
return retval;
}
{
struct api_context ctx;
unsigned long expire;
int retval;
init_completion(&ctx.done);
urb->context = &ctx;
urb->actual_length = 0;
retval = usb_submit_urb(urb, GFP_NOIO);
if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
if (!wait_for_completion_timeout(&ctx.done, expire)) {
usb_kill_urb(urb);
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%u/%u\n",
current->comm,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
} else
retval = ctx.status;
out:
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
return retval;
}
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int xfertype, max;
struct usb_device *dev;
struct usb_host_endpoint *ep;
int is_out;
usb
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
dev = urb->dev;
if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
return -ENODEV;
/* For now, get the endpoint from the pipe. Eventually drivers
* will be required to set urb->ep directly and we will eliminate
* urb->pipe.
*/
ep = usb_pipe_endpoint(dev, urb->pipe);
{
int xfertype, max;
struct usb_device *dev;
struct usb_host_endpoint *ep;
int is_out;
usb
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
dev = urb->dev;
if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
return -ENODEV;
/* For now, get the endpoint from the pipe. Eventually drivers
* will be required to set urb->ep directly and we will eliminate
* urb->pipe.
*/
ep = usb_pipe_endpoint(dev, urb->pipe);
通过pipe和device对象,得到pipe对应的device中的endpoint
static inline struct usb_host_endpoint *
usb_pipe_endpoint(struct usb_device *dev, unsigned int pipe)
{
struct usb_host_endpoint **eps;
eps = usb_pipein(pipe) ? dev->ep_in : dev->ep_out;//
usb_pipe_endpoint(struct usb_device *dev, unsigned int pipe)
{
struct usb_host_endpoint **eps;
eps = usb_pipein(pipe) ? dev->ep_in : dev->ep_out;//
return eps[usb_pipeendpoint(pipe)];
}
}
在2.0规范Table 9-13. Standard Endpoint Descriptor中,描述了设备中endpoint的地址,bEndpointAddress的Bit 3...0: 表示The endpoint number,一个设备最多只能支持15个IN和15个OUT endpoint,0端点比较特殊,即支持IN又支持OUT,所以一个USB设备IN和OUT的端点数都是16个
struct usb_device {
......
struct usb_host_endpoint *ep_in[16];
struct usb_host_endpoint *ep_out[16];
......
}
......
struct usb_host_endpoint *ep_in[16];
struct usb_host_endpoint *ep_out[16];
......
}
表示设备或接口设置中包含的endpoint
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct list_head urb_list;
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
};
struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct list_head urb_list;
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
};
if (!ep)return -ENOENT;
urb->ep = ep; //将URB要发送到的endpoint捆绑到URB对象中的endpoint指针
urb->status = -EINPROGRESS;
urb->actual_length = 0; //传输还没开始,实际传输的数据长度是0
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/ //给URB绑定了ep后,要检查ep类型
xfertype = usb_endpoint_type(&ep->desc);
if (xfertype == USB_ENDPOINT_XFER_CONTROL) { //是否是控制传输?是:通过传进的参数构造的setup_packet判断端点方向;否:通过ep描述符判断
struct usb_ctrlrequest *setup =
(struct usb_ctrlrequest *) urb->setup_packet; //setup_packet是usb_control_msg传进的参数封装形成dr,格式同usb_ctrlrequest,被强制转换成usb_ctrlrequest类型
if (!setup)
return -ENOEXEC;
is_out = !(setup->bRequestType & USB_DIR_IN) ||
!setup->wLength;
} else {
is_out = usb_endpoint_dir_out(&ep->desc); //如果不是控制传输,则没有setup_packet,则根据ep的描述符判断ep类型
}
/* Clear the internal flags and cache the direction for later use */
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
URB_DMA_SG_COMBINED); //把如上的所有位清0
urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
if (xfertype != USB_ENDPOINT_XFER_CONTROL && //在设备被配置前,只能发送控制传输URB,其它传输类型必须在设备配置完成后才能发送URB
dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
max = usb_endpoint_maxp(&ep->desc); //每个transaction的大小
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__func__, max);
return -EMSGSIZE;
}
/* periodic transfers limit size per frame/uframe,
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* SuperSpeed isoc endpoints have up to 16 bursts of up to
* 3 packets each
*/
(struct usb_ctrlrequest *) urb->setup_packet; //setup_packet是usb_control_msg传进的参数封装形成dr,格式同usb_ctrlrequest,被强制转换成usb_ctrlrequest类型
if (!setup)
return -ENOEXEC;
is_out = !(setup->bRequestType & USB_DIR_IN) ||
!setup->wLength;
} else {
is_out = usb_endpoint_dir_out(&ep->desc); //如果不是控制传输,则没有setup_packet,则根据ep的描述符判断ep类型
}
/* Clear the internal flags and cache the direction for later use */
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
URB_DMA_SG_COMBINED); //把如上的所有位清0
urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
if (xfertype != USB_ENDPOINT_XFER_CONTROL && //在设备被配置前,只能发送控制传输URB,其它传输类型必须在设备配置完成后才能发送URB
dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
max = usb_endpoint_maxp(&ep->desc); //每个transaction的大小
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__func__, max);
return -EMSGSIZE;
}
/* periodic transfers limit size per frame/uframe,
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* SuperSpeed isoc endpoints have up to 16 bursts of up to
* 3 packets each
*/
/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
struct usb_ss_ep_comp_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bMaxBurst;
struct usb_ss_ep_comp_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bMaxBurst;
//(ep burst支持的最大packets数,0~15==>1~16个packets)Table 9-22. SuperSpeed Endpoint Companion Descriptor
__u8 bmAttributes;
__u8 bmAttributes;
__le16 wBytesPerInterval;
} __attribute__ ((packed));
//最大字节数可以按以下方式计算:wMaxPacketSize * (bMaxBurst +1) * (Mult + 1)
int burst = 1 + ep->ss_ep_comp.bMaxBurst; //终结点伴随描述符的 bMaxBurst 字段。此值表示单个突发事务中可以存在的 wMaxPacketSize 的盘的数目。一个突发事务内最多可有 16 个盘(由 0 到 15 指示)
int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes); //终结点伴随描述符的 Isochronous.Mult 字段。在 SuperSpeed 常时等量传输中,其他事务(与高速设备非常类似)指的是突发事务。Mult 值指示终结点支持的最大突发事务数。一个服务时间间隔内最多可有三个突发事务(由 0 到 2 指示)
max *= burst;
max *= mult;
}
//参考http://technet.microsoft.com/zh-cn/library/hh406225(v=vs.85).aspx
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) {
int mult = 1 + ((max >> 11) & 0x03); // High-Speed, High Bandwidth Endpoints
每微帧最多支持三个
high-speed transactions,取支持的
high-speed transactions数 max &= 0x07ff; //低11位表示每个high-speed transaction的最大数据量(byte)
max *= mult;
}
10..0 Maximum size of data payload in bytes
12..11 Number of transactions per microframe
15..13 Reserved,must be set to zero
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) { //number_of_packets表示一个URB里有过少个等时传输,每个等时传输也称作一个packet,用struct usb_iso_packet_descriptor iso_frame_desc[]表示。
len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max) //如果哪个等时传输中没有数据,如果预算传输的长度比计算出来的max还大,则返回,并将实际传输的数据长度置0.
return -EMSGSIZE;
urb->iso_frame_desc[n].status = -EXDEV; //-EXDEV表示这次等时传输仅仅部分完成
urb->iso_frame_desc[n].actual_length = 0;
}
}
/* the I/O buffer must be mapped/unmapped, except when length=0 */
if (urb->transfer_buffer_length > INT_MAX) //没有看懂???
return -EMSGSIZE;
#ifdef DEBUG
/* stuff that drivers shouldn't do, but which shouldn't
* cause problems in HCDs if they get it wrong.
*/
{
unsigned int allowed;
static int pipetypes[4] = {
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
};
/* Check that the pipe's type matches the endpoint's type */
if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
usb_pipetype(urb->pipe), pipetypes[xfertype]);
/* Check against a simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
URB_FREE_BUFFER);
switch (xfertype) {
case USB_ENDPOINT_XFER_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP;
break;
}
allowed &= urb->transfer_flags;
/* warn if submitter gave bogus flags */
if (allowed != urb->transfer_flags)
dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
urb->transfer_flags, allowed);
}
#endif
/*
* Force periodic transfer intervals to be legal values that are
* a power of two (so HCDs don't need to).
*
* FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
switch (xfertype) { //是关于interval的,所以只涉及ISO和INT
case USB_ENDPOINT_XFER_ISOC:
case USB_ENDPOINT_XFER_INT:
/* too small? */
switch (dev->speed) {
case USB_SPEED_WIRELESS:
if (urb->interval < 6)
return -EINVAL;
break;
default:
if (urb->interval <= 0)
return -EINVAL;
break;
}
/* too big? */
switch (dev->speed) {
case USB_SPEED_SUPER: /* units are 125us */
/* Handle up to 2^(16-1) microframes */
if (urb->interval > (1 << 15))
return -EINVAL;
max = 1 << 15;
break;
case USB_SPEED_WIRELESS:
if (urb->interval > 16)
return -EINVAL;
break;
case USB_SPEED_HIGH: /* units are microframes */
/* NOTE usb handles 2^15 */
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
max = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
/* NOTE ohci only handles up to 32 */
max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
/* NOTE usb and ohci handle up to 2^15 */
max = 1024;
}
break;
default:
return -EINVAL;
}
if (dev->speed != USB_SPEED_WIRELESS) {
/* Round down to a power of 2, no more than max */
urb->interval = min(max, 1 << ilog2(urb->interval));
}
}
return usb_hcd_submit_urb(urb, mem_flags);
}
EXPORT_SYMBOL_GPL(usb_submit_urb);
if (len < 0 || len > max) //如果哪个等时传输中没有数据,如果预算传输的长度比计算出来的max还大,则返回,并将实际传输的数据长度置0.
return -EMSGSIZE;
urb->iso_frame_desc[n].status = -EXDEV; //-EXDEV表示这次等时传输仅仅部分完成
urb->iso_frame_desc[n].actual_length = 0;
}
}
/* the I/O buffer must be mapped/unmapped, except when length=0 */
if (urb->transfer_buffer_length > INT_MAX) //没有看懂???
return -EMSGSIZE;
#ifdef DEBUG
/* stuff that drivers shouldn't do, but which shouldn't
* cause problems in HCDs if they get it wrong.
*/
{
unsigned int allowed;
static int pipetypes[4] = {
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
};
/* Check that the pipe's type matches the endpoint's type */
if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
usb_pipetype(urb->pipe), pipetypes[xfertype]);
/* Check against a simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
URB_FREE_BUFFER);
switch (xfertype) {
case USB_ENDPOINT_XFER_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP;
break;
}
allowed &= urb->transfer_flags;
/* warn if submitter gave bogus flags */
if (allowed != urb->transfer_flags)
dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
urb->transfer_flags, allowed);
}
#endif
/*
* Force periodic transfer intervals to be legal values that are
* a power of two (so HCDs don't need to).
*
* FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
switch (xfertype) { //是关于interval的,所以只涉及ISO和INT
case USB_ENDPOINT_XFER_ISOC:
case USB_ENDPOINT_XFER_INT:
/* too small? */
switch (dev->speed) {
case USB_SPEED_WIRELESS:
if (urb->interval < 6)
return -EINVAL;
break;
default:
if (urb->interval <= 0)
return -EINVAL;
break;
}
/* too big? */
switch (dev->speed) {
case USB_SPEED_SUPER: /* units are 125us */
/* Handle up to 2^(16-1) microframes */
if (urb->interval > (1 << 15))
return -EINVAL;
max = 1 << 15;
break;
case USB_SPEED_WIRELESS:
if (urb->interval > 16)
return -EINVAL;
break;
case USB_SPEED_HIGH: /* units are microframes */
/* NOTE usb handles 2^15 */
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
max = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
/* NOTE ohci only handles up to 32 */
max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
/* NOTE usb and ohci handle up to 2^15 */
max = 1024;
}
break;
default:
return -EINVAL;
}
if (dev->speed != USB_SPEED_WIRELESS) {
/* Round down to a power of 2, no more than max */
urb->interval = min(max, 1 << ilog2(urb->interval));
}
}
return usb_hcd_submit_urb(urb, mem_flags);
}
EXPORT_SYMBOL_GPL(usb_submit_urb);
/*-------------------------------------------------------------------------*/
/* may be called in any context with a valid urb->dev usecount
* caller surrenders "ownership" of urb
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
*/
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
/* increment urb's reference count as part of giving it to the HCD
* (which will control it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
usb_get_urb(urb);
atomic_inc(&urb->use_count);
atomic_inc(&urb->dev->urbnum);
usbmon_urb_submit(&hcd->self, urb);
/* NOTE requirements on root-hub callers (usbfs and the hub
* driver, for now): URBs' urb->transfer_buffer must be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data. Also, control
* URBs must be submitted in process context with interrupts
* enabled.
*/
if (is_root_hub(urb->dev)) {
status = rh_urb_enqueue(hcd, urb);
} else {
status = map_urb_for_dma(hcd, urb, mem_flags);
if (likely(status == 0)) {
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
if (unlikely(status))
unmap_urb_for_dma(hcd, urb);
}
}
if (unlikely(status)) {
usbmon_urb_submit_error(&hcd->self, urb, status);
urb->hcpriv = NULL;
INIT_LIST_HEAD(&urb->urb_list);
atomic_dec(&urb->use_count);
atomic_dec(&urb->dev->urbnum);
if (atomic_read(&urb->reject))
wake_up(&usb_kill_urb_queue);
usb_put_urb(urb);
}
return status;
}
/* may be called in any context with a valid urb->dev usecount
* caller surrenders "ownership" of urb
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
*/
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
/* increment urb's reference count as part of giving it to the HCD
* (which will control it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
usb_get_urb(urb);
atomic_inc(&urb->use_count);
atomic_inc(&urb->dev->urbnum);
usbmon_urb_submit(&hcd->self, urb);
/* NOTE requirements on root-hub callers (usbfs and the hub
* driver, for now): URBs' urb->transfer_buffer must be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data. Also, control
* URBs must be submitted in process context with interrupts
* enabled.
*/
if (is_root_hub(urb->dev)) {
status = rh_urb_enqueue(hcd, urb);
} else {
status = map_urb_for_dma(hcd, urb, mem_flags);
if (likely(status == 0)) {
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
if (unlikely(status))
unmap_urb_for_dma(hcd, urb);
}
}
if (unlikely(status)) {
usbmon_urb_submit_error(&hcd->self, urb, status);
urb->hcpriv = NULL;
INIT_LIST_HEAD(&urb->urb_list);
atomic_dec(&urb->use_count);
atomic_dec(&urb->dev->urbnum);
if (atomic_read(&urb->reject))
wake_up(&usb_kill_urb_queue);
usb_put_urb(urb);
}
return status;
}
- usb_control_msg
- usb_control_msg
- usb_control_msg函数用法
- usb_control_msg()各参数详解
- usb_control_msg函数用法
- usb_control_msg函数用法
- usb_control_msg函数用法
- usb_control_msg(drivers/usb/core/message.c)
- usb_control_msg() -- 从设备读取各种信息
- 调用 usb_control_msg 返回错误值 -32, Broken pipe, 对 hidraw write时 返回错误值 -32, Broken pipe
- ubuntu下运行eclipse开发c++
- HTML5里面的知识:Canvas简单与KineticJS滚动条!
- DataTable记录的更改【删除Gridview记录篇】
- SVN服务器搭建和使用(一)
- 停止预览时调用Camera.release(), 出现Method called after release()异常问题原因及解决办法
- usb_control_msg
- 10月15日面试之某华
- 初学Linux_Ubuntu 13.04安装与配置
- java项目打包(尤其用到fatjar插件)
- Error while registering Oracle JDBC Diagnosability MBean.
- analysis of ShadowMapping Sample with GLSL
- Hibernate--hibernate.hbm2ddl.auto配置详解
- android adb shell 命令大全
- flash and vc++制作精美界面程序