📄 usb.c
字号:
return;
}
if (!(buf = malloc (256))) {
free (envp);
printf ("enomem2");
return;
}
/* only one standardized param to hotplug command: type */
argv [0] = hotplug_path;
argv [1] = "usb";
argv [2] = 0;
/* minimal command environment */
envp [i++] = "HOME=/";
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
#ifdef DEBUG
/* hint that policy agent should enter no-stdout debug mode */
envp [i++] = "DEBUG=kernel";
#endif
/* extensible set of named bus-specific parameters,
* supporting multiple driver selection algorithms.
*/
scratch = buf;
/* action: add, remove */
envp [i++] = scratch;
scratch += sprintf (scratch, "ACTION=%s", verb) + 1;
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
* even act as usermode drivers.
*
* FIXME reduce hardwired intelligence here
*/
envp [i++] = "DEVFS=/proc/bus/usb";
envp [i++] = scratch;
scratch += sprintf (scratch, "DEVICE=/proc/bus/usb/%03d/%03d",
dev->bus->busnum, dev->devnum) + 1;
#endif
/* per-device configuration hacks are common */
envp [i++] = scratch;
scratch += sprintf (scratch, "PRODUCT=%x/%x/%x",
dev->descriptor.idVendor,
dev->descriptor.idProduct,
dev->descriptor.bcdDevice) + 1;
/* class-based driver binding models */
envp [i++] = scratch;
scratch += sprintf (scratch, "TYPE=%d/%d/%d",
dev->descriptor.bDeviceClass,
dev->descriptor.bDeviceSubClass,
dev->descriptor.bDeviceProtocol) + 1;
if (dev->descriptor.bDeviceClass == 0) {
int alt = dev->actconfig->interface [0].act_altsetting;
/* a simple/common case: one config, one interface, one driver
* with current altsetting being a reasonable setting.
* everything needs a smart agent and usbdevfs; or can rely on
* device-specific binding policies.
*/
envp [i++] = scratch;
scratch += sprintf (scratch, "INTERFACE=%d/%d/%d",
dev->actconfig->interface [0].altsetting [alt].bInterfaceClass,
dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass,
dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol)
+ 1;
/* INTERFACE-0, INTERFACE-1, ... ? */
}
envp [i++] = 0;
/* assert: (scratch - buf) < sizeof buf */
/* NOTE: user mode daemons can call the agents too */
printf ("kusbd: %s %s %d", argv [0], verb, dev->devnum);
value = call_usermodehelper (argv [0], argv, envp);
free (buf);
free (envp);
if (value != 0)
printf ("kusbd policy returned 0x%d", value);
}
#else
static inline void
call_policy (char *verb, struct usb_device *dev)
{ }
#endif /* CONFIG_HOTPLUG */
/*
* This entrypoint gets called for each new device.
*
* All interfaces are scanned for matching drivers.
*/
static void usb_find_drivers(struct usb_device *dev)
{
unsigned ifnum;
unsigned rejected = 0;
unsigned claimed = 0;
for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
/* if this interface hasn't already been claimed */
if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) {
if (usb_find_interface_driver(dev, ifnum))
rejected++;
else
claimed++;
}
}
if (rejected)
printf("unhandled interfaces on device\n");
if (!claimed) {
printf("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.\n",
dev->devnum,
dev->descriptor.idVendor,
dev->descriptor.idProduct);
printf("usb device %d(VID/PID:0x%x/0x%x) Maxpacketsize[ep0]:0x%x/iManufacture:0x%x/iProduct:0x%x/iSerialNumber:0x%x/bNumConf:0x%x.\n",
dev->devnum,dev->descriptor.idVendor,dev->descriptor.idProduct,
dev->descriptor.bMaxPacketSize0,
dev->descriptor.iManufacturer,dev->descriptor.iProduct,
dev->descriptor.iSerialNumber,dev->descriptor.bNumConfigurations);
#ifdef DEBUG
usb_show_device(dev);
#endif
}
}
/*
* Only HC's should call usb_alloc_dev and usb_free_dev directly
* Anybody may use usb_inc_dev_use or usb_dec_dev_use
*/
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
{
struct usb_device *dev;
dev = (struct usb_device *)malloc(sizeof(*dev));
if (!dev)
return NULL;
memset(dev, 0, sizeof(*dev));
usb_bus_get(bus);
dev->bus = bus;
dev->parent = parent;
atomic_set(&dev->refcnt, 1);
INIT_LIST_HEAD(&dev->inodes);
INIT_LIST_HEAD(&dev->filelist);
// init_MUTEX(&dev->serialize);
dev->bus->op->allocate(dev);
return dev;
}
void usb_destroy_configuration(struct usb_device *dev)
{
int c, i, j, k;
if (!dev->config)
return;
if (dev->rawdescriptors) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
free(dev->rawdescriptors[i]);
free(dev->rawdescriptors);
}
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
struct usb_config_descriptor *cf = &dev->config[c];
if (!cf->interface)
break;
for (i = 0; i < cf->bNumInterfaces; i++) {
struct usb_interface *ifp =
&cf->interface[i];
if (!ifp->altsetting)
break;
for (j = 0; j < ifp->num_altsetting; j++) {
struct usb_interface_descriptor *as =
&ifp->altsetting[j];
if(as->extra) {
free(as->extra);
}
if (!as->endpoint)
break;
for(k = 0; k < as->bNumEndpoints; k++) {
if(as->endpoint[k].extra) {
free(as->endpoint[k].extra);
}
}
free(as->endpoint);
}
free(ifp->altsetting);
}
free(cf->interface);
}
free(dev->config);
}
void usb_free_dev(struct usb_device *dev)
{
if (atomic_dec_and_test(&dev->refcnt)) {
dev->bus->op->deallocate(dev);
usb_destroy_configuration(dev);
usb_bus_put(dev->bus);
free(dev);
}
}
void usb_inc_dev_use(struct usb_device *dev)
{
atomic_inc(&dev->refcnt);
}
/* -------------------------------------------------------------------------------------
* New USB Core Functions
* -------------------------------------------------------------------------------------*/
/**
* usb_alloc_urb - creates a new urb for a USB driver to use
* @iso_packets: number of iso packets for this urb
*
* Creates an urb for the USB driver to use and returns a pointer to it.
* If no memory is available, NULL is returned.
*
* If the driver want to use this urb for interrupt, control, or bulk
* endpoints, pass '0' as the number of iso packets.
*
* The driver should call usb_free_urb() when it is finished with the urb.
*/
urb_t *usb_alloc_urb(int iso_packets)
{
urb_t *urb;
urb = (urb_t *)malloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t));
if (!urb) {
err("alloc_urb: malloc failed");
return NULL;
}
memset(urb, 0, sizeof(*urb));
// spin_lock_init(&urb->lock);
return urb;
}
/**
* usb_free_urb - frees the memory used by a urb
* @urb: pointer to the urb to free
*
* If an urb is created with a call to usb_create_urb() it should be
* cleaned up with a call to usb_free_urb() when the driver is finished
* with it.
*/
void usb_free_urb(urb_t* urb)
{
if (urb)
free(urb);
}
/*-------------------------------------------------------------------*/
int usb_submit_urb(urb_t *urb)
{
if (urb && urb->dev)
return urb->dev->bus->op->submit_urb(urb);
else
return -ENODEV;
}
/*-------------------------------------------------------------------*/
int usb_unlink_urb(urb_t *urb)
{
if (urb && urb->dev)
return urb->dev->bus->op->unlink_urb(urb);
else
return -ENODEV;
}
/*-------------------------------------------------------------------*
* 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
printf("(blocking_completion): waitqueue empty!");
// even occurs if urb was unlinked by timeout...
#endif
}
/*-------------------------------------------------------------------*
* COMPATIBILITY STUFF *
*-------------------------------------------------------------------*/
// Starts urb and waits for completion or timeout
static 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;
// urb_priv_t * urb_priv = urb->hcpriv; //added by hcm
// awd.wakeup = &wqh;
// 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);
// current->state = TASK_RUNNING;
// remove_wait_queue(&wqh, &wait);
return status;
}
// printf("urb->status:%d\n",urb->status);//added by changming HUANG
if (urb->status == -EINPROGRESS) {
wait_ms(timeout);
if(urb->status==-EINPROGRESS)
status=0;
else
status=1;
/* while (timeout && urb->status == -EINPROGRESS){
printf("Schedule timeout(hcm)\n");
// printf("LB MMU WTL Status:%X\n",*((unsigned short*)(0xfffec204)));
status = timeout = schedule_timeout(timeout);
}
*/
} else
status = 1;
// printf("The second status:%d\n",status);//added by changming HUANG
// current->state = TASK_RUNNING;
// remove_wait_queue(&wqh, &wait);
if (!status) {
// timeout
printf("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;
/* build urb */
FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,(usb_complete_t)usb_api_blocking_completion,0);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
/**
* usb_control_msg - Builds a control urb, sends it off and waits for completion
* @dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @request: USB message request value
* @requesttype: USB message request type value
* @value: USB message value
* @index: USB message index value
* @data: pointer to the data to send
* @size: length in bytes of the data to send
* @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
*
* This function sends a simple control message to a specified endpoint
* and waits for the message to complete, or timeout.
*
* If successful, it returns 0, othwise a negative error number.
*
* Don't use this function from within an interrupt context, like a
* bottom half handler. If you need a asyncronous message, or need to send
* a message from within interrupt context, use usb_submit_urb()
*/
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)
{
int ret;
devrequest *dr = (devrequest*)malloc(sizeof(devrequest));
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);
dr->value = value;
dr->index = index;
dr->length = size;
// printf("DR->value:%X value:%X\n",dr->value,value);no problem
//printf("usb_control_msg");
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
free(dr);
return ret;
}
/**
* usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
* @usb_dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @data: pointer to the data to send
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred in bytes
* @timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
*
* This function sends a simple bulk message to a specified endpoint
* and waits for the message to complete, or timeout.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -