📄 message.c
字号:
if (!io->urbs)
goto nomem;
urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT;
if (usb_pipein (pipe))
urb_flags |= URB_SHORT_NOT_OK;
for (i = 0; i < io->entries; i++, io->count = i) {
unsigned len;
io->urbs [i] = usb_alloc_urb (0, mem_flags);
if (!io->urbs [i]) {
io->entries = i;
goto nomem;
}
io->urbs [i]->dev = dev;
io->urbs [i]->pipe = pipe;
io->urbs [i]->interval = period;
io->urbs [i]->transfer_flags = urb_flags;
io->urbs [i]->complete = sg_complete;
io->urbs [i]->context = io;
io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0;
if (dma) {
/* hc may use _only_ transfer_dma */
io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i);
} else {
/* hc may use _only_ transfer_buffer */
io->urbs [i]->transfer_buffer =
page_address (sg [i].page) + sg [i].offset;
len = sg [i].length;
}
if (length) {
len = min_t (unsigned, len, length);
length -= len;
if (length == 0)
io->entries = i + 1;
}
io->urbs [i]->transfer_buffer_length = len;
}
io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;
/* transaction state */
io->status = 0;
io->bytes = 0;
init_completion (&io->complete);
return 0;
nomem:
sg_clean (io);
return -ENOMEM;
}
/**
* usb_sg_wait - synchronously execute scatter/gather request
* @io: request block handle, as initialized with usb_sg_init().
* some fields become accessible when this call returns.
* Context: !in_interrupt ()
*
* This function blocks until the specified I/O operation completes. It
* leverages the grouping of the related I/O requests to get good transfer
* rates, by queueing the requests. At higher speeds, such queuing can
* significantly improve USB throughput.
*
* There are three kinds of completion for this function.
* (1) success, where io->status is zero. The number of io->bytes
* transferred is as requested.
* (2) error, where io->status is a negative errno value. The number
* of io->bytes transferred before the error is usually less
* than requested, and can be nonzero.
* (3) cancelation, a type of error with status -ECONNRESET that
* is initiated by usb_sg_cancel().
*
* When this function returns, all memory allocated through usb_sg_init() or
* this call will have been freed. The request block parameter may still be
* passed to usb_sg_cancel(), or it may be freed. It could also be
* reinitialized and then reused.
*
* Data Transfer Rates:
*
* Bulk transfers are valid for full or high speed endpoints.
* The best full speed data rate is 19 packets of 64 bytes each
* per frame, or 1216 bytes per millisecond.
* The best high speed data rate is 13 packets of 512 bytes each
* per microframe, or 52 KBytes per millisecond.
*
* The reason to use interrupt transfers through this API would most likely
* be to reserve high speed bandwidth, where up to 24 KBytes per millisecond
* could be transferred. That capability is less useful for low or full
* speed interrupt endpoints, which allow at most one packet per millisecond,
* of at most 8 or 64 bytes (respectively).
*/
void usb_sg_wait (struct usb_sg_request *io)
{
int i;
unsigned long flags;
/* queue the urbs. */
spin_lock_irqsave (&io->lock, flags);
for (i = 0; i < io->entries && !io->status; i++) {
int retval;
retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC);
/* after we submit, let completions or cancelations fire;
* we handshake using io->status.
*/
spin_unlock_irqrestore (&io->lock, flags);
switch (retval) {
/* maybe we retrying will recover */
case -ENXIO: // hc didn't queue this one
case -EAGAIN:
case -ENOMEM:
retval = 0;
i--;
// FIXME: should it usb_sg_cancel() on INTERRUPT?
yield ();
break;
/* no error? continue immediately.
*
* NOTE: to work better with UHCI (4K I/O buffer may
* need 3K of TDs) it may be good to limit how many
* URBs are queued at once; N milliseconds?
*/
case 0:
cpu_relax ();
break;
/* fail any uncompleted urbs */
default:
io->urbs [i]->status = retval;
dbg ("usb_sg_msg, submit --> %d", retval);
usb_sg_cancel (io);
}
spin_lock_irqsave (&io->lock, flags);
if (retval && io->status == -ECONNRESET)
io->status = retval;
}
spin_unlock_irqrestore (&io->lock, flags);
/* OK, yes, this could be packaged as non-blocking.
* So could the submit loop above ... but it's easier to
* solve neither problem than to solve both!
*/
wait_for_completion (&io->complete);
sg_clean (io);
}
/**
* usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
* @io: request block, initialized with usb_sg_init()
*
* This stops a request after it has been started by usb_sg_wait().
* It can also prevents one initialized by usb_sg_init() from starting,
* so that call just frees resources allocated to the request.
*/
void usb_sg_cancel (struct usb_sg_request *io)
{
unsigned long flags;
spin_lock_irqsave (&io->lock, flags);
/* shut everything down, if it didn't already */
if (!io->status) {
int i;
io->status = -ECONNRESET;
for (i = 0; i < io->entries; i++) {
int retval;
if (!io->urbs [i]->dev)
continue;
retval = usb_unlink_urb (io->urbs [i]);
if (retval && retval != -EINPROGRESS)
warn ("usb_sg_cancel, unlink --> %d", retval);
// FIXME don't warn on "not yet submitted" error
}
}
spin_unlock_irqrestore (&io->lock, flags);
}
#endif
/*-------------------------------------------------------------------*/
/**
* 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 the number of bytes received 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 = 0;
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 the number of bytes received 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 the number of bytes received 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 the number of bytes received 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, when setting up a config
void usb_set_maxpacket(struct usb_device *dev)
{
int i, b;
/* NOTE: affects all endpoints _except_ ep0 */
for (i=0; i<dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *ifp = dev->actconfig->interface + i;
struct usb_host_interface *as = ifp->altsetting + ifp->act_altsetting;
struct usb_host_endpoint *ep = as->endpoint;
int e;
for (e=0; e<as->desc.bNumEndpoints; e++) {
struct usb_endpoint_descriptor *d;
d = &ep [e].desc;
b = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if ((d->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
dev->epmaxpacketout[b] = d->wMaxPacketSize;
dev->epmaxpacketin [b] = d->wMaxPacketSize;
}
else if (usb_endpoint_out(d->bEndpointAddress)) {
if (d->wMaxPacketSize > dev->epmaxpacketout[b])
dev->epmaxpacketout[b] = d->wMaxPacketSize;
}
else {
if (d->wMaxPacketSize > dev->epmaxpacketin [b])
dev->epmaxpacketin [b] = d->wMaxPacketSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -