📄 usb.c
字号:
void usb_inc_dev_use(struct usb_device *dev){ atomic_inc(&dev->refcnt);}/* ------------------------------------------------------------------------------------- * New USB Core Functions * -------------------------------------------------------------------------------------*/urb_t *usb_alloc_urb(int iso_packets){ urb_t *urb; urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!urb) { err("alloc_urb: kmalloc failed"); return NULL; } memset(urb, 0, sizeof(*urb)); spin_lock_init(&urb->lock); return urb;}/*-------------------------------------------------------------------*/void usb_free_urb(urb_t* urb){ if (urb) kfree(urb);}/*-------------------------------------------------------------------*/int usb_submit_urb(urb_t *urb){ if (urb && urb->dev) return urb->dev->bus->op->submit_urb(urb); else return -1;}/*-------------------------------------------------------------------*/int usb_unlink_urb(urb_t *urb){ if (urb && urb->dev) return urb->dev->bus->op->unlink_urb(urb); else return -1;}/*-------------------------------------------------------------------* * COMPLETION HANDLERS * *-------------------------------------------------------------------*//*-------------------------------------------------------------------* * completion handler for compatibility wrappers (sync control/bulk) * *-------------------------------------------------------------------*/static void usb_api_blocking_completion(urb_t *urb){ api_wrapper_data *awd = (api_wrapper_data *)urb->context; if (waitqueue_active(awd->wakeup)) wake_up(awd->wakeup);#if 0 else dbg("(blocking_completion): waitqueue empty!"); // even occurs if urb was unlinked by timeout...#endif}/*-------------------------------------------------------------------* * completion handler for compatibility wrappers (async bulk) * *-------------------------------------------------------------------*/static void usb_api_async_completion(urb_t *urb){ api_wrapper_data *awd = (api_wrapper_data *)urb->context; if (awd->handler) awd->handler(urb->status, urb->transfer_buffer, urb->actual_length, awd->stuff); }/*-------------------------------------------------------------------* * COMPATIBILITY STUFF * *-------------------------------------------------------------------*/// Starts urb and waits for completion or timeoutstatic int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length){ DECLARE_WAITQUEUE(wait, current); DECLARE_WAIT_QUEUE_HEAD(wqh); api_wrapper_data awd; int status; awd.wakeup = &wqh; awd.handler = 0; init_waitqueue_head(&wqh); current->state = TASK_INTERRUPTIBLE; add_wait_queue(&wqh, &wait); urb->context = &awd; status = usb_submit_urb(urb); if (status) { // something went wrong usb_free_urb(urb); remove_wait_queue(&wqh, &wait); return status; } if (urb->status == -EINPROGRESS) { while (timeout && urb->status == -EINPROGRESS) status = timeout = schedule_timeout(timeout); } else status = 1; remove_wait_queue(&wqh, &wait); if (!status) { // timeout printk("usb_control/bulk_msg: timeout\n"); usb_unlink_urb(urb); // remove urb safely status = -ETIMEDOUT; } else status = urb->status; if (actual_length) *actual_length = urb->actual_length; usb_free_urb(urb); return status;}/*-------------------------------------------------------------------*/// returns status (negative) or length (positive)int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout){ urb_t *urb; int retv; int length; urb = usb_alloc_urb(0); if (!urb) return -ENOMEM; FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len, /* build urb */ (usb_complete_t)usb_api_blocking_completion,0); retv = usb_start_wait_urb(urb, timeout, &length); if (retv < 0) return retv; else return length; }/*-------------------------------------------------------------------*/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){ devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL); int ret; if (!dr) return -ENOMEM; dr->requesttype = requesttype; dr->request = request; dr->value = cpu_to_le16p(&value); dr->index = cpu_to_le16p(&index); dr->length = cpu_to_le16p(&size); //dbg("usb_control_msg"); ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); kfree(dr); return ret;}/*-------------------------------------------------------------------*//* compatibility wrapper, builds bulk urb, and waits for completion *//* synchronous behavior */int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout){ urb_t *urb; if (len < 0) return -EINVAL; urb=usb_alloc_urb(0); if (!urb) return -ENOMEM; FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len, /* build urb */ (usb_complete_t)usb_api_blocking_completion,0); return usb_start_wait_urb(urb,timeout,actual_length);}/*-------------------------------------------------------------------*/void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id){ urb_t *urb; api_wrapper_data *awd; if (!(urb=usb_alloc_urb(0))) return NULL; if (!(awd = kmalloc(sizeof(api_wrapper_data), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) { kfree(urb); return NULL; } /* build urb */ FILL_BULK_URB(urb, dev, pipe, data, len, (usb_complete_t)usb_api_async_completion, awd); awd->handler=handler; awd->stuff=dev_id; if (usb_submit_urb(urb) < 0) { kfree(awd); kfree(urb); return NULL; } return urb;}// compatibility wrapper. Remove urb only if it is called before the// transaction's completion interrupt. If called from within the// completion handler (urb->completed==1), it does nothing, since the// qh is already removed int usb_terminate_bulk(struct usb_device *dev, void *first){ urb_t *urb=(urb_t*)first; dbg("usb_terminate_bulk: urb:%p",urb); if (!urb) // none found? there is nothing to remove! return -ENODEV; usb_unlink_urb(urb); kfree(urb->context); kfree(urb); return USB_ST_NOERROR;}/* * usb_release_bandwidth(): * * called to release an interrupt pipe's bandwidth (in microseconds) */void usb_release_bandwidth(struct usb_device *dev, int bw_alloc){ dev->bus->bandwidth_allocated -= bw_alloc; dev->bus->bandwidth_int_reqs--; dbg("bw_alloc reduced to %d for %d requesters", dev->bus->bandwidth_allocated, dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);}static void irq_callback(urb_t *urb){ struct irq_wrapper_data *wd = (struct irq_wrapper_data *)urb->context; if (!wd->handler) return;#if 0 // verbose... if (!wd->handler(urb->status, urb->transfer_buffer, urb->actual_length, wd->context)) err("legacy irq callback returned 0!!!");#else wd->handler(urb->status, urb->transfer_buffer, urb->actual_length, wd->context);#endif}int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle){ long bustime; int ret; struct irq_wrapper_data *wd; urb_t *urb; unsigned int maxsze = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); *handle = NULL; //dbg("irq: dev:%p pipe:%08X handler:%p period:%d dev_id:%p max:%d", dev, pipe, handler, period, dev_id, maxsze); /* Check host controller's bandwidth for this int. request. */ bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0, usb_maxpacket(dev, pipe, usb_pipeout(pipe))); bustime = NS_TO_US(bustime); /* work in microseconds */ if (check_bandwidth_alloc (dev->bus->bandwidth_allocated, bustime)) return -EUSERS; // no bandwidth left if (!maxsze || !usb_pipeint(pipe)) return -EINVAL; if (!(urb = usb_alloc_urb(0))) return -ENOMEM; if (!(wd = kmalloc(sizeof(struct irq_wrapper_data), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) { kfree(urb); return -ENOMEM; } if (!(urb->transfer_buffer = kmalloc(maxsze, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL))) { kfree(urb); kfree(wd); return -ENOMEM; } wd->handler=handler; wd->context=dev_id; urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer_length = urb->actual_length = maxsze; urb->interval = period; urb->context = wd; urb->complete = irq_callback; if ((ret = usb_submit_urb(urb)) < 0) { kfree(wd); kfree(urb->transfer_buffer); kfree(urb); return ret; } *handle = urb; /* Claim the USB bandwidth if no error. */ if (!ret) { dev->bus->bandwidth_allocated += bustime; dev->bus->bandwidth_int_reqs++; dbg("bw_alloc bumped to %d for %d requesters", dev->bus->bandwidth_allocated, dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); } return ret;}int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe){ long bustime; int err; urb_t *urb = (urb_t*)handle; if (!urb) return -EBADF; err=usb_unlink_urb(urb); kfree(urb->context); kfree(urb->transfer_buffer); kfree(urb); /* Return the USB bandwidth if no error. */ if (!err) { bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0, usb_maxpacket(dev, pipe, usb_pipeout(pipe))); bustime = NS_TO_US(bustime); /* work in microseconds */ usb_release_bandwidth(dev, bustime); } return err;}/* * usb_get_current_frame_number() * * returns the current frame number for the parent USB bus/controller * of the given USB device. */int usb_get_current_frame_number(struct usb_device *usb_dev){ return usb_dev->bus->op->get_frame_number (usb_dev);}/*-------------------------------------------------------------------*/static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size){ struct usb_descriptor_header *header; unsigned char *begin; int parsed = 0, len, numskipped; header = (struct usb_descriptor_header *)buffer; /* Everything should be fine being passed into here, but we sanity */ /* check JIC */ if (header->bLength > size) { err("ran out of descriptors parsing"); return -1; } if (header->bDescriptorType != USB_DT_ENDPOINT) { warn("unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X", endpoint->bDescriptorType, USB_DT_ENDPOINT); return parsed; } if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) memcpy(endpoint, buffer, USB_DT_ENDPOINT_AUDIO_SIZE); else memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE); le16_to_cpus(&endpoint->wMaxPacketSize); buffer += header->bLength; size -= header->bLength; parsed += header->bLength; /* Skip over the rest of the Class Specific or Vendor Specific */ /* descriptors */ begin = buffer; numskipped = 0; while (size >= sizeof(struct usb_descriptor_header)) { header = (struct usb_descriptor_header *)buffer; if (header->bLength < 2) { err("invalid descriptor length of %d", header->bLength); return -1; } /* If we find another descriptor which is at or below us */ /* in the descriptor heirarchy then we're done */ if ((header->bDescriptorType == USB_DT_ENDPOINT) || (header->bDescriptorType == USB_DT_INTERFACE) || (header->bDescriptorType == USB_DT_CONFIG) || (header->bDescriptorType == USB_DT_DEVICE)) break; dbg("skipping descriptor 0x%X", header->bDescriptorType); numskipped++; buffer += header->bLength; size -= header->bLength; parsed += header->bLength; } if (numskipped) dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); /* Copy any unknown descriptors into a storage area for drivers */ /* to later parse */ len = (int)(buffer - begin); if (!len) { endpoint->extra = NULL; endpoint->extralen = 0; return parsed; } endpoint->extra = kmalloc(len, GFP_KERNEL); if (!endpoint->extra) { err("couldn't allocate memory for endpoint extra descriptors"); endpoint->extralen = 0; return parsed; } memcpy(endpoint->extra, begin, len); endpoint->extralen = len; return parsed;}static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size){ int i, len, numskipped, retval, parsed = 0; struct usb_descriptor_header *header; struct usb_interface_descriptor *ifp; unsigned char *begin; interface->act_altsetting = 0; interface->num_altsetting = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -