📄 usb.c
字号:
data [1] = 3; return data [0];}/* * __usb_get_extra_descriptor() finds a descriptor of specific type in the * extra field of the interface and endpoint descriptor structs. */int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr){ struct usb_descriptor_header *header; 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 (header->bDescriptorType == type) { *ptr = header; return 0; } buffer += header->bLength; size -= header->bLength; } return -1;}/** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected * Context: !in_interrupt () * * Something got disconnected. Get rid of it, and all of its children. * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. * * This call is synchronous, and may not be used in an interrupt context. */void usb_disconnect(struct usb_device **pdev){ struct usb_device * dev = *pdev; int i; if (!dev) return; *pdev = NULL; info("USB disconnect on device %d", dev->devnum); if (dev->actconfig) { for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { struct usb_interface *interface = &dev->actconfig->interface[i]; struct usb_driver *driver = interface->driver; if (driver) { if (driver->owner) __MOD_INC_USE_COUNT(driver->owner); down(&driver->serialize); driver->disconnect(dev, interface->private_data); up(&driver->serialize); if (driver->owner) __MOD_DEC_USE_COUNT(driver->owner); /* if driver->disconnect didn't release the interface */ if (interface->driver) usb_driver_release_interface(driver, interface); } /* remove our device node for this interface */ put_device(&interface->dev); } } /* Free up all the children.. */ for (i = 0; i < USB_MAXCHILDREN; i++) { struct usb_device **child = dev->children + i; if (*child) usb_disconnect(child); } /* Let policy agent unload modules etc */ call_policy ("remove", dev); /* Free the device number and remove the /proc/bus/usb entry */ if (dev->devnum > 0) { clear_bit(dev->devnum, dev->bus->devmap.devicemap); usbfs_remove_device(dev); put_device(&dev->dev); } /* Free up the device itself */ usb_free_dev(dev);}/** * usb_connect - connects a new device during enumeration (usbcore-internal) * @dev: partially enumerated device * * Connect a new USB device. This basically just initializes * the USB device information and sets up the topology - it's * up to the low-level driver to reset the port and actually * do the setup (the upper levels don't know how to do that). * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. */void usb_connect(struct usb_device *dev){ int devnum; // FIXME needs locking for SMP!! /* why? this is called only from the hub thread, * which hopefully doesn't run on multiple CPU's simultaneously 8-) * ... it's also called from modprobe/rmmod/apmd threads as part * of virtual root hub init/reinit. In the init case, the hub code * won't have seen this, but not so for reinit ... */ dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */#ifndef DEVNUM_ROUND_ROBIN devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);#else /* round_robin alloc of devnums */ /* Try to allocate the next devnum beginning at bus->devnum_next. */ devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next); if (devnum >= 128) devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);#endif /* round_robin alloc of devnums */ if (devnum < 128) { set_bit(devnum, dev->bus->devmap.devicemap); dev->devnum = devnum; }}/* * These are the actual routines to send * and receive control messages. */// hub-only!! ... and only exported for reset/reinit path.// otherwise used internally, for usb_new_device()int usb_set_address(struct usb_device *dev){ return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS, // FIXME USB_CTRL_SET_TIMEOUT 0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_GET_TIMEOUT);}/** * usb_get_descriptor - issues a generic GET_DESCRIPTOR request * @dev: the device whose descriptor is being retrieved * @type: the descriptor type (USB_DT_*) * @index: the number of the descriptor * @buf: where to put the descriptor * @size: how big is "buf"? * Context: !in_interrupt () * * Gets a USB descriptor. Convenience functions exist to simplify * getting some types of descriptors. Use * usb_get_device_descriptor() for USB_DT_DEVICE, * and usb_get_string() or usb_string() for USB_DT_STRING. * Configuration descriptors (USB_DT_CONFIG) are part of the device * structure, at least for the current configuration. * In addition to a number of USB-standard descriptors, some * devices also use class-specific or vendor-specific descriptors. * * This call is synchronous, and may not be used in an interrupt context. * * Returns zero on success, or else the status code returned by the * underlying usb_control_msg() call. */int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size){ int i = 5; int result; memset(buf,0,size); // Make sure we parse really received data while (i--) { /* retries if the returned length was 0; flakey device */ if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, HZ * USB_CTRL_GET_TIMEOUT)) > 0 || result == -EPIPE) break; } return result;}/** * usb_get_string - gets a string descriptor * @dev: the device whose string descriptor is being retrieved * @langid: code for language chosen (from string descriptor zero) * @index: the number of the descriptor * @buf: where to put the string * @size: how big is "buf"? * Context: !in_interrupt () * * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character, * in little-endian byte order). * The usb_string() function will often be a convenient way to turn * these strings into kernel-printable form. * * Strings may be referenced in device, configuration, interface, or other * descriptors, and could also be used in vendor-specific ways. * * This call is synchronous, and may not be used in an interrupt context. * * Returns zero on success, or else the status code returned by the * underlying usb_control_msg() call. */int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size){ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (USB_DT_STRING << 8) + index, langid, buf, size, HZ * USB_CTRL_GET_TIMEOUT);}/** * usb_get_device_descriptor - (re)reads the device descriptor * @dev: the device whose device descriptor is being updated * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, * which dedicates space for this purpose. Note that several fields are * converted to the host CPU's byte order: the USB version (bcdUSB), and * vendors product and version fields (idVendor, idProduct, and bcdDevice). * That lets device drivers compare against non-byteswapped constants. * * There's normally no need to use this call, although some devices * will change their descriptors after events like updating firmware. * * This call is synchronous, and may not be used in an interrupt context. * * Returns zero on success, or else the status code returned by the * underlying usb_control_msg() call. */int usb_get_device_descriptor(struct usb_device *dev){ int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); if (ret >= 0) { le16_to_cpus(&dev->descriptor.bcdUSB); le16_to_cpus(&dev->descriptor.idVendor); le16_to_cpus(&dev->descriptor.idProduct); le16_to_cpus(&dev->descriptor.bcdDevice); } return ret;}/** * usb_get_status - issues a GET_STATUS call * @dev: the device whose status is being checked * @type: USB_RECIP_*; for device, interface, or endpoint * @target: zero (for device), else interface or endpoint number * @data: pointer to two bytes of bitmap data * Context: !in_interrupt () * * Returns device, interface, or endpoint status. Normally only of * interest to see if the device is self powered, or has enabled the * remote wakeup facility; or whether a bulk or interrupt endpoint * is halted ("stalled"). * * Bits in these status bitmaps are set using the SET_FEATURE request, * and cleared using the CLEAR_FEATURE request. The usb_clear_halt() * function should be used to clear halt ("stall") status. * * This call is synchronous, and may not be used in an interrupt context. * * Returns zero on success, or else the status code returned by the * underlying usb_control_msg() call. */int usb_get_status(struct usb_device *dev, int type, int target, void *data){ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2, HZ * USB_CTRL_GET_TIMEOUT);}// hub-only!! ... and only exported for reset/reinit path.// otherwise used internally, for config/altsetting reconfig.void usb_set_maxpacket(struct usb_device *dev){ int i, b; for (i=0; i<dev->actconfig->bNumInterfaces; i++) { struct usb_interface *ifp = dev->actconfig->interface + i; struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting; struct usb_endpoint_descriptor *ep = as->endpoint; int e; for (e=0; e<as->bNumEndpoints; e++) { b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */ dev->epmaxpacketout[b] = ep[e].wMaxPacketSize; dev->epmaxpacketin [b] = ep[e].wMaxPacketSize; } else if (usb_endpoint_out(ep[e].bEndpointAddress)) { if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b]) dev->epmaxpacketout[b] = ep[e].wMaxPacketSize; } else { if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b]) dev->epmaxpacketin [b] = ep[e].wMaxPacketSize; } } }}/** * usb_clear_halt - tells device to clear endpoint halt/stall condition * @dev: device whose endpoint is halted * @pipe: endpoint "pipe" being cleared * Context: !in_interrupt () * * This is used to clear halt conditions for bulk and interrupt endpoints, * as reported by URB completion status. Endpoints that are halted are * sometimes referred to as being "stalled". Such endpoints are unable * to transmit or receive data until the halt status is cleared. Any URBs * queued queued for such an endpoint should normally be unlinked before * clearing the halt condition. * * Note that control and isochronous endpoints don't halt, although control * endpoints report "protocol stall" (for unsupported requests) using the * same status code used to report a true stall. * * This call is synchronous, and may not be used in an interrupt context. * * Returns zero on success, or else the status code returned by the * underlying usb_control_msg() call. */int usb_clear_halt(struct usb_device *dev, int pipe){ int result; __u16 status; unsigned char *buffer; int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);/* if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp))) return 0;*/ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); /* don't clear if failed */ if (result < 0) return result; buffer = kmalloc(sizeof(status), GFP_KERNEL); if (!buffer) { err("unable to allocate memory for configuration descriptors"); return -ENOMEM; } result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp, // FIXME USB_CTRL_GET_TIMEOUT, yes? why not usb_get_status() ? buffer, sizeof(status), HZ * USB_CTRL_SET_TIMEOUT); memcpy(&status, buffer, sizeof(status)); kfree(buffer); if (result < 0) return result; if (le16_to_cpu(status) & 1) return -EPIPE; /* still halted */ usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); /* toggle is reset on clear */ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); return 0;}/** * usb_set_interface - Makes a particular alternate setting be current * @dev: the device whose interface is being updated * @interface: the interface being updated * @alternate: the setting being chosen. * Context: !in_interrupt () * * This is used to enable data transfers on interfaces that may not * be enabled by default. Not all devices support such configurability. * * Within any given configuration, each interface may have several * alternative settings. These are often used to control levels of * bandwidth consumption. For example, the default setting for a high * speed interrupt endpoint may not send more than about 4KBytes per * microframe, and isochronous endpoints may never be part of a an * interface's default setting. To access such bandwidth, alternate * interface setting must be made current. * * Note that in the Linux USB subsystem, bandwidth associated with * an endpoint in a given alternate setting is not reserved until an * is submitted that needs that bandwidth. Some other operating systems * allocate bandwidth early, when a configuration is chosen. * * This call is synchronous, and may not be used in an interrupt context. * * Returns zero on success, or else the status code returned by the * underlying usb_control_msg() call. */int usb_set_interface(struct usb_device *dev, int interface, int alternate){ struct usb_interface *iface; struct usb_interface_descriptor *iface_as; int i, ret; iface = usb_ifnum_to_if(dev, interface); if (!ifa
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -