forked from Minki/linux
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (229 commits) USB: remove unused usb_buffer_alloc and usb_buffer_free macros usb: musb: update gfp/slab.h includes USB: ftdi_sio: fix legacy SIO-device header USB: kl5usb105: reimplement using generic framework USB: kl5usb105: minor clean ups USB: kl5usb105: fix memory leak USB: io_ti: use kfifo to implement write buffering USB: io_ti: remove unsused private counter USB: ti_usb: use kfifo to implement write buffering USB: ir-usb: fix incorrect write-buffer length USB: aircable: fix incorrect write-buffer length USB: safe_serial: straighten out read processing USB: safe_serial: reimplement read using generic framework USB: safe_serial: reimplement write using generic framework usb-storage: always print quirks USB: usb-storage: trivial debug improvements USB: oti6858: use port write fifo USB: oti6858: use kfifo to implement write buffering USB: cypress_m8: use kfifo to implement write buffering USB: cypress_m8: remove unused drain define ... Fix up conflicts (due to usb_buffer_alloc/free renaming) in drivers/input/tablet/acecad.c drivers/input/tablet/kbtab.c drivers/input/tablet/wacom_sys.c drivers/media/video/gspca/gspca.c sound/usb/usbaudio.c
This commit is contained in:
commit
7a9b149212
31
Documentation/ABI/obsolete/sysfs-bus-usb
Normal file
31
Documentation/ABI/obsolete/sysfs-bus-usb
Normal file
@ -0,0 +1,31 @@
|
||||
What: /sys/bus/usb/devices/.../power/level
|
||||
Date: March 2007
|
||||
KernelVersion: 2.6.21
|
||||
Contact: Alan Stern <stern@rowland.harvard.edu>
|
||||
Description:
|
||||
Each USB device directory will contain a file named
|
||||
power/level. This file holds a power-level setting for
|
||||
the device, either "on" or "auto".
|
||||
|
||||
"on" means that the device is not allowed to autosuspend,
|
||||
although normal suspends for system sleep will still
|
||||
be honored. "auto" means the device will autosuspend
|
||||
and autoresume in the usual manner, according to the
|
||||
capabilities of its driver.
|
||||
|
||||
During normal use, devices should be left in the "auto"
|
||||
level. The "on" level is meant for administrative uses.
|
||||
If you want to suspend a device immediately but leave it
|
||||
free to wake up in response to I/O requests, you should
|
||||
write "0" to power/autosuspend.
|
||||
|
||||
Device not capable of proper suspend and resume should be
|
||||
left in the "on" level. Although the USB spec requires
|
||||
devices to support suspend/resume, many of them do not.
|
||||
In fact so many don't that by default, the USB core
|
||||
initializes all non-hub devices in the "on" level. Some
|
||||
drivers may change this setting when they are bound.
|
||||
|
||||
This file is deprecated and will be removed after 2010.
|
||||
Use the power/control file instead; it does exactly the
|
||||
same thing.
|
@ -14,34 +14,6 @@ Description:
|
||||
The autosuspend delay for newly-created devices is set to
|
||||
the value of the usbcore.autosuspend module parameter.
|
||||
|
||||
What: /sys/bus/usb/devices/.../power/level
|
||||
Date: March 2007
|
||||
KernelVersion: 2.6.21
|
||||
Contact: Alan Stern <stern@rowland.harvard.edu>
|
||||
Description:
|
||||
Each USB device directory will contain a file named
|
||||
power/level. This file holds a power-level setting for
|
||||
the device, either "on" or "auto".
|
||||
|
||||
"on" means that the device is not allowed to autosuspend,
|
||||
although normal suspends for system sleep will still
|
||||
be honored. "auto" means the device will autosuspend
|
||||
and autoresume in the usual manner, according to the
|
||||
capabilities of its driver.
|
||||
|
||||
During normal use, devices should be left in the "auto"
|
||||
level. The "on" level is meant for administrative uses.
|
||||
If you want to suspend a device immediately but leave it
|
||||
free to wake up in response to I/O requests, you should
|
||||
write "0" to power/autosuspend.
|
||||
|
||||
Device not capable of proper suspend and resume should be
|
||||
left in the "on" level. Although the USB spec requires
|
||||
devices to support suspend/resume, many of them do not.
|
||||
In fact so many don't that by default, the USB core
|
||||
initializes all non-hub devices in the "on" level. Some
|
||||
drivers may change this setting when they are bound.
|
||||
|
||||
What: /sys/bus/usb/devices/.../power/persist
|
||||
Date: May 2007
|
||||
KernelVersion: 2.6.23
|
||||
|
@ -0,0 +1,9 @@
|
||||
What: /sys/devices/platform/_UDC_/gadget/suspended
|
||||
Date: April 2010
|
||||
Contact: Fabien Chouteau <fabien.chouteau@barco.com>
|
||||
Description:
|
||||
Show the suspend state of an USB composite gadget.
|
||||
1 -> suspended
|
||||
0 -> resumed
|
||||
|
||||
(_UDC_ is the name of the USB Device Controller driver)
|
@ -342,7 +342,7 @@ static inline void skel_delete (struct usb_skel *dev)
|
||||
{
|
||||
kfree (dev->bulk_in_buffer);
|
||||
if (dev->bulk_out_buffer != NULL)
|
||||
usb_buffer_free (dev->udev, dev->bulk_out_size,
|
||||
usb_free_coherent (dev->udev, dev->bulk_out_size,
|
||||
dev->bulk_out_buffer,
|
||||
dev->write_urb->transfer_dma);
|
||||
usb_free_urb (dev->write_urb);
|
||||
|
78
Documentation/usb/bulk-streams.txt
Normal file
78
Documentation/usb/bulk-streams.txt
Normal file
@ -0,0 +1,78 @@
|
||||
Background
|
||||
==========
|
||||
|
||||
Bulk endpoint streams were added in the USB 3.0 specification. Streams allow a
|
||||
device driver to overload a bulk endpoint so that multiple transfers can be
|
||||
queued at once.
|
||||
|
||||
Streams are defined in sections 4.4.6.4 and 8.12.1.4 of the Universal Serial Bus
|
||||
3.0 specification at http://www.usb.org/developers/docs/ The USB Attached SCSI
|
||||
Protocol, which uses streams to queue multiple SCSI commands, can be found on
|
||||
the T10 website (http://t10.org/).
|
||||
|
||||
|
||||
Device-side implications
|
||||
========================
|
||||
|
||||
Once a buffer has been queued to a stream ring, the device is notified (through
|
||||
an out-of-band mechanism on another endpoint) that data is ready for that stream
|
||||
ID. The device then tells the host which "stream" it wants to start. The host
|
||||
can also initiate a transfer on a stream without the device asking, but the
|
||||
device can refuse that transfer. Devices can switch between streams at any
|
||||
time.
|
||||
|
||||
|
||||
Driver implications
|
||||
===================
|
||||
|
||||
int usb_alloc_streams(struct usb_interface *interface,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
unsigned int num_streams, gfp_t mem_flags);
|
||||
|
||||
Device drivers will call this API to request that the host controller driver
|
||||
allocate memory so the driver can use up to num_streams stream IDs. They must
|
||||
pass an array of usb_host_endpoints that need to be setup with similar stream
|
||||
IDs. This is to ensure that a UASP driver will be able to use the same stream
|
||||
ID for the bulk IN and OUT endpoints used in a Bi-directional command sequence.
|
||||
|
||||
The return value is an error condition (if one of the endpoints doesn't support
|
||||
streams, or the xHCI driver ran out of memory), or the number of streams the
|
||||
host controller allocated for this endpoint. The xHCI host controller hardware
|
||||
declares how many stream IDs it can support, and each bulk endpoint on a
|
||||
SuperSpeed device will say how many stream IDs it can handle. Therefore,
|
||||
drivers should be able to deal with being allocated less stream IDs than they
|
||||
requested.
|
||||
|
||||
Do NOT call this function if you have URBs enqueued for any of the endpoints
|
||||
passed in as arguments. Do not call this function to request less than two
|
||||
streams.
|
||||
|
||||
Drivers will only be allowed to call this API once for the same endpoint
|
||||
without calling usb_free_streams(). This is a simplification for the xHCI host
|
||||
controller driver, and may change in the future.
|
||||
|
||||
|
||||
Picking new Stream IDs to use
|
||||
============================
|
||||
|
||||
Stream ID 0 is reserved, and should not be used to communicate with devices. If
|
||||
usb_alloc_streams() returns with a value of N, you may use streams 1 though N.
|
||||
To queue an URB for a specific stream, set the urb->stream_id value. If the
|
||||
endpoint does not support streams, an error will be returned.
|
||||
|
||||
Note that new API to choose the next stream ID will have to be added if the xHCI
|
||||
driver supports secondary stream IDs.
|
||||
|
||||
|
||||
Clean up
|
||||
========
|
||||
|
||||
If a driver wishes to stop using streams to communicate with the device, it
|
||||
should call
|
||||
|
||||
void usb_free_streams(struct usb_interface *interface,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
gfp_t mem_flags);
|
||||
|
||||
All stream IDs will be deallocated when the driver releases the interface, to
|
||||
ensure that drivers that don't support streams will be able to use the endpoint.
|
@ -16,11 +16,11 @@ OR: they can now be DMA-aware.
|
||||
manage dma mappings for existing dma-ready buffers (see below).
|
||||
|
||||
- URBs have an additional "transfer_dma" field, as well as a transfer_flags
|
||||
bit saying if it's valid. (Control requests also have "setup_dma" and a
|
||||
corresponding transfer_flags bit.)
|
||||
bit saying if it's valid. (Control requests also have "setup_dma", but
|
||||
drivers must not use it.)
|
||||
|
||||
- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do
|
||||
it first and set URB_NO_TRANSFER_DMA_MAP or URB_NO_SETUP_DMA_MAP. HCDs
|
||||
- "usbcore" will map this DMA address, if a DMA-aware driver didn't do
|
||||
it first and set URB_NO_TRANSFER_DMA_MAP. HCDs
|
||||
don't manage dma mappings for URBs.
|
||||
|
||||
- There's a new "generic DMA API", parts of which are usable by USB device
|
||||
@ -43,22 +43,16 @@ and effects like cache-trashing can impose subtle penalties.
|
||||
kind of addresses to store in urb->transfer_buffer and urb->transfer_dma.
|
||||
You'd also set URB_NO_TRANSFER_DMA_MAP in urb->transfer_flags:
|
||||
|
||||
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
|
||||
void *usb_alloc_coherent (struct usb_device *dev, size_t size,
|
||||
int mem_flags, dma_addr_t *dma);
|
||||
|
||||
void usb_buffer_free (struct usb_device *dev, size_t size,
|
||||
void usb_free_coherent (struct usb_device *dev, size_t size,
|
||||
void *addr, dma_addr_t dma);
|
||||
|
||||
Most drivers should *NOT* be using these primitives; they don't need
|
||||
to use this type of memory ("dma-coherent"), and memory returned from
|
||||
kmalloc() will work just fine.
|
||||
|
||||
For control transfers you can use the buffer primitives or not for each
|
||||
of the transfer buffer and setup buffer independently. Set the flag bits
|
||||
URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which
|
||||
buffers you have prepared. For non-control transfers URB_NO_SETUP_DMA_MAP
|
||||
is ignored.
|
||||
|
||||
The memory buffer returned is "dma-coherent"; sometimes you might need to
|
||||
force a consistent memory access ordering by using memory barriers. It's
|
||||
not using a streaming DMA mapping, so it's good for small transfers on
|
||||
@ -130,8 +124,8 @@ of Documentation/PCI/PCI-DMA-mapping.txt, titled "What memory is DMA-able?")
|
||||
void usb_buffer_unmap (struct urb *urb);
|
||||
|
||||
The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP
|
||||
so that usbcore won't map or unmap the buffer. The same goes for
|
||||
urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests.
|
||||
so that usbcore won't map or unmap the buffer. They cannot be used for
|
||||
setup_packet buffers in control requests.
|
||||
|
||||
Note that several of those interfaces are currently commented out, since
|
||||
they don't have current users. See the source code. Other than the dmasync
|
||||
|
445
Documentation/usb/gadget_hid.txt
Normal file
445
Documentation/usb/gadget_hid.txt
Normal file
@ -0,0 +1,445 @@
|
||||
|
||||
Linux USB HID gadget driver
|
||||
|
||||
Introduction
|
||||
|
||||
The HID Gadget driver provides emulation of USB Human Interface
|
||||
Devices (HID). The basic HID handling is done in the kernel,
|
||||
and HID reports can be sent/received through I/O on the
|
||||
/dev/hidgX character devices.
|
||||
|
||||
For more details about HID, see the developer page on
|
||||
http://www.usb.org/developers/hidpage/
|
||||
|
||||
Configuration
|
||||
|
||||
g_hid is a platform driver, so to use it you need to add
|
||||
struct platform_device(s) to your platform code defining the
|
||||
HID function descriptors you want to use - E.G. something
|
||||
like:
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/g_hid.h>
|
||||
|
||||
/* hid descriptor for a keyboard */
|
||||
static struct hidg_func_descriptor my_hid_data = {
|
||||
.subclass = 0, /* No subclass */
|
||||
.protocol = 1, /* Keyboard */
|
||||
.report_length = 8,
|
||||
.report_desc_length = 63,
|
||||
.report_desc = {
|
||||
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
|
||||
0x09, 0x06, /* USAGE (Keyboard) */
|
||||
0xa1, 0x01, /* COLLECTION (Application) */
|
||||
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
|
||||
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
|
||||
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x75, 0x01, /* REPORT_SIZE (1) */
|
||||
0x95, 0x08, /* REPORT_COUNT (8) */
|
||||
0x81, 0x02, /* INPUT (Data,Var,Abs) */
|
||||
0x95, 0x01, /* REPORT_COUNT (1) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
|
||||
0x95, 0x05, /* REPORT_COUNT (5) */
|
||||
0x75, 0x01, /* REPORT_SIZE (1) */
|
||||
0x05, 0x08, /* USAGE_PAGE (LEDs) */
|
||||
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
|
||||
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
|
||||
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
|
||||
0x95, 0x01, /* REPORT_COUNT (1) */
|
||||
0x75, 0x03, /* REPORT_SIZE (3) */
|
||||
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
|
||||
0x95, 0x06, /* REPORT_COUNT (6) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
|
||||
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
|
||||
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
|
||||
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
|
||||
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
|
||||
0xc0 /* END_COLLECTION */
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device my_hid = {
|
||||
.name = "hidg",
|
||||
.id = 0,
|
||||
.num_resources = 0,
|
||||
.resource = 0,
|
||||
.dev.platform_data = &my_hid_data,
|
||||
};
|
||||
|
||||
You can add as many HID functions as you want, only limited by
|
||||
the amount of interrupt endpoints your gadget driver supports.
|
||||
|
||||
Send and receive HID reports
|
||||
|
||||
HID reports can be sent/received using read/write on the
|
||||
/dev/hidgX character devices. See below for an example program
|
||||
to do this.
|
||||
|
||||
hid_gadget_test is a small interactive program to test the HID
|
||||
gadget driver. To use, point it at a hidg device and set the
|
||||
device type (keyboard / mouse / joystick) - E.G.:
|
||||
|
||||
# hid_gadget_test /dev/hidg0 keyboard
|
||||
|
||||
You are now in the prompt of hid_gadget_test. You can type any
|
||||
combination of options and values. Available options and
|
||||
values are listed at program start. In keyboard mode you can
|
||||
send up to six values.
|
||||
|
||||
For example type: g i s t r --left-shift
|
||||
|
||||
Hit return and the corresponding report will be sent by the
|
||||
HID gadget.
|
||||
|
||||
Another interesting example is the caps lock test. Type
|
||||
-–caps-lock and hit return. A report is then sent by the
|
||||
gadget and you should receive the host answer, corresponding
|
||||
to the caps lock LED status.
|
||||
|
||||
--caps-lock
|
||||
recv report:2
|
||||
|
||||
With this command:
|
||||
|
||||
# hid_gadget_test /dev/hidg1 mouse
|
||||
|
||||
You can test the mouse emulation. Values are two signed numbers.
|
||||
|
||||
|
||||
Sample code
|
||||
|
||||
/* hid_gadget_test */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BUF_LEN 512
|
||||
|
||||
struct options {
|
||||
const char *opt;
|
||||
unsigned char val;
|
||||
};
|
||||
|
||||
static struct options kmod[] = {
|
||||
{.opt = "--left-ctrl", .val = 0x01},
|
||||
{.opt = "--right-ctrl", .val = 0x10},
|
||||
{.opt = "--left-shift", .val = 0x02},
|
||||
{.opt = "--right-shift", .val = 0x20},
|
||||
{.opt = "--left-alt", .val = 0x04},
|
||||
{.opt = "--right-alt", .val = 0x40},
|
||||
{.opt = "--left-meta", .val = 0x08},
|
||||
{.opt = "--right-meta", .val = 0x80},
|
||||
{.opt = NULL}
|
||||
};
|
||||
|
||||
static struct options kval[] = {
|
||||
{.opt = "--return", .val = 0x28},
|
||||
{.opt = "--esc", .val = 0x29},
|
||||
{.opt = "--bckspc", .val = 0x2a},
|
||||
{.opt = "--tab", .val = 0x2b},
|
||||
{.opt = "--spacebar", .val = 0x2c},
|
||||
{.opt = "--caps-lock", .val = 0x39},
|
||||
{.opt = "--f1", .val = 0x3a},
|
||||
{.opt = "--f2", .val = 0x3b},
|
||||
{.opt = "--f3", .val = 0x3c},
|
||||
{.opt = "--f4", .val = 0x3d},
|
||||
{.opt = "--f5", .val = 0x3e},
|
||||
{.opt = "--f6", .val = 0x3f},
|
||||
{.opt = "--f7", .val = 0x40},
|
||||
{.opt = "--f8", .val = 0x41},
|
||||
{.opt = "--f9", .val = 0x42},
|
||||
{.opt = "--f10", .val = 0x43},
|
||||
{.opt = "--f11", .val = 0x44},
|
||||
{.opt = "--f12", .val = 0x45},
|
||||
{.opt = "--insert", .val = 0x49},
|
||||
{.opt = "--home", .val = 0x4a},
|
||||
{.opt = "--pageup", .val = 0x4b},
|
||||
{.opt = "--del", .val = 0x4c},
|
||||
{.opt = "--end", .val = 0x4d},
|
||||
{.opt = "--pagedown", .val = 0x4e},
|
||||
{.opt = "--right", .val = 0x4f},
|
||||
{.opt = "--left", .val = 0x50},
|
||||
{.opt = "--down", .val = 0x51},
|
||||
{.opt = "--kp-enter", .val = 0x58},
|
||||
{.opt = "--up", .val = 0x52},
|
||||
{.opt = "--num-lock", .val = 0x53},
|
||||
{.opt = NULL}
|
||||
};
|
||||
|
||||
int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
|
||||
{
|
||||
char *tok = strtok(buf, " ");
|
||||
int key = 0;
|
||||
int i = 0;
|
||||
|
||||
for (; tok != NULL; tok = strtok(NULL, " ")) {
|
||||
|
||||
if (strcmp(tok, "--quit") == 0)
|
||||
return -1;
|
||||
|
||||
if (strcmp(tok, "--hold") == 0) {
|
||||
*hold = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key < 6) {
|
||||
for (i = 0; kval[i].opt != NULL; i++)
|
||||
if (strcmp(tok, kval[i].opt) == 0) {
|
||||
report[2 + key++] = kval[i].val;
|
||||
break;
|
||||
}
|
||||
if (kval[i].opt != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key < 6)
|
||||
if (islower(tok[0])) {
|
||||
report[2 + key++] = (tok[0] - ('a' - 0x04));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; kmod[i].opt != NULL; i++)
|
||||
if (strcmp(tok, kmod[i].opt) == 0) {
|
||||
report[0] = report[0] | kmod[i].val;
|
||||
break;
|
||||
}
|
||||
if (kmod[i].opt != NULL)
|
||||
continue;
|
||||
|
||||
if (key < 6)
|
||||
fprintf(stderr, "unknown option: %s\n", tok);
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
|
||||
static struct options mmod[] = {
|
||||
{.opt = "--b1", .val = 0x01},
|
||||
{.opt = "--b2", .val = 0x02},
|
||||
{.opt = "--b3", .val = 0x04},
|
||||
{.opt = NULL}
|
||||
};
|
||||
|
||||
int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
|
||||
{
|
||||
char *tok = strtok(buf, " ");
|
||||
int mvt = 0;
|
||||
int i = 0;
|
||||
for (; tok != NULL; tok = strtok(NULL, " ")) {
|
||||
|
||||
if (strcmp(tok, "--quit") == 0)
|
||||
return -1;
|
||||
|
||||
if (strcmp(tok, "--hold") == 0) {
|
||||
*hold = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; mmod[i].opt != NULL; i++)
|
||||
if (strcmp(tok, mmod[i].opt) == 0) {
|
||||
report[0] = report[0] | mmod[i].val;
|
||||
break;
|
||||
}
|
||||
if (mmod[i].opt != NULL)
|
||||
continue;
|
||||
|
||||
if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
|
||||
errno = 0;
|
||||
report[1 + mvt++] = (char)strtol(tok, NULL, 0);
|
||||
if (errno != 0) {
|
||||
fprintf(stderr, "Bad value:'%s'\n", tok);
|
||||
report[1 + mvt--] = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "unknown option: %s\n", tok);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
static struct options jmod[] = {
|
||||
{.opt = "--b1", .val = 0x10},
|
||||
{.opt = "--b2", .val = 0x20},
|
||||
{.opt = "--b3", .val = 0x40},
|
||||
{.opt = "--b4", .val = 0x80},
|
||||
{.opt = "--hat1", .val = 0x00},
|
||||
{.opt = "--hat2", .val = 0x01},
|
||||
{.opt = "--hat3", .val = 0x02},
|
||||
{.opt = "--hat4", .val = 0x03},
|
||||
{.opt = "--hatneutral", .val = 0x04},
|
||||
{.opt = NULL}
|
||||
};
|
||||
|
||||
int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
|
||||
{
|
||||
char *tok = strtok(buf, " ");
|
||||
int mvt = 0;
|
||||
int i = 0;
|
||||
|
||||
*hold = 1;
|
||||
|
||||
/* set default hat position: neutral */
|
||||
report[3] = 0x04;
|
||||
|
||||
for (; tok != NULL; tok = strtok(NULL, " ")) {
|
||||
|
||||
if (strcmp(tok, "--quit") == 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; jmod[i].opt != NULL; i++)
|
||||
if (strcmp(tok, jmod[i].opt) == 0) {
|
||||
report[3] = (report[3] & 0xF0) | jmod[i].val;
|
||||
break;
|
||||
}
|
||||
if (jmod[i].opt != NULL)
|
||||
continue;
|
||||
|
||||
if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
|
||||
errno = 0;
|
||||
report[mvt++] = (char)strtol(tok, NULL, 0);
|
||||
if (errno != 0) {
|
||||
fprintf(stderr, "Bad value:'%s'\n", tok);
|
||||
report[mvt--] = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "unknown option: %s\n", tok);
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
void print_options(char c)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (c == 'k') {
|
||||
printf(" keyboard options:\n"
|
||||
" --hold\n");
|
||||
for (i = 0; kmod[i].opt != NULL; i++)
|
||||
printf("\t\t%s\n", kmod[i].opt);
|
||||
printf("\n keyboard values:\n"
|
||||
" [a-z] or\n");
|
||||
for (i = 0; kval[i].opt != NULL; i++)
|
||||
printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
|
||||
printf("\n");
|
||||
} else if (c == 'm') {
|
||||
printf(" mouse options:\n"
|
||||
" --hold\n");
|
||||
for (i = 0; mmod[i].opt != NULL; i++)
|
||||
printf("\t\t%s\n", mmod[i].opt);
|
||||
printf("\n mouse values:\n"
|
||||
" Two signed numbers\n"
|
||||
"--quit to close\n");
|
||||
} else {
|
||||
printf(" joystick options:\n");
|
||||
for (i = 0; jmod[i].opt != NULL; i++)
|
||||
printf("\t\t%s\n", jmod[i].opt);
|
||||
printf("\n joystick values:\n"
|
||||
" three signed numbers\n"
|
||||
"--quit to close\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char *filename = NULL;
|
||||
int fd = 0;
|
||||
char buf[BUF_LEN];
|
||||
int cmd_len;
|
||||
char report[8];
|
||||
int to_send = 8;
|
||||
int hold = 0;
|
||||
fd_set rfds;
|
||||
int retval, i;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
|
||||
return 2;
|
||||
|
||||
filename = argv[1];
|
||||
|
||||
if ((fd = open(filename, O_RDWR, 0666)) == -1) {
|
||||
perror(filename);
|
||||
return 3;
|
||||
}
|
||||
|
||||
print_options(argv[2][0]);
|
||||
|
||||
while (42) {
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(STDIN_FILENO, &rfds);
|
||||
FD_SET(fd, &rfds);
|
||||
|
||||
retval = select(fd + 1, &rfds, NULL, NULL, NULL);
|
||||
if (retval == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (retval < 0) {
|
||||
perror("select()");
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fd, &rfds)) {
|
||||
cmd_len = read(fd, buf, BUF_LEN - 1);
|
||||
printf("recv report:");
|
||||
for (i = 0; i < cmd_len; i++)
|
||||
printf(" %02x", buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO, &rfds)) {
|
||||
memset(report, 0x0, sizeof(report));
|
||||
cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
|
||||
|
||||
if (cmd_len == 0)
|
||||
break;
|
||||
|
||||
buf[cmd_len - 1] = '\0';
|
||||
hold = 0;
|
||||
|
||||
memset(report, 0x0, sizeof(report));
|
||||
if (argv[2][0] == 'k')
|
||||
to_send = keyboard_fill_report(report, buf, &hold);
|
||||
else if (argv[2][0] == 'm')
|
||||
to_send = mouse_fill_report(report, buf, &hold);
|
||||
else
|
||||
to_send = joystick_fill_report(report, buf, &hold);
|
||||
|
||||
if (to_send == -1)
|
||||
break;
|
||||
|
||||
if (write(fd, report, to_send) != to_send) {
|
||||
perror(filename);
|
||||
return 5;
|
||||
}
|
||||
if (!hold) {
|
||||
memset(report, 0x0, sizeof(report));
|
||||
if (write(fd, report, to_send) != to_send) {
|
||||
perror(filename);
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
@ -107,7 +107,9 @@ allowed to issue dynamic suspends.
|
||||
The user interface for controlling dynamic PM is located in the power/
|
||||
subdirectory of each USB device's sysfs directory, that is, in
|
||||
/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
|
||||
relevant attribute files are: wakeup, level, and autosuspend.
|
||||
relevant attribute files are: wakeup, control, and autosuspend.
|
||||
(There may also be a file named "level"; this file was deprecated
|
||||
as of the 2.6.35 kernel and replaced by the "control" file.)
|
||||
|
||||
power/wakeup
|
||||
|
||||
@ -120,7 +122,7 @@ relevant attribute files are: wakeup, level, and autosuspend.
|
||||
while the device is suspended, the change won't take
|
||||
effect until the following suspend.)
|
||||
|
||||
power/level
|
||||
power/control
|
||||
|
||||
This file contains one of two words: "on" or "auto".
|
||||
You can write those words to the file to change the
|
||||
@ -148,14 +150,15 @@ relevant attribute files are: wakeup, level, and autosuspend.
|
||||
never to autosuspend. You can write a number to the
|
||||
file to change the autosuspend idle-delay time.
|
||||
|
||||
Writing "-1" to power/autosuspend and writing "on" to power/level do
|
||||
Writing "-1" to power/autosuspend and writing "on" to power/control do
|
||||
essentially the same thing -- they both prevent the device from being
|
||||
autosuspended. Yes, this is a redundancy in the API.
|
||||
|
||||
(In 2.6.21 writing "0" to power/autosuspend would prevent the device
|
||||
from being autosuspended; the behavior was changed in 2.6.22. The
|
||||
power/autosuspend attribute did not exist prior to 2.6.21, and the
|
||||
power/level attribute did not exist prior to 2.6.22.)
|
||||
power/level attribute did not exist prior to 2.6.22. power/control
|
||||
was added in 2.6.34.)
|
||||
|
||||
|
||||
Changing the default idle-delay time
|
||||
@ -212,7 +215,7 @@ among printers and scanners, but plenty of other types of device have
|
||||
the same deficiency.
|
||||
|
||||
For this reason, by default the kernel disables autosuspend (the
|
||||
power/level attribute is initialized to "on") for all devices other
|
||||
power/control attribute is initialized to "on") for all devices other
|
||||
than hubs. Hubs, at least, appear to be reasonably well-behaved in
|
||||
this regard.
|
||||
|
||||
@ -373,7 +376,7 @@ usb_autopm_put_interface() in its close or release routine. But other
|
||||
patterns are possible.
|
||||
|
||||
The autosuspend attempts mentioned above will often fail for one
|
||||
reason or another. For example, the power/level attribute might be
|
||||
reason or another. For example, the power/control attribute might be
|
||||
set to "on", or another interface in the same device might not be
|
||||
idle. This is perfectly normal. If the reason for failure was that
|
||||
the device hasn't been idle for long enough, a timer is scheduled to
|
||||
@ -394,12 +397,12 @@ Drivers can enable autosuspend for their devices by calling
|
||||
|
||||
in their probe() routine, if they know that the device is capable of
|
||||
suspending and resuming correctly. This is exactly equivalent to
|
||||
writing "auto" to the device's power/level attribute. Likewise,
|
||||
writing "auto" to the device's power/control attribute. Likewise,
|
||||
drivers can disable autosuspend by calling
|
||||
|
||||
usb_disable_autosuspend(struct usb_device *udev);
|
||||
|
||||
This is exactly the same as writing "on" to the power/level attribute.
|
||||
This is exactly the same as writing "on" to the power/control attribute.
|
||||
|
||||
Sometimes a driver needs to make sure that remote wakeup is enabled
|
||||
during autosuspend. For example, there's not much point
|
||||
|
@ -194,6 +194,10 @@ FTDI Single Port Serial Driver
|
||||
|
||||
This is a single port DB-25 serial adapter.
|
||||
|
||||
Devices supported include:
|
||||
-TripNav TN-200 USB GPS
|
||||
-Navis Engineering Bureau CH-4711 USB GPS
|
||||
|
||||
For any questions or problems with this driver, please contact Bill Ryder.
|
||||
|
||||
|
||||
@ -216,7 +220,7 @@ Cypress M8 CY4601 Family Serial Driver
|
||||
|
||||
Devices supported:
|
||||
|
||||
-DeLorme's USB Earthmate (SiRF Star II lp arch)
|
||||
-DeLorme's USB Earthmate GPS (SiRF Star II lp arch)
|
||||
-Cypress HID->COM RS232 adapter
|
||||
|
||||
Note: Cypress Semiconductor claims no affiliation with the
|
||||
@ -392,9 +396,10 @@ REINER SCT cyberJack pinpad/e-com USB chipcard reader
|
||||
Prolific PL2303 Driver
|
||||
|
||||
This driver supports any device that has the PL2303 chip from Prolific
|
||||
in it. This includes a number of single port USB to serial
|
||||
converters and USB GPS devices. Devices from Aten (the UC-232) and
|
||||
IO-Data work with this driver, as does the DCU-11 mobile-phone cable.
|
||||
in it. This includes a number of single port USB to serial converters,
|
||||
more than 70% of USB GPS devices (in 2010), and some USB UPSes. Devices
|
||||
from Aten (the UC-232) and IO-Data work with this driver, as does
|
||||
the DCU-11 mobile-phone cable.
|
||||
|
||||
For any questions or problems with this driver, please contact Greg
|
||||
Kroah-Hartman at greg@kroah.com
|
||||
@ -435,6 +440,22 @@ Winchiphead CH341 Driver
|
||||
For any questions or problems with this driver, please contact
|
||||
frank@kingswood-consulting.co.uk.
|
||||
|
||||
Moschip MCS7720, MCS7715 driver
|
||||
|
||||
These chips are present in devices sold by various manufacturers, such as Syba
|
||||
and Cables Unlimited. There may be others. The 7720 provides two serial
|
||||
ports, and the 7715 provides one serial and one standard PC parallel port.
|
||||
Support for the 7715's parallel port is enabled by a separate option, which
|
||||
will not appear unless parallel port support is first enabled at the top-level
|
||||
of the Device Drivers config menu. Currently only compatibility mode is
|
||||
supported on the parallel port (no ECP/EPP).
|
||||
|
||||
TODO:
|
||||
- Implement ECP/EPP modes for the parallel port.
|
||||
- Baud rates higher than 115200 are currently broken.
|
||||
- Devices with a single serial port based on the Moschip MCS7703 may work
|
||||
with this driver with a simple addition to the usb_device_id table. I
|
||||
don't have one of these devices, so I can't say for sure.
|
||||
|
||||
Generic Serial driver
|
||||
|
||||
|
@ -702,6 +702,9 @@ static void __init omap3_evm_init(void)
|
||||
omap_mux_init_gpio(21, OMAP_PIN_INPUT_PULLUP);
|
||||
ehci_pdata.reset_gpio_port[1] = 21;
|
||||
|
||||
/* EVM REV >= E can supply 500mA with EXTVBUS programming */
|
||||
musb_board_data.power = 500;
|
||||
musb_board_data.extvbus = 1;
|
||||
} else {
|
||||
/* setup EHCI phy reset on MDC */
|
||||
omap_mux_init_gpio(135, OMAP_PIN_OUTPUT);
|
||||
|
@ -236,3 +236,158 @@ void __init usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata)
|
||||
|
||||
#endif /* CONFIG_USB_EHCI_HCD */
|
||||
|
||||
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
|
||||
|
||||
static struct resource ohci_resources[] = {
|
||||
{
|
||||
.start = OMAP34XX_OHCI_BASE,
|
||||
.end = OMAP34XX_OHCI_BASE + SZ_1K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = OMAP34XX_UHH_CONFIG_BASE,
|
||||
.end = OMAP34XX_UHH_CONFIG_BASE + SZ_1K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = OMAP34XX_USBTLL_BASE,
|
||||
.end = OMAP34XX_USBTLL_BASE + SZ_4K - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{ /* general IRQ */
|
||||
.start = INT_34XX_OHCI_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static u64 ohci_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device ohci_device = {
|
||||
.name = "ohci-omap3",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &ohci_dmamask,
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(ohci_resources),
|
||||
.resource = ohci_resources,
|
||||
};
|
||||
|
||||
static void setup_ohci_io_mux(const enum ohci_omap3_port_mode *port_mode)
|
||||
{
|
||||
switch (port_mode[0]) {
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
|
||||
omap_mux_init_signal("mm1_rxdp",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
omap_mux_init_signal("mm1_rxdm",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
|
||||
omap_mux_init_signal("mm1_rxrcv",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
|
||||
omap_mux_init_signal("mm1_txen_n", OMAP_PIN_OUTPUT);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
|
||||
omap_mux_init_signal("mm1_txse0",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
omap_mux_init_signal("mm1_txdat",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
break;
|
||||
case OMAP_OHCI_PORT_MODE_UNUSED:
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (port_mode[1]) {
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
|
||||
omap_mux_init_signal("mm2_rxdp",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
omap_mux_init_signal("mm2_rxdm",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
|
||||
omap_mux_init_signal("mm2_rxrcv",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
|
||||
omap_mux_init_signal("mm2_txen_n", OMAP_PIN_OUTPUT);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
|
||||
omap_mux_init_signal("mm2_txse0",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
omap_mux_init_signal("mm2_txdat",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
break;
|
||||
case OMAP_OHCI_PORT_MODE_UNUSED:
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (port_mode[2]) {
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
|
||||
omap_mux_init_signal("mm3_rxdp",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
omap_mux_init_signal("mm3_rxdm",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
|
||||
omap_mux_init_signal("mm3_rxrcv",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
|
||||
omap_mux_init_signal("mm3_txen_n", OMAP_PIN_OUTPUT);
|
||||
/* FALLTHROUGH */
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
|
||||
case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
|
||||
omap_mux_init_signal("mm3_txse0",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
omap_mux_init_signal("mm3_txdat",
|
||||
OMAP_PIN_INPUT_PULLDOWN);
|
||||
break;
|
||||
case OMAP_OHCI_PORT_MODE_UNUSED:
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void __init usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata)
|
||||
{
|
||||
platform_device_add_data(&ohci_device, pdata, sizeof(*pdata));
|
||||
|
||||
/* Setup Pin IO MUX for OHCI */
|
||||
if (cpu_is_omap34xx())
|
||||
setup_ohci_io_mux(pdata->port_mode);
|
||||
|
||||
if (platform_device_register(&ohci_device) < 0) {
|
||||
pr_err("Unable to register FS-USB (OHCI) device\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void __init usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_OHCI_HCD */
|
||||
|
@ -107,6 +107,7 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
|
||||
musb_plat.board_data = board_data;
|
||||
musb_plat.power = board_data->power >> 1;
|
||||
musb_plat.mode = board_data->mode;
|
||||
musb_plat.extvbus = board_data->extvbus;
|
||||
|
||||
if (platform_device_register(&musb_device) < 0)
|
||||
printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
|
||||
|
@ -13,6 +13,20 @@ enum ehci_hcd_omap_mode {
|
||||
EHCI_HCD_OMAP_MODE_TLL,
|
||||
};
|
||||
|
||||
enum ohci_omap3_port_mode {
|
||||
OMAP_OHCI_PORT_MODE_UNUSED,
|
||||
OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0,
|
||||
OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM,
|
||||
OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0,
|
||||
OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM,
|
||||
OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0,
|
||||
OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM,
|
||||
OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0,
|
||||
OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM,
|
||||
OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0,
|
||||
OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM,
|
||||
};
|
||||
|
||||
struct ehci_hcd_omap_platform_data {
|
||||
enum ehci_hcd_omap_mode port_mode[OMAP3_HS_USB_PORTS];
|
||||
unsigned phy_reset:1;
|
||||
@ -21,6 +35,13 @@ struct ehci_hcd_omap_platform_data {
|
||||
int reset_gpio_port[OMAP3_HS_USB_PORTS];
|
||||
};
|
||||
|
||||
struct ohci_hcd_omap_platform_data {
|
||||
enum ohci_omap3_port_mode port_mode[OMAP3_HS_USB_PORTS];
|
||||
|
||||
/* Set this to true for ES2.x silicon */
|
||||
unsigned es2_compatibility:1;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define OMAP1_OTG_BASE 0xfffb0400
|
||||
@ -47,6 +68,7 @@ struct omap_musb_board_data {
|
||||
u8 interface_type;
|
||||
u8 mode;
|
||||
u16 power;
|
||||
unsigned extvbus:1;
|
||||
};
|
||||
|
||||
enum musb_interface {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI};
|
||||
@ -55,6 +77,8 @@ extern void usb_musb_init(struct omap_musb_board_data *board_data);
|
||||
|
||||
extern void usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata);
|
||||
|
||||
extern void usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata);
|
||||
|
||||
#endif
|
||||
|
||||
void omap_usb_init(struct omap_usb_config *pdata);
|
||||
|
@ -783,13 +783,12 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
|
||||
usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
|
||||
usbhid->inbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
|
||||
&usbhid->inbuf_dma);
|
||||
usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
|
||||
usbhid->outbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
|
||||
&usbhid->outbuf_dma);
|
||||
usbhid->cr = usb_buffer_alloc(dev, sizeof(*usbhid->cr), GFP_KERNEL,
|
||||
&usbhid->cr_dma);
|
||||
usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
|
||||
usbhid->cr = kmalloc(sizeof(*usbhid->cr), GFP_KERNEL);
|
||||
usbhid->ctrlbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
|
||||
&usbhid->ctrlbuf_dma);
|
||||
if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr ||
|
||||
!usbhid->ctrlbuf)
|
||||
@ -844,10 +843,10 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
|
||||
usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
|
||||
usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
|
||||
usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
|
||||
usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
|
||||
usb_free_coherent(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
|
||||
usb_free_coherent(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
|
||||
kfree(usbhid->cr);
|
||||
usb_free_coherent(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
|
||||
}
|
||||
|
||||
static int usbhid_parse(struct hid_device *hid)
|
||||
@ -1007,9 +1006,8 @@ static int usbhid_start(struct hid_device *hid)
|
||||
|
||||
usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
|
||||
usbhid->ctrlbuf, 1, hid_ctrl, hid);
|
||||
usbhid->urbctrl->setup_dma = usbhid->cr_dma;
|
||||
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
|
||||
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
|
||||
usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
|
||||
usbhid_init_reports(hid);
|
||||
|
@ -75,7 +75,6 @@ struct usbhid_device {
|
||||
|
||||
struct urb *urbctrl; /* Control URB */
|
||||
struct usb_ctrlrequest *cr; /* Control request struct */
|
||||
dma_addr_t cr_dma; /* Control request struct dma */
|
||||
struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */
|
||||
unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
|
||||
char *ctrlbuf; /* Control buffer */
|
||||
|
@ -74,7 +74,6 @@ struct usb_kbd {
|
||||
unsigned char *new;
|
||||
struct usb_ctrlrequest *cr;
|
||||
unsigned char *leds;
|
||||
dma_addr_t cr_dma;
|
||||
dma_addr_t new_dma;
|
||||
dma_addr_t leds_dma;
|
||||
};
|
||||
@ -197,11 +196,11 @@ static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
|
||||
return -1;
|
||||
if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
|
||||
return -1;
|
||||
if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
|
||||
if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
|
||||
return -1;
|
||||
if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
|
||||
if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
|
||||
return -1;
|
||||
if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
|
||||
if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@ -211,9 +210,9 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
|
||||
{
|
||||
usb_free_urb(kbd->irq);
|
||||
usb_free_urb(kbd->led);
|
||||
usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
|
||||
usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
|
||||
usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
|
||||
usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
|
||||
kfree(kbd->cr);
|
||||
usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
|
||||
}
|
||||
|
||||
static int usb_kbd_probe(struct usb_interface *iface,
|
||||
@ -304,9 +303,8 @@ static int usb_kbd_probe(struct usb_interface *iface,
|
||||
usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
|
||||
(void *) kbd->cr, kbd->leds, 1,
|
||||
usb_kbd_led, kbd);
|
||||
kbd->led->setup_dma = kbd->cr_dma;
|
||||
kbd->led->transfer_dma = kbd->leds_dma;
|
||||
kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
|
||||
kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
error = input_register_device(kbd->dev);
|
||||
if (error)
|
||||
|
@ -142,7 +142,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
|
||||
if (!mouse || !input_dev)
|
||||
goto fail1;
|
||||
|
||||
mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
|
||||
mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
|
||||
if (!mouse->data)
|
||||
goto fail1;
|
||||
|
||||
@ -205,7 +205,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
|
||||
fail3:
|
||||
usb_free_urb(mouse->irq);
|
||||
fail2:
|
||||
usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
|
||||
usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
|
||||
fail1:
|
||||
input_free_device(input_dev);
|
||||
kfree(mouse);
|
||||
@ -221,7 +221,7 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
|
||||
usb_kill_urb(mouse->irq);
|
||||
input_unregister_device(mouse->dev);
|
||||
usb_free_urb(mouse->irq);
|
||||
usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
|
||||
usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
|
||||
kfree(mouse);
|
||||
}
|
||||
}
|
||||
|
@ -533,8 +533,8 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
|
||||
return 0;
|
||||
|
||||
xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
|
||||
GFP_KERNEL, &xpad->odata_dma);
|
||||
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
GFP_KERNEL, &xpad->odata_dma);
|
||||
if (!xpad->odata)
|
||||
goto fail1;
|
||||
|
||||
@ -554,7 +554,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
|
||||
return 0;
|
||||
|
||||
fail2: usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
||||
fail2: usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
||||
fail1: return error;
|
||||
}
|
||||
|
||||
@ -568,7 +568,7 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
|
||||
{
|
||||
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
|
||||
usb_free_urb(xpad->irq_out);
|
||||
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
|
||||
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
xpad->odata, xpad->odata_dma);
|
||||
}
|
||||
}
|
||||
@ -788,8 +788,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
if (!xpad || !input_dev)
|
||||
goto fail1;
|
||||
|
||||
xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
|
||||
GFP_KERNEL, &xpad->idata_dma);
|
||||
xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
|
||||
GFP_KERNEL, &xpad->idata_dma);
|
||||
if (!xpad->idata)
|
||||
goto fail1;
|
||||
|
||||
@ -942,7 +942,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
fail5: usb_kill_urb(xpad->irq_in);
|
||||
fail4: usb_free_urb(xpad->irq_in);
|
||||
fail3: xpad_deinit_output(xpad);
|
||||
fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
|
||||
fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
|
||||
fail1: input_free_device(input_dev);
|
||||
kfree(xpad);
|
||||
return error;
|
||||
@ -964,7 +964,7 @@ static void xpad_disconnect(struct usb_interface *intf)
|
||||
usb_kill_urb(xpad->irq_in);
|
||||
}
|
||||
usb_free_urb(xpad->irq_in);
|
||||
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
|
||||
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
xpad->idata, xpad->idata_dma);
|
||||
kfree(xpad);
|
||||
}
|
||||
|
@ -624,13 +624,13 @@ static void ati_remote_irq_in(struct urb *urb)
|
||||
static int ati_remote_alloc_buffers(struct usb_device *udev,
|
||||
struct ati_remote *ati_remote)
|
||||
{
|
||||
ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
|
||||
&ati_remote->inbuf_dma);
|
||||
ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
|
||||
&ati_remote->inbuf_dma);
|
||||
if (!ati_remote->inbuf)
|
||||
return -1;
|
||||
|
||||
ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
|
||||
&ati_remote->outbuf_dma);
|
||||
ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC,
|
||||
&ati_remote->outbuf_dma);
|
||||
if (!ati_remote->outbuf)
|
||||
return -1;
|
||||
|
||||
@ -653,10 +653,10 @@ static void ati_remote_free_buffers(struct ati_remote *ati_remote)
|
||||
usb_free_urb(ati_remote->irq_urb);
|
||||
usb_free_urb(ati_remote->out_urb);
|
||||
|
||||
usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
|
||||
usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
|
||||
ati_remote->inbuf, ati_remote->inbuf_dma);
|
||||
|
||||
usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
|
||||
usb_free_coherent(ati_remote->udev, DATA_BUFSIZE,
|
||||
ati_remote->outbuf, ati_remote->outbuf_dma);
|
||||
}
|
||||
|
||||
|
@ -589,7 +589,7 @@ static int ati_remote2_urb_init(struct ati_remote2 *ar2)
|
||||
int i, pipe, maxp;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
|
||||
ar2->buf[i] = usb_alloc_coherent(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
|
||||
if (!ar2->buf[i])
|
||||
return -ENOMEM;
|
||||
|
||||
@ -617,7 +617,7 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
usb_free_urb(ar2->urb[i]);
|
||||
usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
|
||||
usb_free_coherent(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,6 @@ struct cm109_dev {
|
||||
struct cm109_ctl_packet *ctl_data;
|
||||
dma_addr_t ctl_dma;
|
||||
struct usb_ctrlrequest *ctl_req;
|
||||
dma_addr_t ctl_req_dma;
|
||||
struct urb *urb_ctl;
|
||||
/*
|
||||
* The 3 bitfields below are protected by ctl_submit_lock.
|
||||
@ -629,15 +628,13 @@ static const struct usb_device_id cm109_usb_table[] = {
|
||||
|
||||
static void cm109_usb_cleanup(struct cm109_dev *dev)
|
||||
{
|
||||
if (dev->ctl_req)
|
||||
usb_buffer_free(dev->udev, sizeof(*(dev->ctl_req)),
|
||||
dev->ctl_req, dev->ctl_req_dma);
|
||||
kfree(dev->ctl_req);
|
||||
if (dev->ctl_data)
|
||||
usb_buffer_free(dev->udev, USB_PKT_LEN,
|
||||
dev->ctl_data, dev->ctl_dma);
|
||||
usb_free_coherent(dev->udev, USB_PKT_LEN,
|
||||
dev->ctl_data, dev->ctl_dma);
|
||||
if (dev->irq_data)
|
||||
usb_buffer_free(dev->udev, USB_PKT_LEN,
|
||||
dev->irq_data, dev->irq_dma);
|
||||
usb_free_coherent(dev->udev, USB_PKT_LEN,
|
||||
dev->irq_data, dev->irq_dma);
|
||||
|
||||
usb_free_urb(dev->urb_irq); /* parameter validation in core/urb */
|
||||
usb_free_urb(dev->urb_ctl); /* parameter validation in core/urb */
|
||||
@ -686,18 +683,17 @@ static int cm109_usb_probe(struct usb_interface *intf,
|
||||
goto err_out;
|
||||
|
||||
/* allocate usb buffers */
|
||||
dev->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
|
||||
GFP_KERNEL, &dev->irq_dma);
|
||||
dev->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
|
||||
GFP_KERNEL, &dev->irq_dma);
|
||||
if (!dev->irq_data)
|
||||
goto err_out;
|
||||
|
||||
dev->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
|
||||
GFP_KERNEL, &dev->ctl_dma);
|
||||
dev->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
|
||||
GFP_KERNEL, &dev->ctl_dma);
|
||||
if (!dev->ctl_data)
|
||||
goto err_out;
|
||||
|
||||
dev->ctl_req = usb_buffer_alloc(udev, sizeof(*(dev->ctl_req)),
|
||||
GFP_KERNEL, &dev->ctl_req_dma);
|
||||
dev->ctl_req = kmalloc(sizeof(*(dev->ctl_req)), GFP_KERNEL);
|
||||
if (!dev->ctl_req)
|
||||
goto err_out;
|
||||
|
||||
@ -735,10 +731,8 @@ static int cm109_usb_probe(struct usb_interface *intf,
|
||||
usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
|
||||
(void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
|
||||
cm109_urb_ctl_callback, dev);
|
||||
dev->urb_ctl->setup_dma = dev->ctl_req_dma;
|
||||
dev->urb_ctl->transfer_dma = dev->ctl_dma;
|
||||
dev->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP |
|
||||
URB_NO_TRANSFER_DMA_MAP;
|
||||
dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
dev->urb_ctl->dev = udev;
|
||||
|
||||
/* find out the physical bus location */
|
||||
|
@ -464,7 +464,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
|
||||
remote->in_endpoint = endpoint;
|
||||
remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */
|
||||
|
||||
remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
|
||||
remote->in_buffer = usb_alloc_coherent(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
|
||||
if (!remote->in_buffer) {
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
@ -543,7 +543,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
|
||||
return 0;
|
||||
|
||||
fail3: usb_free_urb(remote->irq_urb);
|
||||
fail2: usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
|
||||
fail2: usb_free_coherent(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
|
||||
fail1: kfree(remote);
|
||||
input_free_device(input_dev);
|
||||
|
||||
@ -564,7 +564,7 @@ static void keyspan_disconnect(struct usb_interface *interface)
|
||||
input_unregister_device(remote->input);
|
||||
usb_kill_urb(remote->irq_urb);
|
||||
usb_free_urb(remote->irq_urb);
|
||||
usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
|
||||
usb_free_coherent(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
|
||||
kfree(remote);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ struct powermate_device {
|
||||
dma_addr_t data_dma;
|
||||
struct urb *irq, *config;
|
||||
struct usb_ctrlrequest *configcr;
|
||||
dma_addr_t configcr_dma;
|
||||
struct usb_device *udev;
|
||||
struct input_dev *input;
|
||||
spinlock_t lock;
|
||||
@ -182,8 +181,6 @@ static void powermate_sync_state(struct powermate_device *pm)
|
||||
usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
|
||||
(void *) pm->configcr, NULL, 0,
|
||||
powermate_config_complete, pm);
|
||||
pm->config->setup_dma = pm->configcr_dma;
|
||||
pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP;
|
||||
|
||||
if (usb_submit_urb(pm->config, GFP_ATOMIC))
|
||||
printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
|
||||
@ -276,13 +273,12 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig
|
||||
|
||||
static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
|
||||
{
|
||||
pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX,
|
||||
GFP_ATOMIC, &pm->data_dma);
|
||||
pm->data = usb_alloc_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX,
|
||||
GFP_ATOMIC, &pm->data_dma);
|
||||
if (!pm->data)
|
||||
return -1;
|
||||
|
||||
pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)),
|
||||
GFP_ATOMIC, &pm->configcr_dma);
|
||||
pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL);
|
||||
if (!pm->configcr)
|
||||
return -1;
|
||||
|
||||
@ -291,10 +287,9 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev
|
||||
|
||||
static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
|
||||
{
|
||||
usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
|
||||
pm->data, pm->data_dma);
|
||||
usb_buffer_free(udev, sizeof(*(pm->configcr)),
|
||||
pm->configcr, pm->configcr_dma);
|
||||
usb_free_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX,
|
||||
pm->data, pm->data_dma);
|
||||
kfree(pm->configcr);
|
||||
}
|
||||
|
||||
/* Called whenever a USB device matching one in our supported devices table is connected */
|
||||
|
@ -111,7 +111,6 @@ struct yealink_dev {
|
||||
struct yld_ctl_packet *ctl_data;
|
||||
dma_addr_t ctl_dma;
|
||||
struct usb_ctrlrequest *ctl_req;
|
||||
dma_addr_t ctl_req_dma;
|
||||
struct urb *urb_ctl;
|
||||
|
||||
char phys[64]; /* physical device path */
|
||||
@ -836,12 +835,9 @@ static int usb_cleanup(struct yealink_dev *yld, int err)
|
||||
usb_free_urb(yld->urb_irq);
|
||||
usb_free_urb(yld->urb_ctl);
|
||||
|
||||
usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
|
||||
yld->ctl_req, yld->ctl_req_dma);
|
||||
usb_buffer_free(yld->udev, USB_PKT_LEN,
|
||||
yld->ctl_data, yld->ctl_dma);
|
||||
usb_buffer_free(yld->udev, USB_PKT_LEN,
|
||||
yld->irq_data, yld->irq_dma);
|
||||
kfree(yld->ctl_req);
|
||||
usb_free_coherent(yld->udev, USB_PKT_LEN, yld->ctl_data, yld->ctl_dma);
|
||||
usb_free_coherent(yld->udev, USB_PKT_LEN, yld->irq_data, yld->irq_dma);
|
||||
|
||||
kfree(yld);
|
||||
return err;
|
||||
@ -886,18 +882,17 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
return usb_cleanup(yld, -ENOMEM);
|
||||
|
||||
/* allocate usb buffers */
|
||||
yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
|
||||
GFP_ATOMIC, &yld->irq_dma);
|
||||
yld->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
|
||||
GFP_ATOMIC, &yld->irq_dma);
|
||||
if (yld->irq_data == NULL)
|
||||
return usb_cleanup(yld, -ENOMEM);
|
||||
|
||||
yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
|
||||
GFP_ATOMIC, &yld->ctl_dma);
|
||||
yld->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
|
||||
GFP_ATOMIC, &yld->ctl_dma);
|
||||
if (!yld->ctl_data)
|
||||
return usb_cleanup(yld, -ENOMEM);
|
||||
|
||||
yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)),
|
||||
GFP_ATOMIC, &yld->ctl_req_dma);
|
||||
yld->ctl_req = kmalloc(sizeof(*(yld->ctl_req)), GFP_KERNEL);
|
||||
if (yld->ctl_req == NULL)
|
||||
return usb_cleanup(yld, -ENOMEM);
|
||||
|
||||
@ -936,10 +931,8 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
|
||||
(void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
|
||||
urb_ctl_callback, yld);
|
||||
yld->urb_ctl->setup_dma = yld->ctl_req_dma;
|
||||
yld->urb_ctl->transfer_dma = yld->ctl_dma;
|
||||
yld->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP |
|
||||
URB_NO_TRANSFER_DMA_MAP;
|
||||
yld->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
yld->urb_ctl->dev = udev;
|
||||
|
||||
/* find out the physical bus location */
|
||||
|
@ -806,8 +806,8 @@ static int atp_probe(struct usb_interface *iface,
|
||||
if (!dev->urb)
|
||||
goto err_free_devs;
|
||||
|
||||
dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL,
|
||||
&dev->urb->transfer_dma);
|
||||
dev->data = usb_alloc_coherent(dev->udev, dev->info->datalen, GFP_KERNEL,
|
||||
&dev->urb->transfer_dma);
|
||||
if (!dev->data)
|
||||
goto err_free_urb;
|
||||
|
||||
@ -862,8 +862,8 @@ static int atp_probe(struct usb_interface *iface,
|
||||
return 0;
|
||||
|
||||
err_free_buffer:
|
||||
usb_buffer_free(dev->udev, dev->info->datalen,
|
||||
dev->data, dev->urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, dev->info->datalen,
|
||||
dev->data, dev->urb->transfer_dma);
|
||||
err_free_urb:
|
||||
usb_free_urb(dev->urb);
|
||||
err_free_devs:
|
||||
@ -881,8 +881,8 @@ static void atp_disconnect(struct usb_interface *iface)
|
||||
if (dev) {
|
||||
usb_kill_urb(dev->urb);
|
||||
input_unregister_device(dev->input);
|
||||
usb_buffer_free(dev->udev, dev->info->datalen,
|
||||
dev->data, dev->urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, dev->info->datalen,
|
||||
dev->data, dev->urb->transfer_dma);
|
||||
usb_free_urb(dev->urb);
|
||||
kfree(dev);
|
||||
}
|
||||
|
@ -715,15 +715,15 @@ static int bcm5974_probe(struct usb_interface *iface,
|
||||
if (!dev->tp_urb)
|
||||
goto err_free_bt_urb;
|
||||
|
||||
dev->bt_data = usb_buffer_alloc(dev->udev,
|
||||
dev->cfg.bt_datalen, GFP_KERNEL,
|
||||
&dev->bt_urb->transfer_dma);
|
||||
dev->bt_data = usb_alloc_coherent(dev->udev,
|
||||
dev->cfg.bt_datalen, GFP_KERNEL,
|
||||
&dev->bt_urb->transfer_dma);
|
||||
if (!dev->bt_data)
|
||||
goto err_free_urb;
|
||||
|
||||
dev->tp_data = usb_buffer_alloc(dev->udev,
|
||||
dev->cfg.tp_datalen, GFP_KERNEL,
|
||||
&dev->tp_urb->transfer_dma);
|
||||
dev->tp_data = usb_alloc_coherent(dev->udev,
|
||||
dev->cfg.tp_datalen, GFP_KERNEL,
|
||||
&dev->tp_urb->transfer_dma);
|
||||
if (!dev->tp_data)
|
||||
goto err_free_bt_buffer;
|
||||
|
||||
@ -765,10 +765,10 @@ static int bcm5974_probe(struct usb_interface *iface,
|
||||
return 0;
|
||||
|
||||
err_free_buffer:
|
||||
usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
|
||||
usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
|
||||
dev->tp_data, dev->tp_urb->transfer_dma);
|
||||
err_free_bt_buffer:
|
||||
usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
|
||||
usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
|
||||
dev->bt_data, dev->bt_urb->transfer_dma);
|
||||
err_free_urb:
|
||||
usb_free_urb(dev->tp_urb);
|
||||
@ -788,10 +788,10 @@ static void bcm5974_disconnect(struct usb_interface *iface)
|
||||
usb_set_intfdata(iface, NULL);
|
||||
|
||||
input_unregister_device(dev->input);
|
||||
usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
|
||||
dev->tp_data, dev->tp_urb->transfer_dma);
|
||||
usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
|
||||
dev->bt_data, dev->bt_urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
|
||||
dev->tp_data, dev->tp_urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
|
||||
dev->bt_data, dev->bt_urb->transfer_dma);
|
||||
usb_free_urb(dev->tp_urb);
|
||||
usb_free_urb(dev->bt_urb);
|
||||
kfree(dev);
|
||||
|
@ -155,7 +155,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
|
||||
acecad->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &acecad->data_dma);
|
||||
if (!acecad->data) {
|
||||
err= -ENOMEM;
|
||||
goto fail1;
|
||||
@ -235,7 +235,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
|
||||
|
||||
return 0;
|
||||
|
||||
fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
|
||||
fail2: usb_free_coherent(dev, 8, acecad->data, acecad->data_dma);
|
||||
fail1: input_free_device(input_dev);
|
||||
kfree(acecad);
|
||||
return err;
|
||||
@ -249,7 +249,7 @@ static void usb_acecad_disconnect(struct usb_interface *intf)
|
||||
|
||||
input_unregister_device(acecad->input);
|
||||
usb_free_urb(acecad->irq);
|
||||
usb_buffer_free(acecad->usbdev, 8, acecad->data, acecad->data_dma);
|
||||
usb_free_coherent(acecad->usbdev, 8, acecad->data, acecad->data_dma);
|
||||
kfree(acecad);
|
||||
}
|
||||
|
||||
|
@ -1711,8 +1711,8 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
|
||||
GFP_ATOMIC, &aiptek->data_dma);
|
||||
aiptek->data = usb_alloc_coherent(usbdev, AIPTEK_PACKET_LENGTH,
|
||||
GFP_ATOMIC, &aiptek->data_dma);
|
||||
if (!aiptek->data) {
|
||||
dev_warn(&intf->dev, "cannot allocate usb buffer\n");
|
||||
goto fail1;
|
||||
@ -1884,8 +1884,8 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
|
||||
fail4: sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group);
|
||||
fail3: usb_free_urb(aiptek->urb);
|
||||
fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
|
||||
aiptek->data_dma);
|
||||
fail2: usb_free_coherent(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
|
||||
aiptek->data_dma);
|
||||
fail1: usb_set_intfdata(intf, NULL);
|
||||
input_free_device(inputdev);
|
||||
kfree(aiptek);
|
||||
@ -1909,9 +1909,9 @@ static void aiptek_disconnect(struct usb_interface *intf)
|
||||
input_unregister_device(aiptek->inputdev);
|
||||
sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group);
|
||||
usb_free_urb(aiptek->urb);
|
||||
usb_buffer_free(interface_to_usbdev(intf),
|
||||
AIPTEK_PACKET_LENGTH,
|
||||
aiptek->data, aiptek->data_dma);
|
||||
usb_free_coherent(interface_to_usbdev(intf),
|
||||
AIPTEK_PACKET_LENGTH,
|
||||
aiptek->data, aiptek->data_dma);
|
||||
kfree(aiptek);
|
||||
}
|
||||
}
|
||||
|
@ -850,8 +850,8 @@ static int gtco_probe(struct usb_interface *usbinterface,
|
||||
gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
|
||||
|
||||
/* Allocate some data for incoming reports */
|
||||
gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE,
|
||||
GFP_KERNEL, >co->buf_dma);
|
||||
gtco->buffer = usb_alloc_coherent(gtco->usbdev, REPORT_MAX_SIZE,
|
||||
GFP_KERNEL, >co->buf_dma);
|
||||
if (!gtco->buffer) {
|
||||
err("No more memory for us buffers");
|
||||
error = -ENOMEM;
|
||||
@ -982,8 +982,8 @@ static int gtco_probe(struct usb_interface *usbinterface,
|
||||
err_free_urb:
|
||||
usb_free_urb(gtco->urbinfo);
|
||||
err_free_buf:
|
||||
usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
|
||||
gtco->buffer, gtco->buf_dma);
|
||||
usb_free_coherent(gtco->usbdev, REPORT_MAX_SIZE,
|
||||
gtco->buffer, gtco->buf_dma);
|
||||
err_free_devs:
|
||||
input_free_device(input_dev);
|
||||
kfree(gtco);
|
||||
@ -1005,8 +1005,8 @@ static void gtco_disconnect(struct usb_interface *interface)
|
||||
input_unregister_device(gtco->inputdevice);
|
||||
usb_kill_urb(gtco->urbinfo);
|
||||
usb_free_urb(gtco->urbinfo);
|
||||
usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
|
||||
gtco->buffer, gtco->buf_dma);
|
||||
usb_free_coherent(gtco->usbdev, REPORT_MAX_SIZE,
|
||||
gtco->buffer, gtco->buf_dma);
|
||||
kfree(gtco);
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
if (!kbtab || !input_dev)
|
||||
goto fail1;
|
||||
|
||||
kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
|
||||
kbtab->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbtab->data_dma);
|
||||
if (!kbtab->data)
|
||||
goto fail1;
|
||||
|
||||
@ -173,7 +173,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
return 0;
|
||||
|
||||
fail3: usb_free_urb(kbtab->irq);
|
||||
fail2: usb_buffer_free(dev, 8, kbtab->data, kbtab->data_dma);
|
||||
fail2: usb_free_coherent(dev, 8, kbtab->data, kbtab->data_dma);
|
||||
fail1: input_free_device(input_dev);
|
||||
kfree(kbtab);
|
||||
return error;
|
||||
@ -187,7 +187,7 @@ static void kbtab_disconnect(struct usb_interface *intf)
|
||||
|
||||
input_unregister_device(kbtab->dev);
|
||||
usb_free_urb(kbtab->irq);
|
||||
usb_buffer_free(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma);
|
||||
usb_free_coherent(kbtab->usbdev, 8, kbtab->data, kbtab->data_dma);
|
||||
kfree(kbtab);
|
||||
}
|
||||
|
||||
|
@ -465,8 +465,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX,
|
||||
GFP_KERNEL, &wacom->data_dma);
|
||||
wacom_wac->data = usb_alloc_coherent(dev, WACOM_PKGLEN_MAX,
|
||||
GFP_KERNEL, &wacom->data_dma);
|
||||
if (!wacom_wac->data) {
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
@ -536,7 +536,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
|
||||
fail4: wacom_remove_shared_data(wacom_wac);
|
||||
fail3: usb_free_urb(wacom->irq);
|
||||
fail2: usb_buffer_free(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
|
||||
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
|
||||
fail1: input_free_device(input_dev);
|
||||
kfree(wacom);
|
||||
return error;
|
||||
@ -551,7 +551,7 @@ static void wacom_disconnect(struct usb_interface *intf)
|
||||
usb_kill_urb(wacom->irq);
|
||||
input_unregister_device(wacom->wacom_wac.input);
|
||||
usb_free_urb(wacom->irq);
|
||||
usb_buffer_free(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
|
||||
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
|
||||
wacom->wacom_wac.data, wacom->data_dma);
|
||||
wacom_remove_shared_data(&wacom->wacom_wac);
|
||||
kfree(wacom);
|
||||
|
@ -1290,8 +1290,8 @@ static void usbtouch_close(struct input_dev *input)
|
||||
static void usbtouch_free_buffers(struct usb_device *udev,
|
||||
struct usbtouch_usb *usbtouch)
|
||||
{
|
||||
usb_buffer_free(udev, usbtouch->type->rept_size,
|
||||
usbtouch->data, usbtouch->data_dma);
|
||||
usb_free_coherent(udev, usbtouch->type->rept_size,
|
||||
usbtouch->data, usbtouch->data_dma);
|
||||
kfree(usbtouch->buffer);
|
||||
}
|
||||
|
||||
@ -1335,8 +1335,8 @@ static int usbtouch_probe(struct usb_interface *intf,
|
||||
if (!type->process_pkt)
|
||||
type->process_pkt = usbtouch_process_pkt;
|
||||
|
||||
usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
|
||||
GFP_KERNEL, &usbtouch->data_dma);
|
||||
usbtouch->data = usb_alloc_coherent(udev, type->rept_size,
|
||||
GFP_KERNEL, &usbtouch->data_dma);
|
||||
if (!usbtouch->data)
|
||||
goto out_free;
|
||||
|
||||
|
@ -96,8 +96,9 @@ static int usb_free_stream_buffers(struct usb_data_stream *stream)
|
||||
while (stream->buf_num) {
|
||||
stream->buf_num--;
|
||||
deb_mem("freeing buffer %d\n",stream->buf_num);
|
||||
usb_buffer_free(stream->udev, stream->buf_size,
|
||||
stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]);
|
||||
usb_free_coherent(stream->udev, stream->buf_size,
|
||||
stream->buf_list[stream->buf_num],
|
||||
stream->dma_addr[stream->buf_num]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +117,7 @@ static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num,
|
||||
for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
|
||||
deb_mem("allocating buffer %d\n",stream->buf_num);
|
||||
if (( stream->buf_list[stream->buf_num] =
|
||||
usb_buffer_alloc(stream->udev, size, GFP_ATOMIC,
|
||||
usb_alloc_coherent(stream->udev, size, GFP_ATOMIC,
|
||||
&stream->dma_addr[stream->buf_num]) ) == NULL) {
|
||||
deb_mem("not enough memory for urb-buffer allocation.\n");
|
||||
usb_free_stream_buffers(stream);
|
||||
|
@ -1257,7 +1257,7 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec)
|
||||
if(!dec->irq_urb) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE,
|
||||
dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE,
|
||||
GFP_ATOMIC, &dec->irq_dma_handle);
|
||||
if(!dec->irq_buffer) {
|
||||
usb_free_urb(dec->irq_urb);
|
||||
@ -1550,8 +1550,8 @@ static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
|
||||
|
||||
usb_free_urb(dec->irq_urb);
|
||||
|
||||
usb_buffer_free(dec->udev,IRQ_PACKET_SIZE,
|
||||
dec->irq_buffer, dec->irq_dma_handle);
|
||||
usb_free_coherent(dec->udev,IRQ_PACKET_SIZE,
|
||||
dec->irq_buffer, dec->irq_dma_handle);
|
||||
|
||||
if (dec->rc_input_dev) {
|
||||
input_unregister_device(dec->rc_input_dev);
|
||||
|
@ -177,7 +177,7 @@ void au0828_uninit_isoc(struct au0828_dev *dev)
|
||||
usb_unlink_urb(urb);
|
||||
|
||||
if (dev->isoc_ctl.transfer_buffer[i]) {
|
||||
usb_buffer_free(dev->usbdev,
|
||||
usb_free_coherent(dev->usbdev,
|
||||
urb->transfer_buffer_length,
|
||||
dev->isoc_ctl.transfer_buffer[i],
|
||||
urb->transfer_dma);
|
||||
@ -247,7 +247,7 @@ int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
|
||||
}
|
||||
dev->isoc_ctl.urb[i] = urb;
|
||||
|
||||
dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->usbdev,
|
||||
dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev,
|
||||
sb_size, GFP_KERNEL, &urb->transfer_dma);
|
||||
if (!dev->isoc_ctl.transfer_buffer[i]) {
|
||||
printk("unable to allocate %i bytes for transfer"
|
||||
|
@ -676,11 +676,11 @@ void cx231xx_uninit_isoc(struct cx231xx *dev)
|
||||
usb_unlink_urb(urb);
|
||||
|
||||
if (dev->video_mode.isoc_ctl.transfer_buffer[i]) {
|
||||
usb_buffer_free(dev->udev,
|
||||
urb->transfer_buffer_length,
|
||||
dev->video_mode.isoc_ctl.
|
||||
transfer_buffer[i],
|
||||
urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev,
|
||||
urb->transfer_buffer_length,
|
||||
dev->video_mode.isoc_ctl.
|
||||
transfer_buffer[i],
|
||||
urb->transfer_dma);
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
dev->video_mode.isoc_ctl.urb[i] = NULL;
|
||||
@ -767,8 +767,8 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
|
||||
dev->video_mode.isoc_ctl.urb[i] = urb;
|
||||
|
||||
dev->video_mode.isoc_ctl.transfer_buffer[i] =
|
||||
usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) {
|
||||
cx231xx_err("unable to allocate %i bytes for transfer"
|
||||
" buffer %i%s\n",
|
||||
|
@ -970,7 +970,7 @@ void em28xx_uninit_isoc(struct em28xx *dev)
|
||||
usb_unlink_urb(urb);
|
||||
|
||||
if (dev->isoc_ctl.transfer_buffer[i]) {
|
||||
usb_buffer_free(dev->udev,
|
||||
usb_free_coherent(dev->udev,
|
||||
urb->transfer_buffer_length,
|
||||
dev->isoc_ctl.transfer_buffer[i],
|
||||
urb->transfer_dma);
|
||||
@ -1045,7 +1045,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
|
||||
}
|
||||
dev->isoc_ctl.urb[i] = urb;
|
||||
|
||||
dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
|
||||
dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
|
||||
sb_size, GFP_KERNEL, &urb->transfer_dma);
|
||||
if (!dev->isoc_ctl.transfer_buffer[i]) {
|
||||
em28xx_err("unable to allocate %i bytes for transfer"
|
||||
|
@ -117,13 +117,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
gspca_dev->urb[n] = urb;
|
||||
urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
|
||||
urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
|
||||
SD_PKT_SZ * SD_NPKT,
|
||||
GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
|
||||
if (urb->transfer_buffer == NULL) {
|
||||
err("usb_buffer_alloc failed");
|
||||
err("usb_alloc_coherent failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
urb->dev = gspca_dev->dev;
|
||||
|
@ -213,7 +213,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
|
||||
goto error;
|
||||
}
|
||||
|
||||
buffer = usb_buffer_alloc(dev, buffer_len,
|
||||
buffer = usb_alloc_coherent(dev, buffer_len,
|
||||
GFP_KERNEL, &urb->transfer_dma);
|
||||
if (!buffer) {
|
||||
ret = -ENOMEM;
|
||||
@ -232,10 +232,10 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
|
||||
return ret;
|
||||
|
||||
error_submit:
|
||||
usb_buffer_free(dev,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
usb_free_coherent(dev,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
error_buffer:
|
||||
usb_free_urb(urb);
|
||||
error:
|
||||
@ -272,10 +272,10 @@ static void gspca_input_destroy_urb(struct gspca_dev *gspca_dev)
|
||||
if (urb) {
|
||||
gspca_dev->int_urb = NULL;
|
||||
usb_kill_urb(urb);
|
||||
usb_buffer_free(gspca_dev->dev,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
usb_free_coherent(gspca_dev->dev,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
}
|
||||
@ -605,10 +605,10 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
|
||||
gspca_dev->urb[i] = NULL;
|
||||
usb_kill_urb(urb);
|
||||
if (urb->transfer_buffer != NULL)
|
||||
usb_buffer_free(gspca_dev->dev,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
usb_free_coherent(gspca_dev->dev,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
}
|
||||
@ -760,13 +760,13 @@ static int create_urbs(struct gspca_dev *gspca_dev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
gspca_dev->urb[n] = urb;
|
||||
urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
|
||||
urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
|
||||
bsize,
|
||||
GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
|
||||
if (urb->transfer_buffer == NULL) {
|
||||
err("usb_buffer_alloc failed");
|
||||
err("usb_alloc_coherent failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
urb->dev = gspca_dev->dev;
|
||||
|
@ -92,8 +92,8 @@ static int hdpvr_free_queue(struct list_head *q)
|
||||
buf = list_entry(p, struct hdpvr_buffer, buff_list);
|
||||
|
||||
urb = buf->urb;
|
||||
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
tmp = p->next;
|
||||
list_del(p);
|
||||
@ -143,8 +143,8 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
|
||||
}
|
||||
buf->urb = urb;
|
||||
|
||||
mem = usb_buffer_alloc(dev->udev, dev->bulk_in_size, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
if (!mem) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"cannot allocate usb transfer buffer\n");
|
||||
|
@ -454,8 +454,8 @@ static int poseidon_probe(struct usb_interface *interface,
|
||||
|
||||
device_init_wakeup(&udev->dev, 1);
|
||||
#ifdef CONFIG_PM
|
||||
pd->udev->autosuspend_disabled = 0;
|
||||
pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
|
||||
usb_enable_autosuspend(pd->udev);
|
||||
|
||||
if (in_hibernation(pd)) {
|
||||
INIT_WORK(&pd->pm_work, hibernation_resume);
|
||||
|
@ -478,10 +478,10 @@ static int prepare_iso_urb(struct video_data *video)
|
||||
goto out;
|
||||
|
||||
video->urb_array[i] = urb;
|
||||
mem = usb_buffer_alloc(udev,
|
||||
ISO_PKT_SIZE * PK_PER_URB,
|
||||
GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
mem = usb_alloc_coherent(udev,
|
||||
ISO_PKT_SIZE * PK_PER_URB,
|
||||
GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
|
||||
urb->complete = urb_complete_iso; /* handler */
|
||||
urb->dev = udev;
|
||||
@ -521,8 +521,8 @@ int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
|
||||
if (urb == NULL)
|
||||
return i;
|
||||
|
||||
mem = usb_buffer_alloc(udev, buf_size, gfp_flags,
|
||||
&urb->transfer_dma);
|
||||
mem = usb_alloc_coherent(udev, buf_size, gfp_flags,
|
||||
&urb->transfer_dma);
|
||||
if (mem == NULL)
|
||||
return i;
|
||||
|
||||
@ -542,7 +542,7 @@ void free_all_urb_generic(struct urb **urb_array, int num)
|
||||
for (i = 0; i < num; i++) {
|
||||
urb = urb_array[i];
|
||||
if (urb) {
|
||||
usb_buffer_free(urb->dev,
|
||||
usb_free_coherent(urb->dev,
|
||||
urb->transfer_buffer_length,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
|
@ -2493,10 +2493,10 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
|
||||
}
|
||||
usbvision->sbuf[bufIdx].urb = urb;
|
||||
usbvision->sbuf[bufIdx].data =
|
||||
usb_buffer_alloc(usbvision->dev,
|
||||
sb_size,
|
||||
GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
usb_alloc_coherent(usbvision->dev,
|
||||
sb_size,
|
||||
GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
urb->dev = dev;
|
||||
urb->context = usbvision;
|
||||
urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
|
||||
@ -2552,10 +2552,10 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
|
||||
for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
|
||||
usb_kill_urb(usbvision->sbuf[bufIdx].urb);
|
||||
if (usbvision->sbuf[bufIdx].data){
|
||||
usb_buffer_free(usbvision->dev,
|
||||
sb_size,
|
||||
usbvision->sbuf[bufIdx].data,
|
||||
usbvision->sbuf[bufIdx].urb->transfer_dma);
|
||||
usb_free_coherent(usbvision->dev,
|
||||
sb_size,
|
||||
usbvision->sbuf[bufIdx].data,
|
||||
usbvision->sbuf[bufIdx].urb->transfer_dma);
|
||||
}
|
||||
usb_free_urb(usbvision->sbuf[bufIdx].urb);
|
||||
usbvision->sbuf[bufIdx].urb = NULL;
|
||||
|
@ -739,7 +739,7 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream)
|
||||
|
||||
for (i = 0; i < UVC_URBS; ++i) {
|
||||
if (stream->urb_buffer[i]) {
|
||||
usb_buffer_free(stream->dev->udev, stream->urb_size,
|
||||
usb_free_coherent(stream->dev->udev, stream->urb_size,
|
||||
stream->urb_buffer[i], stream->urb_dma[i]);
|
||||
stream->urb_buffer[i] = NULL;
|
||||
}
|
||||
@ -780,7 +780,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
|
||||
for (; npackets > 1; npackets /= 2) {
|
||||
for (i = 0; i < UVC_URBS; ++i) {
|
||||
stream->urb_size = psize * npackets;
|
||||
stream->urb_buffer[i] = usb_buffer_alloc(
|
||||
stream->urb_buffer[i] = usb_alloc_coherent(
|
||||
stream->dev->udev, stream->urb_size,
|
||||
gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
|
||||
if (!stream->urb_buffer[i]) {
|
||||
|
@ -512,8 +512,8 @@ static void ems_usb_write_bulk_callback(struct urb *urb)
|
||||
netdev = dev->netdev;
|
||||
|
||||
/* free up our allocated buffer */
|
||||
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
|
||||
atomic_dec(&dev->active_tx_urbs);
|
||||
|
||||
@ -610,8 +610,8 @@ static int ems_usb_start(struct ems_usb *dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
buf = usb_buffer_alloc(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
if (!buf) {
|
||||
dev_err(netdev->dev.parent,
|
||||
"No memory left for USB buffer\n");
|
||||
@ -631,8 +631,8 @@ static int ems_usb_start(struct ems_usb *dev)
|
||||
netif_device_detach(dev->netdev);
|
||||
|
||||
usb_unanchor_urb(urb);
|
||||
usb_buffer_free(dev->udev, RX_BUFFER_SIZE, buf,
|
||||
urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
|
||||
urb->transfer_dma);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -773,7 +773,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
buf = usb_buffer_alloc(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);
|
||||
buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);
|
||||
if (!buf) {
|
||||
dev_err(netdev->dev.parent, "No memory left for USB buffer\n");
|
||||
usb_free_urb(urb);
|
||||
@ -816,7 +816,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
|
||||
*/
|
||||
if (!context) {
|
||||
usb_unanchor_urb(urb);
|
||||
usb_buffer_free(dev->udev, size, buf, urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
|
||||
|
||||
dev_warn(netdev->dev.parent, "couldn't find free context\n");
|
||||
|
||||
@ -841,7 +841,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
|
||||
can_free_echo_skb(netdev, context->echo_index);
|
||||
|
||||
usb_unanchor_urb(urb);
|
||||
usb_buffer_free(dev->udev, size, buf, urb->transfer_dma);
|
||||
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
atomic_dec(&dev->active_tx_urbs);
|
||||
|
@ -128,17 +128,13 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
|
||||
if (rx_urb == NULL)
|
||||
goto free_tx_urb;
|
||||
|
||||
tx_buf = usb_buffer_alloc(iphone->udev,
|
||||
IPHETH_BUF_SIZE,
|
||||
GFP_KERNEL,
|
||||
&tx_urb->transfer_dma);
|
||||
tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
|
||||
GFP_KERNEL, &tx_urb->transfer_dma);
|
||||
if (tx_buf == NULL)
|
||||
goto free_rx_urb;
|
||||
|
||||
rx_buf = usb_buffer_alloc(iphone->udev,
|
||||
IPHETH_BUF_SIZE,
|
||||
GFP_KERNEL,
|
||||
&rx_urb->transfer_dma);
|
||||
rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
|
||||
GFP_KERNEL, &rx_urb->transfer_dma);
|
||||
if (rx_buf == NULL)
|
||||
goto free_tx_buf;
|
||||
|
||||
@ -150,8 +146,8 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
|
||||
return 0;
|
||||
|
||||
free_tx_buf:
|
||||
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
|
||||
tx_urb->transfer_dma);
|
||||
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
|
||||
tx_urb->transfer_dma);
|
||||
free_rx_urb:
|
||||
usb_free_urb(rx_urb);
|
||||
free_tx_urb:
|
||||
@ -162,10 +158,10 @@ error_nomem:
|
||||
|
||||
static void ipheth_free_urbs(struct ipheth_device *iphone)
|
||||
{
|
||||
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
|
||||
iphone->rx_urb->transfer_dma);
|
||||
usb_buffer_free(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
|
||||
iphone->tx_urb->transfer_dma);
|
||||
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
|
||||
iphone->rx_urb->transfer_dma);
|
||||
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
|
||||
iphone->tx_urb->transfer_dma);
|
||||
usb_free_urb(iphone->rx_urb);
|
||||
usb_free_urb(iphone->tx_urb);
|
||||
}
|
||||
|
@ -1155,13 +1155,13 @@ err_fw:
|
||||
if (!kaweth->irq_urb)
|
||||
goto err_tx_and_rx;
|
||||
|
||||
kaweth->intbuffer = usb_buffer_alloc( kaweth->dev,
|
||||
kaweth->intbuffer = usb_alloc_coherent( kaweth->dev,
|
||||
INTBUFFERSIZE,
|
||||
GFP_KERNEL,
|
||||
&kaweth->intbufferhandle);
|
||||
if (!kaweth->intbuffer)
|
||||
goto err_tx_and_rx_and_irq;
|
||||
kaweth->rx_buf = usb_buffer_alloc( kaweth->dev,
|
||||
kaweth->rx_buf = usb_alloc_coherent( kaweth->dev,
|
||||
KAWETH_BUF_SIZE,
|
||||
GFP_KERNEL,
|
||||
&kaweth->rxbufferhandle);
|
||||
@ -1202,9 +1202,9 @@ err_fw:
|
||||
|
||||
err_intfdata:
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
|
||||
usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
|
||||
err_all_but_rxbuf:
|
||||
usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
|
||||
usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
|
||||
err_tx_and_rx_and_irq:
|
||||
usb_free_urb(kaweth->irq_urb);
|
||||
err_tx_and_rx:
|
||||
@ -1241,8 +1241,8 @@ static void kaweth_disconnect(struct usb_interface *intf)
|
||||
usb_free_urb(kaweth->tx_urb);
|
||||
usb_free_urb(kaweth->irq_urb);
|
||||
|
||||
usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
|
||||
usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
|
||||
usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
|
||||
usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
|
||||
|
||||
free_netdev(netdev);
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ int i2400mu_probe(struct usb_interface *iface,
|
||||
iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */
|
||||
device_init_wakeup(dev, 1);
|
||||
usb_dev->autosuspend_delay = 15 * HZ;
|
||||
usb_dev->autosuspend_disabled = 0;
|
||||
usb_enable_autosuspend(usb_dev);
|
||||
#endif
|
||||
|
||||
result = i2400m_setup(i2400m, I2400M_BRI_MAC_REINIT);
|
||||
|
@ -215,7 +215,7 @@ resubmit:
|
||||
return;
|
||||
|
||||
free:
|
||||
usb_buffer_free(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma);
|
||||
}
|
||||
|
||||
static void ar9170_usb_rx_completed(struct urb *urb)
|
||||
@ -296,7 +296,7 @@ static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru)
|
||||
if (!urb)
|
||||
goto out;
|
||||
|
||||
ibuf = usb_buffer_alloc(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma);
|
||||
ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma);
|
||||
if (!ibuf)
|
||||
goto out;
|
||||
|
||||
@ -309,8 +309,8 @@ static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru)
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err) {
|
||||
usb_unanchor_urb(urb);
|
||||
usb_buffer_free(aru->udev, 64, urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
usb_free_coherent(aru->udev, 64, urb->transfer_buffer,
|
||||
urb->transfer_dma);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -664,15 +664,15 @@ static struct urb *alloc_rx_urb(struct zd_usb *usb)
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return NULL;
|
||||
buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
if (!buffer) {
|
||||
usb_free_urb(urb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
|
||||
buffer, USB_MAX_RX_SIZE,
|
||||
buffer, USB_MAX_RX_SIZE,
|
||||
rx_urb_complete, usb);
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
@ -683,8 +683,8 @@ static void free_rx_urb(struct urb *urb)
|
||||
{
|
||||
if (!urb)
|
||||
return;
|
||||
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
|
||||
|
@ -81,8 +81,8 @@ extern u8 EpToQueue[6];
|
||||
#define RT28XX_PUT_DEVICE usb_put_dev
|
||||
#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso, GFP_ATOMIC)
|
||||
#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb, GFP_ATOMIC)
|
||||
#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) usb_buffer_alloc(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr)
|
||||
#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) usb_buffer_free(pUsb_Dev, BufSize, pTransferBuf, Dma_addr)
|
||||
#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) usb_alloc_coherent(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr)
|
||||
#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) usb_free_coherent(pUsb_Dev, BufSize, pTransferBuf, Dma_addr)
|
||||
|
||||
#define RTUSB_FREE_URB(pUrb) usb_free_urb(pUrb)
|
||||
|
||||
|
@ -1508,8 +1508,8 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
|
||||
urb = unode->urb;
|
||||
|
||||
/* Free each separately allocated piece */
|
||||
usb_buffer_free(urb->dev, dev->urbs.size,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_coherent(urb->dev, dev->urbs.size,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
kfree(node);
|
||||
}
|
||||
@ -1543,8 +1543,8 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
|
||||
}
|
||||
unode->urb = urb;
|
||||
|
||||
buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
buf = usb_alloc_coherent(dev->udev, MAX_TRANSFER, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
if (!buf) {
|
||||
kfree(unode);
|
||||
usb_free_urb(urb);
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#include "usbip_common.h"
|
||||
#include "stub.h"
|
||||
#include "../../usb/core/hcd.h"
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
|
||||
static int is_clear_halt_cmd(struct urb *urb)
|
||||
|
@ -562,7 +562,7 @@ EXPORT_SYMBOL_GPL(sockfd_to_socket);
|
||||
/* there may be more cases to tweak the flags. */
|
||||
static unsigned int tweak_transfer_flags(unsigned int flags)
|
||||
{
|
||||
flags &= ~(URB_NO_TRANSFER_DMA_MAP|URB_NO_SETUP_DMA_MAP);
|
||||
flags &= ~URB_NO_TRANSFER_DMA_MAP;
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include "../../usb/core/hcd.h"
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
|
||||
struct vhci_device {
|
||||
|
@ -94,19 +94,19 @@
|
||||
} while (0)
|
||||
|
||||
#define uea_enters(usb_dev) \
|
||||
uea_vdbg(usb_dev, "entering %s\n", __func__)
|
||||
uea_vdbg(usb_dev, "entering %s\n" , __func__)
|
||||
|
||||
#define uea_leaves(usb_dev) \
|
||||
uea_vdbg(usb_dev, "leaving %s\n", __func__)
|
||||
uea_vdbg(usb_dev, "leaving %s\n" , __func__)
|
||||
|
||||
#define uea_err(usb_dev, format,args...) \
|
||||
dev_err(&(usb_dev)->dev ,"[UEAGLE-ATM] " format , ##args)
|
||||
#define uea_err(usb_dev, format, args...) \
|
||||
dev_err(&(usb_dev)->dev , "[UEAGLE-ATM] " format , ##args)
|
||||
|
||||
#define uea_warn(usb_dev, format,args...) \
|
||||
dev_warn(&(usb_dev)->dev ,"[Ueagle-atm] " format, ##args)
|
||||
#define uea_warn(usb_dev, format, args...) \
|
||||
dev_warn(&(usb_dev)->dev , "[Ueagle-atm] " format, ##args)
|
||||
|
||||
#define uea_info(usb_dev, format,args...) \
|
||||
dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
|
||||
#define uea_info(usb_dev, format, args...) \
|
||||
dev_info(&(usb_dev)->dev , "[ueagle-atm] " format, ##args)
|
||||
|
||||
struct intr_pkt;
|
||||
|
||||
@ -289,7 +289,7 @@ enum {
|
||||
#define IS_ISDN(x) \
|
||||
((x)->annex & ANNEXB)
|
||||
|
||||
#define INS_TO_USBDEV(ins) ins->usb_dev
|
||||
#define INS_TO_USBDEV(ins) (ins->usb_dev)
|
||||
|
||||
#define GET_STATUS(data) \
|
||||
((data >> 8) & 0xf)
|
||||
@ -304,7 +304,7 @@ enum {
|
||||
* The FW_GET_BYTE() macro is provided only for consistency.
|
||||
*/
|
||||
|
||||
#define FW_GET_BYTE(p) *((__u8 *) (p))
|
||||
#define FW_GET_BYTE(p) (*((__u8 *) (p)))
|
||||
|
||||
#define FW_DIR "ueagle-atm/"
|
||||
#define UEA_FW_NAME_MAX 30
|
||||
@ -315,7 +315,7 @@ enum {
|
||||
|
||||
#define ACK_TIMEOUT msecs_to_jiffies(3000)
|
||||
|
||||
#define UEA_INTR_IFACE_NO 0
|
||||
#define UEA_INTR_IFACE_NO 0
|
||||
#define UEA_US_IFACE_NO 1
|
||||
#define UEA_DS_IFACE_NO 2
|
||||
|
||||
@ -326,9 +326,9 @@ enum {
|
||||
#define UEA_INTR_PIPE 0x04
|
||||
#define UEA_ISO_DATA_PIPE 0x08
|
||||
|
||||
#define UEA_E1_SET_BLOCK 0x0001
|
||||
#define UEA_E1_SET_BLOCK 0x0001
|
||||
#define UEA_E4_SET_BLOCK 0x002c
|
||||
#define UEA_SET_MODE 0x0003
|
||||
#define UEA_SET_MODE 0x0003
|
||||
#define UEA_SET_2183_DATA 0x0004
|
||||
#define UEA_SET_TIMEOUT 0x0011
|
||||
|
||||
@ -366,7 +366,7 @@ struct l1_code {
|
||||
u8 string_header[E4_L1_STRING_HEADER];
|
||||
u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
|
||||
struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
|
||||
u8 code [0];
|
||||
u8 code[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* structures describing a block within a DSP page */
|
||||
@ -428,7 +428,8 @@ struct block_info_e4 {
|
||||
#define E4_MODEMREADY 0x1
|
||||
|
||||
#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
|
||||
#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
|
||||
#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | \
|
||||
((st) & 0xf) << 4 | ((s) & 0xf))
|
||||
|
||||
#define E1_MAKESA(a, b, c, d) \
|
||||
(((c) & 0xff) << 24 | \
|
||||
@ -473,7 +474,7 @@ struct cmv_e4 {
|
||||
__be16 wFunction;
|
||||
__be16 wOffset;
|
||||
__be16 wAddress;
|
||||
__be32 dwData [6];
|
||||
__be32 dwData[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* structures representing swap information */
|
||||
@ -534,11 +535,13 @@ struct intr_pkt {
|
||||
|
||||
static struct usb_driver uea_driver;
|
||||
static DEFINE_MUTEX(uea_mutex);
|
||||
static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
|
||||
static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III",
|
||||
"Eagle IV"};
|
||||
|
||||
static int modem_index;
|
||||
static unsigned int debug;
|
||||
static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
|
||||
static unsigned int altsetting[NB_MODEM] = {
|
||||
[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
|
||||
static int sync_wait[NB_MODEM];
|
||||
static char *cmv_file[NB_MODEM];
|
||||
static int annex[NB_MODEM];
|
||||
@ -555,7 +558,7 @@ MODULE_PARM_DESC(cmv_file,
|
||||
"file name with configuration and management variables");
|
||||
module_param_array(annex, uint, NULL, 0644);
|
||||
MODULE_PARM_DESC(annex,
|
||||
"manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
|
||||
"manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
|
||||
|
||||
#define uea_wait(sc, cond, timeo) \
|
||||
({ \
|
||||
@ -602,7 +605,8 @@ static int uea_send_modem_cmd(struct usb_device *usb,
|
||||
return (ret == size) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *context)
|
||||
static void uea_upload_pre_firmware(const struct firmware *fw_entry,
|
||||
void *context)
|
||||
{
|
||||
struct usb_device *usb = context;
|
||||
const u8 *pfw;
|
||||
@ -707,7 +711,8 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
|
||||
}
|
||||
|
||||
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev,
|
||||
GFP_KERNEL, usb, uea_upload_pre_firmware);
|
||||
GFP_KERNEL, usb,
|
||||
uea_upload_pre_firmware);
|
||||
if (ret)
|
||||
uea_err(usb, "firmware %s is not available\n", fw_name);
|
||||
else
|
||||
@ -876,7 +881,7 @@ static int request_dsp(struct uea_softc *sc)
|
||||
if (ret < 0) {
|
||||
uea_err(INS_TO_USBDEV(sc),
|
||||
"requesting firmware %s failed with error %d\n",
|
||||
dsp_name, ret);
|
||||
dsp_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -994,14 +999,17 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
|
||||
|
||||
blockidx = &p->page_header[blockno];
|
||||
blocksize = E4_PAGE_BYTES(blockidx->PageSize);
|
||||
blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
|
||||
blockoffset = sc->dsp_firm->data + le32_to_cpu(
|
||||
blockidx->PageOffset);
|
||||
|
||||
bi.dwSize = cpu_to_be32(blocksize);
|
||||
bi.dwAddress = cpu_to_be32(le32_to_cpu(blockidx->PageAddress));
|
||||
|
||||
uea_dbg(INS_TO_USBDEV(sc),
|
||||
"sending block %u for DSP page %u size %u address %x\n",
|
||||
blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
|
||||
"sending block %u for DSP page "
|
||||
"%u size %u address %x\n",
|
||||
blockno, pageno, blocksize,
|
||||
le32_to_cpu(blockidx->PageAddress));
|
||||
|
||||
/* send block info through the IDMA pipe */
|
||||
if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
|
||||
@ -1042,7 +1050,8 @@ static void uea_load_page_e4(struct work_struct *work)
|
||||
|
||||
p = (struct l1_code *) sc->dsp_firm->data;
|
||||
if (pageno >= le16_to_cpu(p->page_header[0].PageNumber)) {
|
||||
uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
|
||||
uea_err(INS_TO_USBDEV(sc), "invalid DSP "
|
||||
"page %u requested\n", pageno);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1059,7 +1068,7 @@ static void uea_load_page_e4(struct work_struct *work)
|
||||
__uea_load_page_e4(sc, i, 1);
|
||||
}
|
||||
|
||||
uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
|
||||
uea_dbg(INS_TO_USBDEV(sc) , "sending start bi\n");
|
||||
|
||||
bi.wHdr = cpu_to_be16(UEA_BIHDR);
|
||||
bi.bBootPage = 0;
|
||||
@ -1139,8 +1148,10 @@ static int uea_cmv_e1(struct uea_softc *sc,
|
||||
uea_enters(INS_TO_USBDEV(sc));
|
||||
uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
|
||||
"offset : 0x%04x, data : 0x%08x\n",
|
||||
E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
|
||||
E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
|
||||
E1_FUNCTION_TYPE(function),
|
||||
E1_FUNCTION_SUBTYPE(function),
|
||||
E1_GETSA1(address), E1_GETSA2(address),
|
||||
E1_GETSA3(address),
|
||||
E1_GETSA4(address), offset, data);
|
||||
|
||||
/* we send a request, but we expect a reply */
|
||||
@ -1157,7 +1168,8 @@ static int uea_cmv_e1(struct uea_softc *sc,
|
||||
cmv.wOffsetAddress = cpu_to_le16(offset);
|
||||
put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData);
|
||||
|
||||
ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
|
||||
ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START,
|
||||
sizeof(cmv), &cmv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = wait_cmv_ack(sc);
|
||||
@ -1191,7 +1203,8 @@ static int uea_cmv_e4(struct uea_softc *sc,
|
||||
cmv.wOffset = cpu_to_be16(offset);
|
||||
cmv.dwData[0] = cpu_to_be32(data);
|
||||
|
||||
ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
|
||||
ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START,
|
||||
sizeof(cmv), &cmv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = wait_cmv_ack(sc);
|
||||
@ -1208,7 +1221,7 @@ static inline int uea_read_cmv_e1(struct uea_softc *sc,
|
||||
uea_err(INS_TO_USBDEV(sc),
|
||||
"reading cmv failed with error %d\n", ret);
|
||||
else
|
||||
*data = sc->data;
|
||||
*data = sc->data;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1216,13 +1229,14 @@ static inline int uea_read_cmv_e1(struct uea_softc *sc,
|
||||
static inline int uea_read_cmv_e4(struct uea_softc *sc,
|
||||
u8 size, u16 group, u16 address, u16 offset, u32 *data)
|
||||
{
|
||||
int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
|
||||
int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS,
|
||||
E4_REQUESTREAD, size),
|
||||
group, address, offset, 0);
|
||||
if (ret < 0)
|
||||
uea_err(INS_TO_USBDEV(sc),
|
||||
"reading cmv failed with error %d\n", ret);
|
||||
else {
|
||||
*data = sc->data;
|
||||
*data = sc->data;
|
||||
/* size is in 16-bit word quantities */
|
||||
if (size > 2)
|
||||
*(data + 1) = sc->data1;
|
||||
@ -1245,7 +1259,8 @@ static inline int uea_write_cmv_e1(struct uea_softc *sc,
|
||||
static inline int uea_write_cmv_e4(struct uea_softc *sc,
|
||||
u8 size, u16 group, u16 address, u16 offset, u32 data)
|
||||
{
|
||||
int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
|
||||
int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS,
|
||||
E4_REQUESTWRITE, size),
|
||||
group, address, offset, data);
|
||||
if (ret < 0)
|
||||
uea_err(INS_TO_USBDEV(sc),
|
||||
@ -1442,27 +1457,29 @@ static int uea_stat_e4(struct uea_softc *sc)
|
||||
return ret;
|
||||
|
||||
switch (sc->stats.phy.state) {
|
||||
case 0x0: /* not yet synchronized */
|
||||
case 0x1:
|
||||
case 0x3:
|
||||
case 0x4:
|
||||
uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
|
||||
return 0;
|
||||
case 0x5: /* initialization */
|
||||
case 0x6:
|
||||
case 0x9:
|
||||
case 0xa:
|
||||
uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
|
||||
return 0;
|
||||
case 0x2: /* fail ... */
|
||||
uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
|
||||
" (may be try other cmv/dsp)\n");
|
||||
return -EAGAIN;
|
||||
case 0x7: /* operational */
|
||||
break;
|
||||
default:
|
||||
uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
|
||||
return 0;
|
||||
case 0x0: /* not yet synchronized */
|
||||
case 0x1:
|
||||
case 0x3:
|
||||
case 0x4:
|
||||
uea_dbg(INS_TO_USBDEV(sc), "modem not yet "
|
||||
"synchronized\n");
|
||||
return 0;
|
||||
case 0x5: /* initialization */
|
||||
case 0x6:
|
||||
case 0x9:
|
||||
case 0xa:
|
||||
uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
|
||||
return 0;
|
||||
case 0x2: /* fail ... */
|
||||
uea_info(INS_TO_USBDEV(sc), "modem synchronization "
|
||||
"failed (may be try other cmv/dsp)\n");
|
||||
return -EAGAIN;
|
||||
case 0x7: /* operational */
|
||||
break;
|
||||
default:
|
||||
uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n",
|
||||
sc->stats.phy.state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data != 7) {
|
||||
@ -1502,9 +1519,9 @@ static int uea_stat_e4(struct uea_softc *sc)
|
||||
if (sc->stats.phy.flags) {
|
||||
uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
|
||||
sc->stats.phy.flags);
|
||||
if (sc->stats.phy.flags & 1) //delineation LOSS
|
||||
if (sc->stats.phy.flags & 1) /* delineation LOSS */
|
||||
return -EAGAIN;
|
||||
if (sc->stats.phy.flags & 0x4000) //Reset Flag
|
||||
if (sc->stats.phy.flags & 0x4000) /* Reset Flag */
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
@ -1618,7 +1635,8 @@ static int request_cmvs(struct uea_softc *sc,
|
||||
if (ret < 0) {
|
||||
/* if caller can handle old version, try to provide it */
|
||||
if (*ver == 1) {
|
||||
uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
|
||||
uea_warn(INS_TO_USBDEV(sc), "requesting "
|
||||
"firmware %s failed, "
|
||||
"try to get older cmvs\n", cmv_name);
|
||||
return request_cmvs_old(sc, cmvs, fw);
|
||||
}
|
||||
@ -1632,8 +1650,8 @@ static int request_cmvs(struct uea_softc *sc,
|
||||
data = (u8 *) (*fw)->data;
|
||||
if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
|
||||
if (*ver == 1) {
|
||||
uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
|
||||
"try to get older cmvs\n", cmv_name);
|
||||
uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted,"
|
||||
" try to get older cmvs\n", cmv_name);
|
||||
release_firmware(*fw);
|
||||
return request_cmvs_old(sc, cmvs, fw);
|
||||
}
|
||||
@ -1670,7 +1688,7 @@ static int uea_send_cmvs_e1(struct uea_softc *sc)
|
||||
int i, ret, len;
|
||||
void *cmvs_ptr;
|
||||
const struct firmware *cmvs_fw;
|
||||
int ver = 1; // we can handle v1 cmv firmware version;
|
||||
int ver = 1; /* we can handle v1 cmv firmware version; */
|
||||
|
||||
/* Enter in R-IDLE (cmv) until instructed otherwise */
|
||||
ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
|
||||
@ -1685,7 +1703,7 @@ static int uea_send_cmvs_e1(struct uea_softc *sc)
|
||||
sc->stats.phy.firmid);
|
||||
|
||||
/* get options */
|
||||
ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
|
||||
ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -1697,9 +1715,10 @@ static int uea_send_cmvs_e1(struct uea_softc *sc)
|
||||
"please update your firmware\n");
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v1[i].address),
|
||||
get_unaligned_le16(&cmvs_v1[i].offset),
|
||||
get_unaligned_le32(&cmvs_v1[i].data));
|
||||
ret = uea_write_cmv_e1(sc,
|
||||
get_unaligned_le32(&cmvs_v1[i].address),
|
||||
get_unaligned_le16(&cmvs_v1[i].offset),
|
||||
get_unaligned_le32(&cmvs_v1[i].data));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
@ -1707,9 +1726,10 @@ static int uea_send_cmvs_e1(struct uea_softc *sc)
|
||||
struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v2[i].address),
|
||||
(u16) get_unaligned_le32(&cmvs_v2[i].offset),
|
||||
get_unaligned_le32(&cmvs_v2[i].data));
|
||||
ret = uea_write_cmv_e1(sc,
|
||||
get_unaligned_le32(&cmvs_v2[i].address),
|
||||
(u16) get_unaligned_le32(&cmvs_v2[i].offset),
|
||||
get_unaligned_le32(&cmvs_v2[i].data));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
@ -1722,7 +1742,8 @@ static int uea_send_cmvs_e1(struct uea_softc *sc)
|
||||
/* Enter in R-ACT-REQ */
|
||||
ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
|
||||
uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
|
||||
uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
|
||||
uea_info(INS_TO_USBDEV(sc), "modem started, waiting "
|
||||
"synchronization...\n");
|
||||
out:
|
||||
release_firmware(cmvs_fw);
|
||||
return ret;
|
||||
@ -1733,7 +1754,7 @@ static int uea_send_cmvs_e4(struct uea_softc *sc)
|
||||
int i, ret, len;
|
||||
void *cmvs_ptr;
|
||||
const struct firmware *cmvs_fw;
|
||||
int ver = 2; // we can only handle v2 cmv firmware version;
|
||||
int ver = 2; /* we can only handle v2 cmv firmware version; */
|
||||
|
||||
/* Enter in R-IDLE (cmv) until instructed otherwise */
|
||||
ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
|
||||
@ -1750,7 +1771,7 @@ static int uea_send_cmvs_e4(struct uea_softc *sc)
|
||||
|
||||
|
||||
/* get options */
|
||||
ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
|
||||
ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -1760,10 +1781,10 @@ static int uea_send_cmvs_e4(struct uea_softc *sc)
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
ret = uea_write_cmv_e4(sc, 1,
|
||||
get_unaligned_le32(&cmvs_v2[i].group),
|
||||
get_unaligned_le32(&cmvs_v2[i].address),
|
||||
get_unaligned_le32(&cmvs_v2[i].offset),
|
||||
get_unaligned_le32(&cmvs_v2[i].data));
|
||||
get_unaligned_le32(&cmvs_v2[i].group),
|
||||
get_unaligned_le32(&cmvs_v2[i].address),
|
||||
get_unaligned_le32(&cmvs_v2[i].offset),
|
||||
get_unaligned_le32(&cmvs_v2[i].data));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
@ -1776,7 +1797,8 @@ static int uea_send_cmvs_e4(struct uea_softc *sc)
|
||||
/* Enter in R-ACT-REQ */
|
||||
ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
|
||||
uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
|
||||
uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
|
||||
uea_info(INS_TO_USBDEV(sc), "modem started, waiting "
|
||||
"synchronization...\n");
|
||||
out:
|
||||
release_firmware(cmvs_fw);
|
||||
return ret;
|
||||
@ -1812,7 +1834,7 @@ static int uea_start_reset(struct uea_softc *sc)
|
||||
uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
|
||||
uea_request(sc, UEA_SET_MODE, UEA_BOOT_IDMA, 0, NULL);
|
||||
|
||||
/* enter reset mode */
|
||||
/* enter reset mode */
|
||||
uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
|
||||
|
||||
/* original driver use 200ms, but windows driver use 100ms */
|
||||
@ -1824,7 +1846,7 @@ static int uea_start_reset(struct uea_softc *sc)
|
||||
uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
|
||||
|
||||
if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
|
||||
/* clear tx and rx mailboxes */
|
||||
/* clear tx and rx mailboxes */
|
||||
uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
|
||||
uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
|
||||
uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
|
||||
@ -1835,9 +1857,11 @@ static int uea_start_reset(struct uea_softc *sc)
|
||||
return ret;
|
||||
|
||||
if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
|
||||
sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
|
||||
sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE,
|
||||
E4_MODEMREADY, 1);
|
||||
else
|
||||
sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
|
||||
sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE,
|
||||
E1_MODEMREADY);
|
||||
|
||||
/* demask interrupt */
|
||||
sc->booting = 0;
|
||||
@ -1937,7 +1961,8 @@ static int load_XILINX_firmware(struct uea_softc *sc)
|
||||
value = 0;
|
||||
ret = uea_send_modem_cmd(sc->usb_dev, 0xe, 1, &value);
|
||||
if (ret < 0)
|
||||
uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
|
||||
uea_err(sc->usb_dev, "elsa de-assert failed with error"
|
||||
" %d\n", ret);
|
||||
|
||||
err1:
|
||||
release_firmware(fw_entry);
|
||||
@ -1966,13 +1991,15 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
|
||||
if (UEA_CHIP_VERSION(sc) == ADI930
|
||||
&& cmv->bFunction == E1_MAKEFUNCTION(2, 2)) {
|
||||
cmv->wIndex = cpu_to_le16(dsc->idx);
|
||||
put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress);
|
||||
put_unaligned_le32(dsc->address,
|
||||
&cmv->dwSymbolicAddress);
|
||||
cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
|
||||
} else
|
||||
goto bad2;
|
||||
}
|
||||
|
||||
if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
|
||||
if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE,
|
||||
E1_MODEMREADY)) {
|
||||
wake_up_cmv_ack(sc);
|
||||
uea_leaves(INS_TO_USBDEV(sc));
|
||||
return;
|
||||
@ -2021,7 +2048,8 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
|
||||
if (be16_to_cpu(cmv->wFunction) != dsc->function)
|
||||
goto bad2;
|
||||
|
||||
if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
|
||||
if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE,
|
||||
E4_MODEMREADY, 1)) {
|
||||
wake_up_cmv_ack(sc);
|
||||
uea_leaves(INS_TO_USBDEV(sc));
|
||||
return;
|
||||
@ -2048,14 +2076,16 @@ bad2:
|
||||
return;
|
||||
}
|
||||
|
||||
static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
|
||||
static void uea_schedule_load_page_e1(struct uea_softc *sc,
|
||||
struct intr_pkt *intr)
|
||||
{
|
||||
sc->pageno = intr->e1_bSwapPageNo;
|
||||
sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
|
||||
queue_work(sc->work_q, &sc->task);
|
||||
}
|
||||
|
||||
static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
|
||||
static void uea_schedule_load_page_e4(struct uea_softc *sc,
|
||||
struct intr_pkt *intr)
|
||||
{
|
||||
sc->pageno = intr->e4_bSwapPageNo;
|
||||
queue_work(sc->work_q, &sc->task);
|
||||
@ -2263,8 +2293,8 @@ out:
|
||||
|
||||
static DEVICE_ATTR(stat_status, S_IWUGO | S_IRUGO, read_status, reboot);
|
||||
|
||||
static ssize_t read_human_status(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
static ssize_t read_human_status(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
int modem_state;
|
||||
@ -2289,7 +2319,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
|
||||
case 0xa:
|
||||
modem_state = 1;
|
||||
break;
|
||||
case 0x7: /* operational */
|
||||
case 0x7: /* operational */
|
||||
modem_state = 2;
|
||||
break;
|
||||
case 0x2: /* fail ... */
|
||||
@ -2324,7 +2354,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO, read_human_status, NULL);
|
||||
static DEVICE_ATTR(stat_human_status, S_IWUGO | S_IRUGO,
|
||||
read_human_status, NULL);
|
||||
|
||||
static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -2358,25 +2389,25 @@ out:
|
||||
|
||||
static DEVICE_ATTR(stat_delin, S_IWUGO | S_IRUGO, read_delin, NULL);
|
||||
|
||||
#define UEA_ATTR(name, reset) \
|
||||
#define UEA_ATTR(name, reset) \
|
||||
\
|
||||
static ssize_t read_##name(struct device *dev, \
|
||||
static ssize_t read_##name(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
int ret = -ENODEV; \
|
||||
struct uea_softc *sc; \
|
||||
\
|
||||
mutex_lock(&uea_mutex); \
|
||||
{ \
|
||||
int ret = -ENODEV; \
|
||||
struct uea_softc *sc; \
|
||||
\
|
||||
mutex_lock(&uea_mutex); \
|
||||
sc = dev_to_uea(dev); \
|
||||
if (!sc) \
|
||||
goto out; \
|
||||
if (!sc) \
|
||||
goto out; \
|
||||
ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.name); \
|
||||
if (reset) \
|
||||
sc->stats.phy.name = 0; \
|
||||
out: \
|
||||
mutex_unlock(&uea_mutex); \
|
||||
return ret; \
|
||||
} \
|
||||
out: \
|
||||
mutex_unlock(&uea_mutex); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
static DEVICE_ATTR(stat_##name, S_IRUGO, read_##name, NULL)
|
||||
|
||||
@ -2527,12 +2558,14 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
|
||||
else if (sc->driver_info & AUTO_ANNEX_B)
|
||||
sc->annex = ANNEXB;
|
||||
else
|
||||
sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
|
||||
sc->annex = (le16_to_cpu
|
||||
(sc->usb_dev->descriptor.bcdDevice) & 0x80) ? ANNEXB : ANNEXA;
|
||||
|
||||
alt = altsetting[sc->modem_index];
|
||||
/* ADI930 don't support iso */
|
||||
if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
|
||||
if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
|
||||
if (alt <= 8 &&
|
||||
usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
|
||||
uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
|
||||
uea_info(usb, "using iso mode\n");
|
||||
usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
|
||||
@ -2621,40 +2654,74 @@ static void uea_disconnect(struct usb_interface *intf)
|
||||
* List of supported VID/PID
|
||||
*/
|
||||
static const struct usb_device_id uea_ids[] = {
|
||||
{USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM),
|
||||
.driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM),
|
||||
.driver_info = ADI930 | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM),
|
||||
.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_I | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM),
|
||||
.driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_II | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM),
|
||||
.driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_II | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM),
|
||||
.driver_info = EAGLE_III | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_III | PSTFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM),
|
||||
.driver_info = EAGLE_IV | PREFIRM},
|
||||
{USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_IV | PSTFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM),
|
||||
.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM),
|
||||
.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM),
|
||||
.driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM),
|
||||
.driver_info = EAGLE_II | PREFIRM},
|
||||
{USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM),
|
||||
.driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM),
|
||||
.driver_info = ADI930 | PSTFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM),
|
||||
.driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM),
|
||||
.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM),
|
||||
.driver_info = ADI930 | PREFIRM},
|
||||
{USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM),
|
||||
.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM),
|
||||
.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM),
|
||||
.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),
|
||||
.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),
|
||||
.driver_info = EAGLE_I | PREFIRM},
|
||||
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),
|
||||
.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/usb.h>
|
||||
#include "../core/hcd.h"
|
||||
#include <linux/usb/hcd.h>
|
||||
#include "c67x00.h"
|
||||
|
||||
/*
|
||||
|
@ -892,7 +892,7 @@ static void acm_write_buffers_free(struct acm *acm)
|
||||
struct usb_device *usb_dev = interface_to_usbdev(acm->control);
|
||||
|
||||
for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
|
||||
usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
|
||||
usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah);
|
||||
}
|
||||
|
||||
static void acm_read_buffers_free(struct acm *acm)
|
||||
@ -901,8 +901,8 @@ static void acm_read_buffers_free(struct acm *acm)
|
||||
int i, n = acm->rx_buflimit;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
usb_buffer_free(usb_dev, acm->readsize,
|
||||
acm->rb[i].base, acm->rb[i].dma);
|
||||
usb_free_coherent(usb_dev, acm->readsize,
|
||||
acm->rb[i].base, acm->rb[i].dma);
|
||||
}
|
||||
|
||||
/* Little helper: write buffers allocate */
|
||||
@ -912,13 +912,13 @@ static int acm_write_buffers_alloc(struct acm *acm)
|
||||
struct acm_wb *wb;
|
||||
|
||||
for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
|
||||
wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
|
||||
wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL,
|
||||
&wb->dmah);
|
||||
if (!wb->buf) {
|
||||
while (i != 0) {
|
||||
--i;
|
||||
--wb;
|
||||
usb_buffer_free(acm->dev, acm->writesize,
|
||||
usb_free_coherent(acm->dev, acm->writesize,
|
||||
wb->buf, wb->dmah);
|
||||
}
|
||||
return -ENOMEM;
|
||||
@ -1177,7 +1177,7 @@ made_compressed_probe:
|
||||
tty_port_init(&acm->port);
|
||||
acm->port.ops = &acm_port_ops;
|
||||
|
||||
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||
if (!buf) {
|
||||
dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
|
||||
goto alloc_fail2;
|
||||
@ -1210,11 +1210,11 @@ made_compressed_probe:
|
||||
for (i = 0; i < num_rx_buf; i++) {
|
||||
struct acm_rb *rb = &(acm->rb[i]);
|
||||
|
||||
rb->base = usb_buffer_alloc(acm->dev, readsize,
|
||||
rb->base = usb_alloc_coherent(acm->dev, readsize,
|
||||
GFP_KERNEL, &rb->dma);
|
||||
if (!rb->base) {
|
||||
dev_dbg(&intf->dev,
|
||||
"out of memory (read bufs usb_buffer_alloc)\n");
|
||||
"out of memory (read bufs usb_alloc_coherent)\n");
|
||||
goto alloc_fail7;
|
||||
}
|
||||
}
|
||||
@ -1306,7 +1306,7 @@ alloc_fail7:
|
||||
alloc_fail5:
|
||||
acm_write_buffers_free(acm);
|
||||
alloc_fail4:
|
||||
usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
||||
usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
||||
alloc_fail2:
|
||||
kfree(acm);
|
||||
alloc_fail:
|
||||
@ -1356,8 +1356,8 @@ static void acm_disconnect(struct usb_interface *intf)
|
||||
stop_data_traffic(acm);
|
||||
|
||||
acm_write_buffers_free(acm);
|
||||
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
|
||||
acm->ctrl_dma);
|
||||
usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
|
||||
acm->ctrl_dma);
|
||||
acm_read_buffers_free(acm);
|
||||
|
||||
if (!acm->combined_interfaces)
|
||||
|
@ -124,8 +124,8 @@ struct acm {
|
||||
unsigned char clocal; /* termios CLOCAL */
|
||||
unsigned int ctrl_caps; /* control capabilities from the class specific header */
|
||||
unsigned int susp_count; /* number of suspended interfaces */
|
||||
int combined_interfaces:1; /* control and data collapsed */
|
||||
int is_int_ep:1; /* interrupt endpoints contrary to spec used */
|
||||
unsigned int combined_interfaces:1; /* control and data collapsed */
|
||||
unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */
|
||||
u8 bInterval;
|
||||
struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
|
||||
};
|
||||
|
@ -276,14 +276,14 @@ static void free_urbs(struct wdm_device *desc)
|
||||
|
||||
static void cleanup(struct wdm_device *desc)
|
||||
{
|
||||
usb_buffer_free(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxPacketSize,
|
||||
desc->sbuf,
|
||||
desc->validity->transfer_dma);
|
||||
usb_buffer_free(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxCommand,
|
||||
desc->inbuf,
|
||||
desc->response->transfer_dma);
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxPacketSize,
|
||||
desc->sbuf,
|
||||
desc->validity->transfer_dma);
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxCommand,
|
||||
desc->inbuf,
|
||||
desc->response->transfer_dma);
|
||||
kfree(desc->orq);
|
||||
kfree(desc->irq);
|
||||
kfree(desc->ubuf);
|
||||
@ -705,17 +705,17 @@ next_desc:
|
||||
if (!desc->ubuf)
|
||||
goto err;
|
||||
|
||||
desc->sbuf = usb_buffer_alloc(interface_to_usbdev(intf),
|
||||
desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
|
||||
desc->wMaxPacketSize,
|
||||
GFP_KERNEL,
|
||||
&desc->validity->transfer_dma);
|
||||
if (!desc->sbuf)
|
||||
goto err;
|
||||
|
||||
desc->inbuf = usb_buffer_alloc(interface_to_usbdev(intf),
|
||||
desc->bMaxPacketSize0,
|
||||
GFP_KERNEL,
|
||||
&desc->response->transfer_dma);
|
||||
desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
|
||||
desc->bMaxPacketSize0,
|
||||
GFP_KERNEL,
|
||||
&desc->response->transfer_dma);
|
||||
if (!desc->inbuf)
|
||||
goto err2;
|
||||
|
||||
@ -742,15 +742,15 @@ out:
|
||||
return rv;
|
||||
err3:
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_buffer_free(interface_to_usbdev(desc->intf),
|
||||
desc->bMaxPacketSize0,
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->bMaxPacketSize0,
|
||||
desc->inbuf,
|
||||
desc->response->transfer_dma);
|
||||
err2:
|
||||
usb_buffer_free(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxPacketSize,
|
||||
desc->sbuf,
|
||||
desc->validity->transfer_dma);
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxPacketSize,
|
||||
desc->sbuf,
|
||||
desc->validity->transfer_dma);
|
||||
err:
|
||||
free_urbs(desc);
|
||||
kfree(desc->ubuf);
|
||||
|
@ -27,7 +27,7 @@
|
||||
* v0.11 - add proto_bias option (Pete Zaitcev)
|
||||
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
|
||||
* v0.13 - alloc space for statusbuf (<status> not on stack);
|
||||
* use usb_buffer_alloc() for read buf & write buf;
|
||||
* use usb_alloc_coherent() for read buf & write buf;
|
||||
* none - Maintained in Linux kernel after v0.13
|
||||
*/
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/usb.h>
|
||||
#include "hcd.h"
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1,12 +1,14 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include "usb.h"
|
||||
#include "hcd.h"
|
||||
|
||||
|
||||
#define USB_MAXALTSETTING 128 /* Hard limit */
|
||||
#define USB_MAXENDPOINTS 30 /* Hard limit */
|
||||
@ -19,32 +21,6 @@ static inline const char *plural(int n)
|
||||
return (n == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
/* FIXME: this is a kludge */
|
||||
static int find_next_descriptor_more(unsigned char *buffer, int size,
|
||||
int dt1, int dt2, int dt3, int *num_skipped)
|
||||
{
|
||||
struct usb_descriptor_header *h;
|
||||
int n = 0;
|
||||
unsigned char *buffer0 = buffer;
|
||||
|
||||
/* Find the next descriptor of type dt1 or dt2 or dt3 */
|
||||
while (size > 0) {
|
||||
h = (struct usb_descriptor_header *) buffer;
|
||||
if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 ||
|
||||
h->bDescriptorType == dt3)
|
||||
break;
|
||||
buffer += h->bLength;
|
||||
size -= h->bLength;
|
||||
++n;
|
||||
}
|
||||
|
||||
/* Store the number of descriptors skipped and return the
|
||||
* number of bytes skipped */
|
||||
if (num_skipped)
|
||||
*num_skipped = n;
|
||||
return buffer - buffer0;
|
||||
}
|
||||
|
||||
static int find_next_descriptor(unsigned char *buffer, int size,
|
||||
int dt1, int dt2, int *num_skipped)
|
||||
{
|
||||
@ -69,47 +45,41 @@ static int find_next_descriptor(unsigned char *buffer, int size,
|
||||
return buffer - buffer0;
|
||||
}
|
||||
|
||||
static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
||||
static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
||||
int inum, int asnum, struct usb_host_endpoint *ep,
|
||||
int num_ep, unsigned char *buffer, int size)
|
||||
unsigned char *buffer, int size)
|
||||
{
|
||||
unsigned char *buffer_start = buffer;
|
||||
struct usb_ss_ep_comp_descriptor *desc;
|
||||
int retval;
|
||||
int num_skipped;
|
||||
struct usb_ss_ep_comp_descriptor *desc;
|
||||
int max_tx;
|
||||
int i;
|
||||
|
||||
/* The SuperSpeed endpoint companion descriptor is supposed to
|
||||
* be the first thing immediately following the endpoint descriptor.
|
||||
*/
|
||||
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
|
||||
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
|
||||
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
|
||||
size < USB_DT_SS_EP_COMP_SIZE) {
|
||||
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
|
||||
" interface %d altsetting %d ep %d: "
|
||||
"using minimum values\n",
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
/*
|
||||
* The next descriptor is for an Endpoint or Interface,
|
||||
* no extra descriptors to copy into the companion structure,
|
||||
* and we didn't eat up any of the buffer.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
|
||||
desc = &ep->ss_ep_comp->desc;
|
||||
buffer += desc->bLength;
|
||||
size -= desc->bLength;
|
||||
|
||||
/* Eat up the other descriptors we don't care about */
|
||||
ep->ss_ep_comp->extra = buffer;
|
||||
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
||||
USB_DT_INTERFACE, &num_skipped);
|
||||
ep->ss_ep_comp->extralen = i;
|
||||
buffer += i;
|
||||
size -= i;
|
||||
retval = buffer - buffer_start;
|
||||
if (num_skipped > 0)
|
||||
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
||||
num_skipped, plural(num_skipped),
|
||||
"SuperSpeed endpoint companion");
|
||||
/* Fill in some default values.
|
||||
* Leave bmAttributes as zero, which will mean no streams for
|
||||
* bulk, and isoc won't support multiple bursts of packets.
|
||||
* With bursts of only one packet, and a Mult of 1, the max
|
||||
* amount of data moved per endpoint service interval is one
|
||||
* packet.
|
||||
*/
|
||||
ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE;
|
||||
ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) ||
|
||||
usb_endpoint_xfer_int(&ep->desc))
|
||||
ep->ss_ep_comp.wBytesPerInterval =
|
||||
ep->desc.wMaxPacketSize;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE);
|
||||
|
||||
/* Check the various values */
|
||||
if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
|
||||
@ -117,47 +87,48 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to zero\n", desc->bMaxBurst,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bMaxBurst = 0;
|
||||
}
|
||||
if (desc->bMaxBurst > 15) {
|
||||
ep->ss_ep_comp.bMaxBurst = 0;
|
||||
} else if (desc->bMaxBurst > 15) {
|
||||
dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to 15\n", desc->bMaxBurst,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bMaxBurst = 15;
|
||||
ep->ss_ep_comp.bMaxBurst = 15;
|
||||
}
|
||||
if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
|
||||
&& desc->bmAttributes != 0) {
|
||||
|
||||
if ((usb_endpoint_xfer_control(&ep->desc) ||
|
||||
usb_endpoint_xfer_int(&ep->desc)) &&
|
||||
desc->bmAttributes != 0) {
|
||||
dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to zero\n",
|
||||
usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
|
||||
desc->bmAttributes,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bmAttributes = 0;
|
||||
}
|
||||
if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
|
||||
ep->ss_ep_comp.bmAttributes = 0;
|
||||
} else if (usb_endpoint_xfer_bulk(&ep->desc) &&
|
||||
desc->bmAttributes > 16) {
|
||||
dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to max\n",
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bmAttributes = 16;
|
||||
}
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
|
||||
ep->ss_ep_comp.bmAttributes = 16;
|
||||
} else if (usb_endpoint_xfer_isoc(&ep->desc) &&
|
||||
desc->bmAttributes > 2) {
|
||||
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
"setting to 3\n", desc->bmAttributes + 1,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress);
|
||||
desc->bmAttributes = 2;
|
||||
ep->ss_ep_comp.bmAttributes = 2;
|
||||
}
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc)) {
|
||||
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc))
|
||||
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
|
||||
(desc->bmAttributes + 1);
|
||||
} else if (usb_endpoint_xfer_int(&ep->desc)) {
|
||||
else if (usb_endpoint_xfer_int(&ep->desc))
|
||||
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
|
||||
} else {
|
||||
goto valid;
|
||||
}
|
||||
else
|
||||
max_tx = 999999;
|
||||
if (desc->wBytesPerInterval > max_tx) {
|
||||
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
|
||||
"config %d interface %d altsetting %d ep %d: "
|
||||
@ -166,10 +137,8 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
||||
desc->wBytesPerInterval,
|
||||
cfgno, inum, asnum, ep->desc.bEndpointAddress,
|
||||
max_tx);
|
||||
desc->wBytesPerInterval = max_tx;
|
||||
ep->ss_ep_comp.wBytesPerInterval = max_tx;
|
||||
}
|
||||
valid:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||||
@ -291,61 +260,19 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||||
cfgno, inum, asnum, d->bEndpointAddress,
|
||||
maxp);
|
||||
}
|
||||
/* Allocate room for and parse any SS endpoint companion descriptors */
|
||||
if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
|
||||
endpoint->extra = buffer;
|
||||
i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
|
||||
USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
|
||||
endpoint->extralen = i;
|
||||
buffer += i;
|
||||
size -= i;
|
||||
|
||||
/* Allocate space for the SS endpoint companion descriptor */
|
||||
endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
|
||||
GFP_KERNEL);
|
||||
if (!endpoint->ss_ep_comp)
|
||||
return -ENOMEM;
|
||||
/* Parse a possible SuperSpeed endpoint companion descriptor */
|
||||
if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
|
||||
usb_parse_ss_endpoint_companion(ddev, cfgno,
|
||||
inum, asnum, endpoint, buffer, size);
|
||||
|
||||
/* Fill in some default values (may be overwritten later) */
|
||||
endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
|
||||
endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
|
||||
endpoint->ss_ep_comp->desc.bMaxBurst = 0;
|
||||
/*
|
||||
* Leave bmAttributes as zero, which will mean no streams for
|
||||
* bulk, and isoc won't support multiple bursts of packets.
|
||||
* With bursts of only one packet, and a Mult of 1, the max
|
||||
* amount of data moved per endpoint service interval is one
|
||||
* packet.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(&endpoint->desc) ||
|
||||
usb_endpoint_xfer_int(&endpoint->desc))
|
||||
endpoint->ss_ep_comp->desc.wBytesPerInterval =
|
||||
endpoint->desc.wMaxPacketSize;
|
||||
|
||||
if (size > 0) {
|
||||
retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
|
||||
inum, asnum, endpoint, num_ep, buffer,
|
||||
size);
|
||||
if (retval >= 0) {
|
||||
buffer += retval;
|
||||
retval = buffer - buffer0;
|
||||
}
|
||||
} else {
|
||||
dev_warn(ddev, "config %d interface %d altsetting %d "
|
||||
"endpoint 0x%X has no "
|
||||
"SuperSpeed companion descriptor\n",
|
||||
cfgno, inum, asnum, d->bEndpointAddress);
|
||||
retval = buffer - buffer0;
|
||||
}
|
||||
} else {
|
||||
/* Skip over any Class Specific or Vendor Specific descriptors;
|
||||
* find the next endpoint or interface descriptor */
|
||||
endpoint->extra = buffer;
|
||||
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
||||
USB_DT_INTERFACE, &n);
|
||||
endpoint->extralen = i;
|
||||
retval = buffer - buffer0 + i;
|
||||
}
|
||||
/* Skip over any Class Specific or Vendor Specific descriptors;
|
||||
* find the next endpoint or interface descriptor */
|
||||
endpoint->extra = buffer;
|
||||
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
|
||||
USB_DT_INTERFACE, &n);
|
||||
endpoint->extralen = i;
|
||||
retval = buffer - buffer0 + i;
|
||||
if (n > 0)
|
||||
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
||||
n, plural(n), "endpoint");
|
||||
@ -478,9 +405,10 @@ skip_to_next_interface_descriptor:
|
||||
return buffer - buffer0 + i;
|
||||
}
|
||||
|
||||
static int usb_parse_configuration(struct device *ddev, int cfgidx,
|
||||
static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
|
||||
struct usb_host_config *config, unsigned char *buffer, int size)
|
||||
{
|
||||
struct device *ddev = &dev->dev;
|
||||
unsigned char *buffer0 = buffer;
|
||||
int cfgno;
|
||||
int nintf, nintf_orig;
|
||||
@ -549,6 +477,16 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
|
||||
}
|
||||
|
||||
inum = d->bInterfaceNumber;
|
||||
|
||||
if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
|
||||
n >= nintf_orig) {
|
||||
dev_warn(ddev, "config %d has more interface "
|
||||
"descriptors, than it declares in "
|
||||
"bNumInterfaces, ignoring interface "
|
||||
"number: %d\n", cfgno, inum);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inum >= nintf_orig)
|
||||
dev_warn(ddev, "config %d has an invalid "
|
||||
"interface number: %d but max is %d\n",
|
||||
@ -722,7 +660,6 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
int ncfg = dev->descriptor.bNumConfigurations;
|
||||
int result = 0;
|
||||
unsigned int cfgno, length;
|
||||
unsigned char *buffer;
|
||||
unsigned char *bigbuffer;
|
||||
struct usb_config_descriptor *desc;
|
||||
|
||||
@ -751,17 +688,16 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
if (!dev->rawdescriptors)
|
||||
goto err2;
|
||||
|
||||
buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
|
||||
if (!desc)
|
||||
goto err2;
|
||||
desc = (struct usb_config_descriptor *)buffer;
|
||||
|
||||
result = 0;
|
||||
for (; cfgno < ncfg; cfgno++) {
|
||||
/* We grab just the first descriptor so we know how long
|
||||
* the whole configuration is */
|
||||
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
|
||||
buffer, USB_DT_CONFIG_SIZE);
|
||||
desc, USB_DT_CONFIG_SIZE);
|
||||
if (result < 0) {
|
||||
dev_err(ddev, "unable to read config index %d "
|
||||
"descriptor/%s: %d\n", cfgno, "start", result);
|
||||
@ -800,7 +736,7 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
|
||||
dev->rawdescriptors[cfgno] = bigbuffer;
|
||||
|
||||
result = usb_parse_configuration(&dev->dev, cfgno,
|
||||
result = usb_parse_configuration(dev, cfgno,
|
||||
&dev->config[cfgno], bigbuffer, length);
|
||||
if (result < 0) {
|
||||
++cfgno;
|
||||
@ -810,7 +746,7 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
result = 0;
|
||||
|
||||
err:
|
||||
kfree(buffer);
|
||||
kfree(desc);
|
||||
out_not_authorized:
|
||||
dev->descriptor.bNumConfigurations = cfgno;
|
||||
err2:
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
* devices.c
|
||||
* (C) Copyright 1999 Randy Dunlap.
|
||||
* (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
|
||||
* (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>.
|
||||
* (proc file per device)
|
||||
* (C) Copyright 1999 Deti Fliegl (new USB architecture)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -55,11 +56,11 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "hcd.h"
|
||||
|
||||
/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
|
||||
#define ALLOW_SERIAL_NUMBER
|
||||
@ -138,8 +139,8 @@ struct class_info {
|
||||
char *class_name;
|
||||
};
|
||||
|
||||
static const struct class_info clas_info[] =
|
||||
{ /* max. 5 chars. per name string */
|
||||
static const struct class_info clas_info[] = {
|
||||
/* max. 5 chars. per name string */
|
||||
{USB_CLASS_PER_INTERFACE, ">ifc"},
|
||||
{USB_CLASS_AUDIO, "audio"},
|
||||
{USB_CLASS_COMM, "comm."},
|
||||
@ -191,8 +192,10 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
|
||||
|
||||
if (speed == USB_SPEED_HIGH) {
|
||||
switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) {
|
||||
case 1 << 11: bandwidth = 2; break;
|
||||
case 2 << 11: bandwidth = 3; break;
|
||||
case 1 << 11:
|
||||
bandwidth = 2; break;
|
||||
case 2 << 11:
|
||||
bandwidth = 3; break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,7 +203,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
|
||||
switch (usb_endpoint_type(desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
type = "Ctrl";
|
||||
if (speed == USB_SPEED_HIGH) /* uframes per NAK */
|
||||
if (speed == USB_SPEED_HIGH) /* uframes per NAK */
|
||||
interval = desc->bInterval;
|
||||
else
|
||||
interval = 0;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <linux/usb/hcd.h> /* for usbcore internals */
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/security.h>
|
||||
@ -50,9 +51,7 @@
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#include "hcd.h" /* for usbcore internals */
|
||||
#include "usb.h"
|
||||
#include "hub.h"
|
||||
|
||||
#define USB_MAXBUS 64
|
||||
#define USB_DEVICE_MAX USB_MAXBUS * 128
|
||||
|
@ -26,8 +26,9 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include "hcd.h"
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
|
||||
@ -333,7 +334,8 @@ static int usb_probe_interface(struct device *dev)
|
||||
usb_cancel_queued_reset(intf);
|
||||
|
||||
/* Unbound interfaces are always runtime-PM-disabled and -suspended */
|
||||
pm_runtime_disable(dev);
|
||||
if (driver->supports_autosuspend)
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
|
||||
usb_autosuspend_device(udev);
|
||||
@ -388,7 +390,8 @@ static int usb_unbind_interface(struct device *dev)
|
||||
intf->needs_remote_wakeup = 0;
|
||||
|
||||
/* Unbound interfaces are always runtime-PM-disabled and -suspended */
|
||||
pm_runtime_disable(dev);
|
||||
if (driver->supports_autosuspend)
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
|
||||
/* Undo any residual pm_autopm_get_interface_* calls */
|
||||
@ -437,14 +440,17 @@ int usb_driver_claim_interface(struct usb_driver *driver,
|
||||
|
||||
iface->condition = USB_INTERFACE_BOUND;
|
||||
|
||||
/* Claimed interfaces are initially inactive (suspended). They are
|
||||
* runtime-PM-enabled only if the driver has autosuspend support.
|
||||
* They are sensitive to their children's power states.
|
||||
/* Claimed interfaces are initially inactive (suspended) and
|
||||
* runtime-PM-enabled, but only if the driver has autosuspend
|
||||
* support. Otherwise they are marked active, to prevent the
|
||||
* device from being autosuspended, but left disabled. In either
|
||||
* case they are sensitive to their children's power states.
|
||||
*/
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_suspend_ignore_children(dev, false);
|
||||
if (driver->supports_autosuspend)
|
||||
pm_runtime_enable(dev);
|
||||
else
|
||||
pm_runtime_set_active(dev);
|
||||
|
||||
/* if interface was already added, bind now; else let
|
||||
* the future device_add() bind it, bypassing probe()
|
||||
@ -1355,13 +1361,9 @@ int usb_resume(struct device *dev, pm_message_t msg)
|
||||
*
|
||||
* The caller must hold @udev's device lock.
|
||||
*/
|
||||
int usb_enable_autosuspend(struct usb_device *udev)
|
||||
void usb_enable_autosuspend(struct usb_device *udev)
|
||||
{
|
||||
if (udev->autosuspend_disabled) {
|
||||
udev->autosuspend_disabled = 0;
|
||||
usb_autosuspend_device(udev);
|
||||
}
|
||||
return 0;
|
||||
pm_runtime_allow(&udev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_enable_autosuspend);
|
||||
|
||||
@ -1374,16 +1376,9 @@ EXPORT_SYMBOL_GPL(usb_enable_autosuspend);
|
||||
*
|
||||
* The caller must hold @udev's device lock.
|
||||
*/
|
||||
int usb_disable_autosuspend(struct usb_device *udev)
|
||||
void usb_disable_autosuspend(struct usb_device *udev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!udev->autosuspend_disabled) {
|
||||
rc = usb_autoresume_device(udev);
|
||||
if (rc == 0)
|
||||
udev->autosuspend_disabled = 1;
|
||||
}
|
||||
return rc;
|
||||
pm_runtime_forbid(&udev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_disable_autosuspend);
|
||||
|
||||
@ -1485,9 +1480,6 @@ int usb_autoresume_device(struct usb_device *udev)
|
||||
* 0, a delayed autosuspend request for @intf's device is attempted. The
|
||||
* attempt may fail (see autosuspend_check()).
|
||||
*
|
||||
* If the driver has set @intf->needs_remote_wakeup then autosuspend will
|
||||
* take place only if the device's remote-wakeup facility is enabled.
|
||||
*
|
||||
* This routine can run only in process context.
|
||||
*/
|
||||
void usb_autopm_put_interface(struct usb_interface *intf)
|
||||
@ -1530,7 +1522,7 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
|
||||
atomic_dec(&intf->pm_usage_cnt);
|
||||
pm_runtime_put_noidle(&intf->dev);
|
||||
|
||||
if (!udev->autosuspend_disabled) {
|
||||
if (udev->dev.power.runtime_auto) {
|
||||
/* Optimization: Don't schedule a delayed autosuspend if
|
||||
* the timer is already running and the expiration time
|
||||
* wouldn't change.
|
||||
@ -1672,14 +1664,14 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
|
||||
/* Internal routine to check whether we may autosuspend a device. */
|
||||
static int autosuspend_check(struct usb_device *udev)
|
||||
{
|
||||
int i;
|
||||
int w, i;
|
||||
struct usb_interface *intf;
|
||||
unsigned long suspend_time, j;
|
||||
|
||||
/* Fail if autosuspend is disabled, or any interfaces are in use, or
|
||||
* any interface drivers require remote wakeup but it isn't available.
|
||||
*/
|
||||
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
|
||||
w = 0;
|
||||
if (udev->actconfig) {
|
||||
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
|
||||
intf = udev->actconfig->interface[i];
|
||||
@ -1693,12 +1685,7 @@ static int autosuspend_check(struct usb_device *udev)
|
||||
continue;
|
||||
if (atomic_read(&intf->dev.power.usage_count) > 0)
|
||||
return -EBUSY;
|
||||
if (intf->needs_remote_wakeup &&
|
||||
!udev->do_remote_wakeup) {
|
||||
dev_dbg(&udev->dev, "remote wakeup needed "
|
||||
"for autosuspend\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
w |= intf->needs_remote_wakeup;
|
||||
|
||||
/* Don't allow autosuspend if the device will need
|
||||
* a reset-resume and any of its interface drivers
|
||||
@ -1714,6 +1701,11 @@ static int autosuspend_check(struct usb_device *udev)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (w && !device_can_wakeup(&udev->dev)) {
|
||||
dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
udev->do_remote_wakeup = w;
|
||||
|
||||
/* If everything is okay but the device hasn't been idle for long
|
||||
* enough, queue a delayed autosuspend request.
|
||||
|
@ -18,8 +18,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include "usb.h"
|
||||
#include "hcd.h"
|
||||
|
||||
static inline const char *plural(int n)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
@ -33,7 +34,6 @@
|
||||
#endif
|
||||
|
||||
#include "usb.h"
|
||||
#include "hcd.h"
|
||||
|
||||
|
||||
/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
|
||||
|
@ -38,14 +38,12 @@
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "hcd.h"
|
||||
#include "hub.h"
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -1261,6 +1259,51 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
|
||||
*dma_handle = 0;
|
||||
}
|
||||
|
||||
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
||||
{
|
||||
enum dma_data_direction dir;
|
||||
|
||||
if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
|
||||
dma_unmap_single(hcd->self.controller,
|
||||
urb->setup_dma,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL)
|
||||
hcd_free_coherent(urb->dev->bus,
|
||||
&urb->setup_dma,
|
||||
(void **) &urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
if (urb->transfer_flags & URB_DMA_MAP_SG)
|
||||
dma_unmap_sg(hcd->self.controller,
|
||||
urb->sg,
|
||||
urb->num_sgs,
|
||||
dir);
|
||||
else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
|
||||
dma_unmap_page(hcd->self.controller,
|
||||
urb->transfer_dma,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
|
||||
dma_unmap_single(hcd->self.controller,
|
||||
urb->transfer_dma,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
else if (urb->transfer_flags & URB_MAP_LOCAL)
|
||||
hcd_free_coherent(urb->dev->bus,
|
||||
&urb->transfer_dma,
|
||||
&urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
|
||||
/* Make it safe to call this routine more than once */
|
||||
urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
|
||||
URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
|
||||
URB_DMA_MAP_SINGLE | URB_MAP_LOCAL);
|
||||
}
|
||||
|
||||
static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
@ -1272,11 +1315,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
* unless it uses pio or talks to another transport,
|
||||
* or uses the provided scatter gather list for bulk.
|
||||
*/
|
||||
if (is_root_hub(urb->dev))
|
||||
return 0;
|
||||
|
||||
if (usb_endpoint_xfer_control(&urb->ep->desc)
|
||||
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
|
||||
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
|
||||
if (hcd->self.uses_dma) {
|
||||
urb->setup_dma = dma_map_single(
|
||||
hcd->self.controller,
|
||||
@ -1286,27 +1326,64 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
if (dma_mapping_error(hcd->self.controller,
|
||||
urb->setup_dma))
|
||||
return -EAGAIN;
|
||||
} else if (hcd->driver->flags & HCD_LOCAL_MEM)
|
||||
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
|
||||
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
&urb->setup_dma,
|
||||
(void **)&urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
return ret;
|
||||
urb->transfer_flags |= URB_SETUP_MAP_LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
if (ret == 0 && urb->transfer_buffer_length != 0
|
||||
if (urb->transfer_buffer_length != 0
|
||||
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
|
||||
if (hcd->self.uses_dma) {
|
||||
urb->transfer_dma = dma_map_single (
|
||||
hcd->self.controller,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
if (dma_mapping_error(hcd->self.controller,
|
||||
if (urb->num_sgs) {
|
||||
int n = dma_map_sg(
|
||||
hcd->self.controller,
|
||||
urb->sg,
|
||||
urb->num_sgs,
|
||||
dir);
|
||||
if (n <= 0)
|
||||
ret = -EAGAIN;
|
||||
else
|
||||
urb->transfer_flags |= URB_DMA_MAP_SG;
|
||||
if (n != urb->num_sgs) {
|
||||
urb->num_sgs = n;
|
||||
urb->transfer_flags |=
|
||||
URB_DMA_SG_COMBINED;
|
||||
}
|
||||
} else if (urb->sg) {
|
||||
struct scatterlist *sg = urb->sg;
|
||||
urb->transfer_dma = dma_map_page(
|
||||
hcd->self.controller,
|
||||
sg_page(sg),
|
||||
sg->offset,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
if (dma_mapping_error(hcd->self.controller,
|
||||
urb->transfer_dma))
|
||||
return -EAGAIN;
|
||||
ret = -EAGAIN;
|
||||
else
|
||||
urb->transfer_flags |= URB_DMA_MAP_PAGE;
|
||||
} else {
|
||||
urb->transfer_dma = dma_map_single(
|
||||
hcd->self.controller,
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
if (dma_mapping_error(hcd->self.controller,
|
||||
urb->transfer_dma))
|
||||
ret = -EAGAIN;
|
||||
else
|
||||
urb->transfer_flags |= URB_DMA_MAP_SINGLE;
|
||||
}
|
||||
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
|
||||
ret = hcd_alloc_coherent(
|
||||
urb->dev->bus, mem_flags,
|
||||
@ -1314,55 +1391,16 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
&urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
|
||||
if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
|
||||
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
|
||||
hcd_free_coherent(urb->dev->bus,
|
||||
&urb->setup_dma,
|
||||
(void **)&urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
if (ret == 0)
|
||||
urb->transfer_flags |= URB_MAP_LOCAL;
|
||||
}
|
||||
if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE |
|
||||
URB_SETUP_MAP_LOCAL)))
|
||||
unmap_urb_for_dma(hcd, urb);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
||||
{
|
||||
enum dma_data_direction dir;
|
||||
|
||||
if (is_root_hub(urb->dev))
|
||||
return;
|
||||
|
||||
if (usb_endpoint_xfer_control(&urb->ep->desc)
|
||||
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
|
||||
if (hcd->self.uses_dma)
|
||||
dma_unmap_single(hcd->self.controller, urb->setup_dma,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
else if (hcd->driver->flags & HCD_LOCAL_MEM)
|
||||
hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
|
||||
(void **)&urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
if (urb->transfer_buffer_length != 0
|
||||
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
|
||||
if (hcd->self.uses_dma)
|
||||
dma_unmap_single(hcd->self.controller,
|
||||
urb->transfer_dma,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
else if (hcd->driver->flags & HCD_LOCAL_MEM)
|
||||
hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
|
||||
&urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
dir);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* may be called in any context with a valid urb->dev usecount
|
||||
@ -1391,21 +1429,20 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
|
||||
* URBs must be submitted in process context with interrupts
|
||||
* enabled.
|
||||
*/
|
||||
status = map_urb_for_dma(hcd, urb, mem_flags);
|
||||
if (unlikely(status)) {
|
||||
usbmon_urb_submit_error(&hcd->self, urb, status);
|
||||
goto error;
|
||||
|
||||
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 (is_root_hub(urb->dev))
|
||||
status = rh_urb_enqueue(hcd, urb);
|
||||
else
|
||||
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
|
||||
|
||||
if (unlikely(status)) {
|
||||
usbmon_urb_submit_error(&hcd->self, urb, status);
|
||||
unmap_urb_for_dma(hcd, urb);
|
||||
error:
|
||||
urb->hcpriv = NULL;
|
||||
INIT_LIST_HEAD(&urb->urb_list);
|
||||
atomic_dec(&urb->use_count);
|
||||
@ -1775,6 +1812,75 @@ void usb_hcd_reset_endpoint(struct usb_device *udev,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_alloc_streams - allocate bulk endpoint stream IDs.
|
||||
* @interface: alternate setting that includes all endpoints.
|
||||
* @eps: array of endpoints that need streams.
|
||||
* @num_eps: number of endpoints in the array.
|
||||
* @num_streams: number of streams to allocate.
|
||||
* @mem_flags: flags hcd should use to allocate memory.
|
||||
*
|
||||
* Sets up a group of bulk endpoints to have num_streams stream IDs available.
|
||||
* Drivers may queue multiple transfers to different stream IDs, which may
|
||||
* complete in a different order than they were queued.
|
||||
*/
|
||||
int usb_alloc_streams(struct usb_interface *interface,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
unsigned int num_streams, gfp_t mem_flags)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct usb_device *dev;
|
||||
int i;
|
||||
|
||||
dev = interface_to_usbdev(interface);
|
||||
hcd = bus_to_hcd(dev->bus);
|
||||
if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
|
||||
return -EINVAL;
|
||||
if (dev->speed != USB_SPEED_SUPER)
|
||||
return -EINVAL;
|
||||
|
||||
/* Streams only apply to bulk endpoints. */
|
||||
for (i = 0; i < num_eps; i++)
|
||||
if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
|
||||
return -EINVAL;
|
||||
|
||||
return hcd->driver->alloc_streams(hcd, dev, eps, num_eps,
|
||||
num_streams, mem_flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_alloc_streams);
|
||||
|
||||
/**
|
||||
* usb_free_streams - free bulk endpoint stream IDs.
|
||||
* @interface: alternate setting that includes all endpoints.
|
||||
* @eps: array of endpoints to remove streams from.
|
||||
* @num_eps: number of endpoints in the array.
|
||||
* @mem_flags: flags hcd should use to allocate memory.
|
||||
*
|
||||
* Reverts a group of bulk endpoints back to not using stream IDs.
|
||||
* Can fail if we are given bad arguments, or HCD is broken.
|
||||
*/
|
||||
void usb_free_streams(struct usb_interface *interface,
|
||||
struct usb_host_endpoint **eps, unsigned int num_eps,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct usb_device *dev;
|
||||
int i;
|
||||
|
||||
dev = interface_to_usbdev(interface);
|
||||
hcd = bus_to_hcd(dev->bus);
|
||||
if (dev->speed != USB_SPEED_SUPER)
|
||||
return;
|
||||
|
||||
/* Streams only apply to bulk endpoints. */
|
||||
for (i = 0; i < num_eps; i++)
|
||||
if (!usb_endpoint_xfer_bulk(&eps[i]->desc))
|
||||
return;
|
||||
|
||||
hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_free_streams);
|
||||
|
||||
/* Protect against drivers that try to unlink URBs after the device
|
||||
* is gone, by waiting until all unlinks for @udev are finished.
|
||||
* Since we don't currently track URBs by device, simply wait until
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/freezer.h>
|
||||
@ -28,8 +29,6 @@
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "hcd.h"
|
||||
#include "hub.h"
|
||||
|
||||
/* if we are in debug mode, always announce new devices */
|
||||
#ifdef DEBUG
|
||||
@ -154,11 +153,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev);
|
||||
|
||||
static inline char *portspeed(int portstatus)
|
||||
{
|
||||
if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
|
||||
if (portstatus & USB_PORT_STAT_HIGH_SPEED)
|
||||
return "480 Mb/s";
|
||||
else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
|
||||
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
|
||||
return "1.5 Mb/s";
|
||||
else if (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED))
|
||||
else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
|
||||
return "5.0 Gb/s";
|
||||
else
|
||||
return "12 Mb/s";
|
||||
@ -745,8 +744,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
||||
!(portstatus & USB_PORT_STAT_CONNECTION) ||
|
||||
!udev ||
|
||||
udev->state == USB_STATE_NOTATTACHED)) {
|
||||
clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
|
||||
portstatus &= ~USB_PORT_STAT_ENABLE;
|
||||
/*
|
||||
* USB3 protocol ports will automatically transition
|
||||
* to Enabled state when detect an USB3.0 device attach.
|
||||
* Do not disable USB3 protocol ports.
|
||||
* FIXME: USB3 root hub and external hubs are treated
|
||||
* differently here.
|
||||
*/
|
||||
if (hdev->descriptor.bDeviceProtocol != 3 ||
|
||||
(!hdev->parent &&
|
||||
!(portstatus & USB_PORT_STAT_SUPER_SPEED))) {
|
||||
clear_port_feature(hdev, port1,
|
||||
USB_PORT_FEAT_ENABLE);
|
||||
portstatus &= ~USB_PORT_STAT_ENABLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear status-change flags; we'll debounce later */
|
||||
@ -1784,7 +1795,6 @@ int usb_new_device(struct usb_device *udev)
|
||||
* sysfs power/wakeup controls wakeup enabled/disabled
|
||||
*/
|
||||
device_init_wakeup(&udev->dev, 0);
|
||||
device_set_wakeup_enable(&udev->dev, 1);
|
||||
}
|
||||
|
||||
/* Tell the runtime-PM framework the device is active */
|
||||
@ -3038,7 +3048,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
|
||||
/* maybe switch power back on (e.g. root hub was reset) */
|
||||
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
|
||||
&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
|
||||
&& !(portstatus & USB_PORT_STAT_POWER))
|
||||
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
|
||||
|
||||
if (portstatus & USB_PORT_STAT_ENABLE)
|
||||
@ -3076,7 +3086,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
if (!(hcd->driver->flags & HCD_USB3))
|
||||
udev->speed = USB_SPEED_UNKNOWN;
|
||||
else if ((hdev->parent == NULL) &&
|
||||
(portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)))
|
||||
(portstatus & USB_PORT_STAT_SUPER_SPEED))
|
||||
udev->speed = USB_SPEED_SUPER;
|
||||
else
|
||||
udev->speed = USB_SPEED_UNKNOWN;
|
||||
|
@ -40,9 +40,9 @@
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include "usb.h"
|
||||
#include "hcd.h"
|
||||
|
||||
#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
|
||||
#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
|
||||
|
@ -14,9 +14,9 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
#include <linux/usb/hcd.h> /* for usbcore internals */
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "hcd.h" /* for usbcore internals */
|
||||
#include "usb.h"
|
||||
|
||||
static void cancel_async_set_config(struct usb_device *udev);
|
||||
@ -226,8 +226,7 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
|
||||
struct urb *urb;
|
||||
struct usb_host_endpoint *ep;
|
||||
|
||||
ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)
|
||||
[usb_pipeendpoint(pipe)];
|
||||
ep = usb_pipe_endpoint(usb_dev, pipe);
|
||||
if (!ep || len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@ -259,9 +258,6 @@ static void sg_clean(struct usb_sg_request *io)
|
||||
kfree(io->urbs);
|
||||
io->urbs = NULL;
|
||||
}
|
||||
if (io->dev->dev.dma_mask != NULL)
|
||||
usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
|
||||
io->sg, io->nents);
|
||||
io->dev = NULL;
|
||||
}
|
||||
|
||||
@ -364,7 +360,6 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
|
||||
{
|
||||
int i;
|
||||
int urb_flags;
|
||||
int dma;
|
||||
int use_sg;
|
||||
|
||||
if (!io || !dev || !sg
|
||||
@ -376,114 +371,76 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
|
||||
spin_lock_init(&io->lock);
|
||||
io->dev = dev;
|
||||
io->pipe = pipe;
|
||||
io->sg = sg;
|
||||
io->nents = nents;
|
||||
|
||||
/* not all host controllers use DMA (like the mainstream pci ones);
|
||||
* they can use PIO (sl811) or be software over another transport.
|
||||
*/
|
||||
dma = (dev->dev.dma_mask != NULL);
|
||||
if (dma)
|
||||
io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
|
||||
sg, nents);
|
||||
else
|
||||
io->entries = nents;
|
||||
|
||||
/* initialize all the urbs we'll use */
|
||||
if (io->entries <= 0)
|
||||
return io->entries;
|
||||
|
||||
if (dev->bus->sg_tablesize > 0) {
|
||||
io->urbs = kmalloc(sizeof *io->urbs, mem_flags);
|
||||
use_sg = true;
|
||||
io->entries = 1;
|
||||
} else {
|
||||
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
|
||||
use_sg = false;
|
||||
io->entries = nents;
|
||||
}
|
||||
|
||||
/* initialize all the urbs we'll use */
|
||||
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
|
||||
if (!io->urbs)
|
||||
goto nomem;
|
||||
|
||||
urb_flags = 0;
|
||||
if (dma)
|
||||
urb_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
urb_flags = URB_NO_INTERRUPT;
|
||||
if (usb_pipein(pipe))
|
||||
urb_flags |= URB_SHORT_NOT_OK;
|
||||
|
||||
if (use_sg) {
|
||||
io->urbs[0] = usb_alloc_urb(0, mem_flags);
|
||||
if (!io->urbs[0]) {
|
||||
io->entries = 0;
|
||||
for_each_sg(sg, sg, io->entries, i) {
|
||||
struct urb *urb;
|
||||
unsigned len;
|
||||
|
||||
urb = usb_alloc_urb(0, mem_flags);
|
||||
if (!urb) {
|
||||
io->entries = i;
|
||||
goto nomem;
|
||||
}
|
||||
io->urbs[i] = urb;
|
||||
|
||||
io->urbs[0]->dev = NULL;
|
||||
io->urbs[0]->pipe = pipe;
|
||||
io->urbs[0]->interval = period;
|
||||
io->urbs[0]->transfer_flags = urb_flags;
|
||||
urb->dev = NULL;
|
||||
urb->pipe = pipe;
|
||||
urb->interval = period;
|
||||
urb->transfer_flags = urb_flags;
|
||||
urb->complete = sg_complete;
|
||||
urb->context = io;
|
||||
urb->sg = sg;
|
||||
|
||||
io->urbs[0]->complete = sg_complete;
|
||||
io->urbs[0]->context = io;
|
||||
/* A length of zero means transfer the whole sg list */
|
||||
io->urbs[0]->transfer_buffer_length = length;
|
||||
if (length == 0) {
|
||||
for_each_sg(sg, sg, io->entries, i) {
|
||||
io->urbs[0]->transfer_buffer_length +=
|
||||
sg_dma_len(sg);
|
||||
if (use_sg) {
|
||||
/* There is no single transfer buffer */
|
||||
urb->transfer_buffer = NULL;
|
||||
urb->num_sgs = nents;
|
||||
|
||||
/* A length of zero means transfer the whole sg list */
|
||||
len = length;
|
||||
if (len == 0) {
|
||||
for_each_sg(sg, sg, nents, i)
|
||||
len += sg->length;
|
||||
}
|
||||
}
|
||||
io->urbs[0]->sg = io;
|
||||
io->urbs[0]->num_sgs = io->entries;
|
||||
io->entries = 1;
|
||||
} else {
|
||||
urb_flags |= URB_NO_INTERRUPT;
|
||||
for_each_sg(sg, sg, io->entries, 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 = NULL;
|
||||
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;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Some systems need to revert to PIO when DMA is temporarily
|
||||
* unavailable. For their sakes, both transfer_buffer and
|
||||
* transfer_dma are set when possible.
|
||||
*
|
||||
* Note that if IOMMU coalescing occurred, we cannot
|
||||
* trust sg_page anymore, so check if S/G list shrunk.
|
||||
* Some systems can't use DMA; they use PIO instead.
|
||||
* For their sakes, transfer_buffer is set whenever
|
||||
* possible.
|
||||
*/
|
||||
if (io->nents == io->entries && !PageHighMem(sg_page(sg)))
|
||||
io->urbs[i]->transfer_buffer = sg_virt(sg);
|
||||
if (!PageHighMem(sg_page(sg)))
|
||||
urb->transfer_buffer = sg_virt(sg);
|
||||
else
|
||||
io->urbs[i]->transfer_buffer = NULL;
|
||||
|
||||
if (dma) {
|
||||
io->urbs[i]->transfer_dma = sg_dma_address(sg);
|
||||
len = sg_dma_len(sg);
|
||||
} else {
|
||||
/* hc may use _only_ transfer_buffer */
|
||||
len = sg->length;
|
||||
}
|
||||
urb->transfer_buffer = NULL;
|
||||
|
||||
len = sg->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;
|
||||
urb->transfer_buffer_length = len;
|
||||
}
|
||||
io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
|
||||
|
||||
/* transaction state */
|
||||
io->count = io->entries;
|
||||
|
@ -71,6 +71,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||
/* SKYMEDI USB_DRIVE */
|
||||
{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* BUILDWIN Photo Frame */
|
||||
{ USB_DEVICE(0x1908, 0x1315), .driver_info =
|
||||
USB_QUIRK_HONOR_BNUMINTERFACES },
|
||||
|
||||
/* INTEL VALUE SSD */
|
||||
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
|
@ -383,13 +383,24 @@ static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
|
||||
static const char on_string[] = "on";
|
||||
static const char auto_string[] = "auto";
|
||||
|
||||
static void warn_level(void) {
|
||||
static int level_warned;
|
||||
|
||||
if (!level_warned) {
|
||||
level_warned = 1;
|
||||
printk(KERN_WARNING "WARNING! power/level is deprecated; "
|
||||
"use power/control instead\n");
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_level(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
const char *p = auto_string;
|
||||
|
||||
if (udev->state != USB_STATE_SUSPENDED && udev->autosuspend_disabled)
|
||||
warn_level();
|
||||
if (udev->state != USB_STATE_SUSPENDED && !udev->dev.power.runtime_auto)
|
||||
p = on_string;
|
||||
return sprintf(buf, "%s\n", p);
|
||||
}
|
||||
@ -401,8 +412,9 @@ set_level(struct device *dev, struct device_attribute *attr,
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
int len = count;
|
||||
char *cp;
|
||||
int rc;
|
||||
int rc = count;
|
||||
|
||||
warn_level();
|
||||
cp = memchr(buf, '\n', count);
|
||||
if (cp)
|
||||
len = cp - buf;
|
||||
@ -411,17 +423,17 @@ set_level(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
if (len == sizeof on_string - 1 &&
|
||||
strncmp(buf, on_string, len) == 0)
|
||||
rc = usb_disable_autosuspend(udev);
|
||||
usb_disable_autosuspend(udev);
|
||||
|
||||
else if (len == sizeof auto_string - 1 &&
|
||||
strncmp(buf, auto_string, len) == 0)
|
||||
rc = usb_enable_autosuspend(udev);
|
||||
usb_enable_autosuspend(udev);
|
||||
|
||||
else
|
||||
rc = -EINVAL;
|
||||
|
||||
usb_unlock_device(udev);
|
||||
return (rc < 0 ? rc : count);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/wait.h>
|
||||
#include "hcd.h"
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#define to_urb(d) container_of(d, struct urb, kref)
|
||||
|
||||
@ -308,8 +308,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
* will be required to set urb->ep directly and we will eliminate
|
||||
* urb->pipe.
|
||||
*/
|
||||
ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
|
||||
[usb_pipeendpoint(urb->pipe)];
|
||||
ep = usb_pipe_endpoint(dev, urb->pipe);
|
||||
if (!ep)
|
||||
return -ENOENT;
|
||||
|
||||
@ -333,9 +332,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
is_out = usb_endpoint_dir_out(&ep->desc);
|
||||
}
|
||||
|
||||
/* Cache the direction for later use */
|
||||
urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
|
||||
(is_out ? URB_DIR_OUT : URB_DIR_IN);
|
||||
/* 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);
|
||||
urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
|
||||
|
||||
if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
|
||||
dev->state < USB_STATE_CONFIGURED)
|
||||
@ -396,8 +398,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
return -EPIPE; /* The most suitable error code :-) */
|
||||
|
||||
/* enforce simple/standard policy */
|
||||
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
|
||||
URB_NO_INTERRUPT | URB_DIR_MASK | URB_FREE_BUFFER);
|
||||
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)
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/debugfs.h>
|
||||
@ -41,7 +42,6 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "hcd.h"
|
||||
#include "usb.h"
|
||||
|
||||
|
||||
@ -593,76 +593,6 @@ int usb_lock_device_for_reset(struct usb_device *udev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
|
||||
|
||||
static struct usb_device *match_device(struct usb_device *dev,
|
||||
u16 vendor_id, u16 product_id)
|
||||
{
|
||||
struct usb_device *ret_dev = NULL;
|
||||
int child;
|
||||
|
||||
dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
|
||||
/* see if this device matches */
|
||||
if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
|
||||
(product_id == le16_to_cpu(dev->descriptor.idProduct))) {
|
||||
dev_dbg(&dev->dev, "matched this device!\n");
|
||||
ret_dev = usb_get_dev(dev);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* look through all of the children of this device */
|
||||
for (child = 0; child < dev->maxchild; ++child) {
|
||||
if (dev->children[child]) {
|
||||
usb_lock_device(dev->children[child]);
|
||||
ret_dev = match_device(dev->children[child],
|
||||
vendor_id, product_id);
|
||||
usb_unlock_device(dev->children[child]);
|
||||
if (ret_dev)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return ret_dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_find_device - find a specific usb device in the system
|
||||
* @vendor_id: the vendor id of the device to find
|
||||
* @product_id: the product id of the device to find
|
||||
*
|
||||
* Returns a pointer to a struct usb_device if such a specified usb
|
||||
* device is present in the system currently. The usage count of the
|
||||
* device will be incremented if a device is found. Make sure to call
|
||||
* usb_put_dev() when the caller is finished with the device.
|
||||
*
|
||||
* If a device with the specified vendor and product id is not found,
|
||||
* NULL is returned.
|
||||
*/
|
||||
struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
|
||||
{
|
||||
struct list_head *buslist;
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev = NULL;
|
||||
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
for (buslist = usb_bus_list.next;
|
||||
buslist != &usb_bus_list;
|
||||
buslist = buslist->next) {
|
||||
bus = container_of(buslist, struct usb_bus, bus_list);
|
||||
if (!bus->root_hub)
|
||||
continue;
|
||||
usb_lock_device(bus->root_hub);
|
||||
dev = match_device(bus->root_hub, vendor_id, product_id);
|
||||
usb_unlock_device(bus->root_hub);
|
||||
if (dev)
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_get_current_frame_number - return current bus frame number
|
||||
* @dev: the device whose bus is being queried
|
||||
@ -775,7 +705,7 @@ EXPORT_SYMBOL_GPL(usb_free_coherent);
|
||||
* @urb: urb whose transfer_buffer/setup_packet will be mapped
|
||||
*
|
||||
* Return value is either null (indicating no buffer could be mapped), or
|
||||
* the parameter. URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP are
|
||||
* the parameter. URB_NO_TRANSFER_DMA_MAP is
|
||||
* added to urb->transfer_flags if the operation succeeds. If the device
|
||||
* is connected to this system through a non-DMA controller, this operation
|
||||
* always succeeds.
|
||||
@ -803,17 +733,11 @@ struct urb *usb_buffer_map(struct urb *urb)
|
||||
urb->transfer_buffer, urb->transfer_buffer_length,
|
||||
usb_pipein(urb->pipe)
|
||||
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
if (usb_pipecontrol(urb->pipe))
|
||||
urb->setup_dma = dma_map_single(controller,
|
||||
urb->setup_packet,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
/* FIXME generic api broken like pci, can't report errors */
|
||||
/* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */
|
||||
} else
|
||||
urb->transfer_dma = ~0;
|
||||
urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
|
||||
| URB_NO_SETUP_DMA_MAP);
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
return urb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_buffer_map);
|
||||
@ -881,18 +805,13 @@ void usb_buffer_unmap(struct urb *urb)
|
||||
urb->transfer_dma, urb->transfer_buffer_length,
|
||||
usb_pipein(urb->pipe)
|
||||
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
if (usb_pipecontrol(urb->pipe))
|
||||
dma_unmap_single(controller,
|
||||
urb->setup_dma,
|
||||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
|
||||
| URB_NO_SETUP_DMA_MAP);
|
||||
urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_buffer_unmap);
|
||||
#endif /* 0 */
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
|
||||
* @dev: device to which the scatterlist will be mapped
|
||||
@ -936,6 +855,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
|
||||
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE) ? : -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_buffer_map_sg);
|
||||
#endif
|
||||
|
||||
/* XXX DISABLED, no users currently. If you wish to re-enable this
|
||||
* XXX please determine whether the sync is to transfer ownership of
|
||||
@ -972,6 +892,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
|
||||
EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
|
||||
* @dev: device to which the scatterlist will be mapped
|
||||
@ -997,6 +918,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
|
||||
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg);
|
||||
#endif
|
||||
|
||||
/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
|
||||
#ifdef MODULE
|
||||
|
@ -710,6 +710,43 @@ config USB_GADGETFS
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "gadgetfs".
|
||||
|
||||
config USB_FUNCTIONFS
|
||||
tristate "Function Filesystem (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
The Function Filesystem (FunctioFS) lets one create USB
|
||||
composite functions in user space in the same way as GadgetFS
|
||||
lets one create USB gadgets in user space. This allows creation
|
||||
of composite gadgets such that some of the functions are
|
||||
implemented in kernel space (for instance Ethernet, serial or
|
||||
mass storage) and other are implemented in user space.
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build
|
||||
a dynamically linked module called "g_ffs".
|
||||
|
||||
config USB_FUNCTIONFS_ETH
|
||||
bool "Include CDC ECM (Ethernet) function"
|
||||
depends on USB_FUNCTIONFS && NET
|
||||
help
|
||||
Include an CDC ECM (Ethernet) funcion in the CDC ECM (Funcion)
|
||||
Filesystem. If you also say "y" to the RNDIS query below the
|
||||
gadget will have two configurations.
|
||||
|
||||
config USB_FUNCTIONFS_RNDIS
|
||||
bool "Include RNDIS (Ethernet) function"
|
||||
depends on USB_FUNCTIONFS && NET
|
||||
help
|
||||
Include an RNDIS (Ethernet) funcion in the Funcion Filesystem.
|
||||
If you also say "y" to the CDC ECM query above the gadget will
|
||||
have two configurations.
|
||||
|
||||
config USB_FUNCTIONFS_GENERIC
|
||||
bool "Include 'pure' configuration"
|
||||
depends on USB_FUNCTIONFS && (USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
|
||||
help
|
||||
Include a configuration with FunctionFS and no Ethernet
|
||||
configuration.
|
||||
|
||||
config USB_FILE_STORAGE
|
||||
tristate "File-backed Storage Gadget"
|
||||
depends on BLOCK
|
||||
@ -863,11 +900,30 @@ config USB_G_MULTI_CDC
|
||||
|
||||
If unsure, say "y".
|
||||
|
||||
config USB_G_HID
|
||||
tristate "HID Gadget"
|
||||
help
|
||||
The HID gadget driver provides generic emulation of USB
|
||||
Human Interface Devices (HID).
|
||||
|
||||
For more information, see Documentation/usb/gadget_hid.txt which
|
||||
includes sample code for accessing the device files.
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "g_hid".
|
||||
|
||||
# put drivers that need isochronous transfer support (for audio
|
||||
# or video class gadget drivers), or specific hardware, here.
|
||||
config USB_G_WEBCAM
|
||||
tristate "USB Webcam Gadget"
|
||||
depends on VIDEO_DEV
|
||||
help
|
||||
The Webcam Gadget acts as a composite USB Audio and Video Class
|
||||
device. It provides a userspace API to process UVC control requests
|
||||
and stream video data to the host.
|
||||
|
||||
# - none yet
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "g_webcam".
|
||||
|
||||
endchoice
|
||||
|
||||
|
@ -20,7 +20,7 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
|
||||
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
|
||||
fsl_usb2_udc-objs := fsl_udc_core.o
|
||||
ifeq ($(CONFIG_ARCH_MXC),y)
|
||||
fsl_usb2_udc-objs += fsl_mx3_udc.o
|
||||
fsl_usb2_udc-objs += fsl_mxc_udc.o
|
||||
endif
|
||||
obj-$(CONFIG_USB_M66592) += m66592-udc.o
|
||||
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
|
||||
@ -43,18 +43,24 @@ g_mass_storage-objs := mass_storage.o
|
||||
g_printer-objs := printer.o
|
||||
g_cdc-objs := cdc2.o
|
||||
g_multi-objs := multi.o
|
||||
g_hid-objs := hid.o
|
||||
g_nokia-objs := nokia.o
|
||||
g_webcam-objs := webcam.o
|
||||
|
||||
obj-$(CONFIG_USB_ZERO) += g_zero.o
|
||||
obj-$(CONFIG_USB_AUDIO) += g_audio.o
|
||||
obj-$(CONFIG_USB_ETH) += g_ether.o
|
||||
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
|
||||
obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o
|
||||
obj-$(CONFIG_USB_ETH_FUNCTIONFS) += g_eth_ffs.o
|
||||
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
|
||||
obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
|
||||
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
|
||||
obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
|
||||
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
|
||||
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
|
||||
obj-$(CONFIG_USB_G_HID) += g_hid.o
|
||||
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
|
||||
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
|
||||
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
|
||||
|
||||
|
@ -48,10 +48,9 @@ static int queue_dbg_open(struct inode *inode, struct file *file)
|
||||
|
||||
spin_lock_irq(&ep->udc->lock);
|
||||
list_for_each_entry(req, &ep->queue, queue) {
|
||||
req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
|
||||
req_copy = kmemdup(req, sizeof(*req_copy), GFP_ATOMIC);
|
||||
if (!req_copy)
|
||||
goto fail;
|
||||
memcpy(req_copy, req, sizeof(*req_copy));
|
||||
list_add_tail(&req_copy->queue, queue_data);
|
||||
}
|
||||
spin_unlock_irq(&ep->udc->lock);
|
||||
|
@ -36,7 +36,7 @@
|
||||
*/
|
||||
|
||||
/* big enough to hold our biggest descriptor */
|
||||
#define USB_BUFSIZ 512
|
||||
#define USB_BUFSIZ 1024
|
||||
|
||||
static struct usb_composite_driver *composite;
|
||||
|
||||
@ -85,7 +85,7 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
|
||||
* This function returns the value of the function's bind(), which is
|
||||
* zero for success else a negative errno value.
|
||||
*/
|
||||
int __init usb_add_function(struct usb_configuration *config,
|
||||
int usb_add_function(struct usb_configuration *config,
|
||||
struct usb_function *function)
|
||||
{
|
||||
int value = -EINVAL;
|
||||
@ -215,7 +215,7 @@ int usb_function_activate(struct usb_function *function)
|
||||
* Returns the interface ID which was allocated; or -ENODEV if no
|
||||
* more interface IDs can be allocated.
|
||||
*/
|
||||
int __init usb_interface_id(struct usb_configuration *config,
|
||||
int usb_interface_id(struct usb_configuration *config,
|
||||
struct usb_function *function)
|
||||
{
|
||||
unsigned id = config->next_interface_id;
|
||||
@ -480,7 +480,7 @@ done:
|
||||
* assigns global resources including string IDs, and per-configuration
|
||||
* resources such as interface IDs and endpoints.
|
||||
*/
|
||||
int __init usb_add_config(struct usb_composite_dev *cdev,
|
||||
int usb_add_config(struct usb_composite_dev *cdev,
|
||||
struct usb_configuration *config)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
@ -677,7 +677,7 @@ static int get_string(struct usb_composite_dev *cdev,
|
||||
* ensure that for example different functions don't wrongly assign
|
||||
* different meanings to the same identifier.
|
||||
*/
|
||||
int __init usb_string_id(struct usb_composite_dev *cdev)
|
||||
int usb_string_id(struct usb_composite_dev *cdev)
|
||||
{
|
||||
if (cdev->next_string_id < 254) {
|
||||
/* string id 0 is reserved */
|
||||
@ -898,7 +898,19 @@ static void composite_disconnect(struct usb_gadget *gadget)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void /* __init_or_exit */
|
||||
static ssize_t composite_show_suspended(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_gadget *gadget = dev_to_usb_gadget(dev);
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
|
||||
return sprintf(buf, "%d\n", cdev->suspended);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
|
||||
|
||||
static void
|
||||
composite_unbind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
@ -944,10 +956,11 @@ composite_unbind(struct usb_gadget *gadget)
|
||||
}
|
||||
kfree(cdev);
|
||||
set_gadget_data(gadget, NULL);
|
||||
device_remove_file(&gadget->dev, &dev_attr_suspended);
|
||||
composite = NULL;
|
||||
}
|
||||
|
||||
static void __init
|
||||
static void
|
||||
string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
|
||||
{
|
||||
struct usb_string *str = tab->strings;
|
||||
@ -960,7 +973,7 @@ string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void __init
|
||||
static void
|
||||
string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
|
||||
{
|
||||
while (*tab) {
|
||||
@ -969,7 +982,7 @@ string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
|
||||
}
|
||||
}
|
||||
|
||||
static int __init composite_bind(struct usb_gadget *gadget)
|
||||
static int composite_bind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev;
|
||||
int status = -ENOMEM;
|
||||
@ -1004,6 +1017,14 @@ static int __init composite_bind(struct usb_gadget *gadget)
|
||||
*/
|
||||
usb_ep_autoconfig_reset(cdev->gadget);
|
||||
|
||||
/* standardized runtime overrides for device ID data */
|
||||
if (idVendor)
|
||||
cdev->desc.idVendor = cpu_to_le16(idVendor);
|
||||
if (idProduct)
|
||||
cdev->desc.idProduct = cpu_to_le16(idProduct);
|
||||
if (bcdDevice)
|
||||
cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
|
||||
|
||||
/* composite gadget needs to assign strings for whole device (like
|
||||
* serial number), register function drivers, potentially update
|
||||
* power state and consumption, etc
|
||||
@ -1015,14 +1036,6 @@ static int __init composite_bind(struct usb_gadget *gadget)
|
||||
cdev->desc = *composite->dev;
|
||||
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
/* standardized runtime overrides for device ID data */
|
||||
if (idVendor)
|
||||
cdev->desc.idVendor = cpu_to_le16(idVendor);
|
||||
if (idProduct)
|
||||
cdev->desc.idProduct = cpu_to_le16(idProduct);
|
||||
if (bcdDevice)
|
||||
cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
|
||||
|
||||
/* strings can't be assigned before bind() allocates the
|
||||
* releavnt identifiers
|
||||
*/
|
||||
@ -1036,6 +1049,10 @@ static int __init composite_bind(struct usb_gadget *gadget)
|
||||
string_override(composite->strings,
|
||||
cdev->desc.iSerialNumber, iSerialNumber);
|
||||
|
||||
status = device_create_file(&gadget->dev, &dev_attr_suspended);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
INFO(cdev, "%s ready\n", composite->name);
|
||||
return 0;
|
||||
|
||||
@ -1064,6 +1081,8 @@ composite_suspend(struct usb_gadget *gadget)
|
||||
}
|
||||
if (composite->suspend)
|
||||
composite->suspend(cdev);
|
||||
|
||||
cdev->suspended = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1084,6 +1103,8 @@ composite_resume(struct usb_gadget *gadget)
|
||||
f->resume(f);
|
||||
}
|
||||
}
|
||||
|
||||
cdev->suspended = 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -1092,7 +1113,6 @@ static struct usb_gadget_driver composite_driver = {
|
||||
.speed = USB_SPEED_HIGH,
|
||||
|
||||
.bind = composite_bind,
|
||||
/* .unbind = __exit_p(composite_unbind), */
|
||||
.unbind = composite_unbind,
|
||||
|
||||
.setup = composite_setup,
|
||||
@ -1121,7 +1141,7 @@ static struct usb_gadget_driver composite_driver = {
|
||||
* while it was binding. That would usually be done in order to wait for
|
||||
* some userspace participation.
|
||||
*/
|
||||
int __init usb_composite_register(struct usb_composite_driver *driver)
|
||||
int usb_composite_register(struct usb_composite_driver *driver)
|
||||
{
|
||||
if (!driver || !driver->dev || !driver->bind || composite)
|
||||
return -EINVAL;
|
||||
@ -1142,7 +1162,7 @@ int __init usb_composite_register(struct usb_composite_driver *driver)
|
||||
* This function is used to unregister drivers using the composite
|
||||
* driver framework.
|
||||
*/
|
||||
void /* __exit */ usb_composite_unregister(struct usb_composite_driver *driver)
|
||||
void usb_composite_unregister(struct usb_composite_driver *driver)
|
||||
{
|
||||
if (composite != driver)
|
||||
return;
|
||||
|
@ -128,7 +128,7 @@ int usb_gadget_config_buf(
|
||||
* with identifiers (for interfaces, strings, endpoints, and more)
|
||||
* as needed by a given function instance.
|
||||
*/
|
||||
struct usb_descriptor_header **__init
|
||||
struct usb_descriptor_header **
|
||||
usb_copy_descriptors(struct usb_descriptor_header **src)
|
||||
{
|
||||
struct usb_descriptor_header **tmp;
|
||||
@ -175,7 +175,7 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
|
||||
* intended use is to help remembering the endpoint descriptor to use
|
||||
* when enabling a given endpoint.
|
||||
*/
|
||||
struct usb_endpoint_descriptor *__init
|
||||
struct usb_endpoint_descriptor *
|
||||
usb_find_endpoint(
|
||||
struct usb_descriptor_header **src,
|
||||
struct usb_descriptor_header **copy,
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/io.h>
|
||||
@ -55,9 +56,6 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
||||
#include "../core/hcd.h"
|
||||
|
||||
|
||||
#define DRIVER_DESC "USB Host+Gadget Emulator"
|
||||
#define DRIVER_VERSION "02 May 2005"
|
||||
|
||||
|
@ -34,12 +34,12 @@
|
||||
|
||||
|
||||
/* we must assign addresses for configurable endpoints (like net2280) */
|
||||
static __initdata unsigned epnum;
|
||||
static unsigned epnum;
|
||||
|
||||
// #define MANY_ENDPOINTS
|
||||
#ifdef MANY_ENDPOINTS
|
||||
/* more than 15 configurable endpoints */
|
||||
static __initdata unsigned in_epnum;
|
||||
static unsigned in_epnum;
|
||||
#endif
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ static __initdata unsigned in_epnum;
|
||||
* NOTE: each endpoint is unidirectional, as specified by its USB
|
||||
* descriptor; and isn't specific to a configuration or altsetting.
|
||||
*/
|
||||
static int __init
|
||||
static int
|
||||
ep_matches (
|
||||
struct usb_gadget *gadget,
|
||||
struct usb_ep *ep,
|
||||
@ -187,7 +187,7 @@ ep_matches (
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct usb_ep * __init
|
||||
static struct usb_ep *
|
||||
find_ep (struct usb_gadget *gadget, const char *name)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
@ -229,7 +229,7 @@ find_ep (struct usb_gadget *gadget, const char *name)
|
||||
*
|
||||
* On failure, this returns a null endpoint descriptor.
|
||||
*/
|
||||
struct usb_ep * __init usb_ep_autoconfig (
|
||||
struct usb_ep *usb_ep_autoconfig (
|
||||
struct usb_gadget *gadget,
|
||||
struct usb_endpoint_descriptor *desc
|
||||
)
|
||||
@ -304,7 +304,7 @@ struct usb_ep * __init usb_ep_autoconfig (
|
||||
* state such as ep->driver_data and the record of assigned endpoints
|
||||
* used by usb_ep_autoconfig().
|
||||
*/
|
||||
void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget)
|
||||
void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
|
||||
|
@ -116,7 +116,7 @@ acm_iad_descriptor = {
|
||||
};
|
||||
|
||||
|
||||
static struct usb_interface_descriptor acm_control_interface_desc __initdata = {
|
||||
static struct usb_interface_descriptor acm_control_interface_desc = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
/* .bInterfaceNumber = DYNAMIC */
|
||||
@ -127,7 +127,7 @@ static struct usb_interface_descriptor acm_control_interface_desc __initdata = {
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor acm_data_interface_desc __initdata = {
|
||||
static struct usb_interface_descriptor acm_data_interface_desc = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
/* .bInterfaceNumber = DYNAMIC */
|
||||
@ -138,7 +138,7 @@ static struct usb_interface_descriptor acm_data_interface_desc __initdata = {
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_header_desc acm_header_desc __initdata = {
|
||||
static struct usb_cdc_header_desc acm_header_desc = {
|
||||
.bLength = sizeof(acm_header_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
@ -146,7 +146,7 @@ static struct usb_cdc_header_desc acm_header_desc __initdata = {
|
||||
};
|
||||
|
||||
static struct usb_cdc_call_mgmt_descriptor
|
||||
acm_call_mgmt_descriptor __initdata = {
|
||||
acm_call_mgmt_descriptor = {
|
||||
.bLength = sizeof(acm_call_mgmt_descriptor),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
|
||||
@ -154,14 +154,14 @@ acm_call_mgmt_descriptor __initdata = {
|
||||
/* .bDataInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
|
||||
static struct usb_cdc_acm_descriptor acm_descriptor = {
|
||||
.bLength = sizeof(acm_descriptor),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||
.bmCapabilities = USB_CDC_CAP_LINE,
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc acm_union_desc __initdata = {
|
||||
static struct usb_cdc_union_desc acm_union_desc = {
|
||||
.bLength = sizeof(acm_union_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||
@ -171,7 +171,7 @@ static struct usb_cdc_union_desc acm_union_desc __initdata = {
|
||||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor acm_fs_notify_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor acm_fs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
@ -180,21 +180,21 @@ static struct usb_endpoint_descriptor acm_fs_notify_desc __initdata = {
|
||||
.bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acm_fs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor acm_fs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acm_fs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor acm_fs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *acm_fs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *acm_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &acm_iad_descriptor,
|
||||
(struct usb_descriptor_header *) &acm_control_interface_desc,
|
||||
(struct usb_descriptor_header *) &acm_header_desc,
|
||||
@ -210,7 +210,7 @@ static struct usb_descriptor_header *acm_fs_function[] __initdata = {
|
||||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor acm_hs_notify_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor acm_hs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
@ -219,21 +219,21 @@ static struct usb_endpoint_descriptor acm_hs_notify_desc __initdata = {
|
||||
.bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acm_hs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor acm_hs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor acm_hs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *acm_hs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *acm_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &acm_iad_descriptor,
|
||||
(struct usb_descriptor_header *) &acm_control_interface_desc,
|
||||
(struct usb_descriptor_header *) &acm_header_desc,
|
||||
@ -571,7 +571,7 @@ static int acm_send_break(struct gserial *port, int duration)
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* ACM function driver setup/binding */
|
||||
static int __init
|
||||
static int
|
||||
acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
@ -719,7 +719,7 @@ static inline bool can_support_cdc(struct usb_configuration *c)
|
||||
* handle all the ones it binds. Caller is also responsible
|
||||
* for calling @gserial_cleanup() before module unload.
|
||||
*/
|
||||
int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
int acm_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
{
|
||||
struct f_acm *acm;
|
||||
int status;
|
||||
|
@ -113,7 +113,7 @@ static inline unsigned ecm_bitrate(struct usb_gadget *g)
|
||||
|
||||
/* interface descriptor: */
|
||||
|
||||
static struct usb_interface_descriptor ecm_control_intf __initdata = {
|
||||
static struct usb_interface_descriptor ecm_control_intf = {
|
||||
.bLength = sizeof ecm_control_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -126,7 +126,7 @@ static struct usb_interface_descriptor ecm_control_intf __initdata = {
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_header_desc ecm_header_desc __initdata = {
|
||||
static struct usb_cdc_header_desc ecm_header_desc = {
|
||||
.bLength = sizeof ecm_header_desc,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
@ -134,7 +134,7 @@ static struct usb_cdc_header_desc ecm_header_desc __initdata = {
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc ecm_union_desc __initdata = {
|
||||
static struct usb_cdc_union_desc ecm_union_desc = {
|
||||
.bLength = sizeof(ecm_union_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||
@ -142,7 +142,7 @@ static struct usb_cdc_union_desc ecm_union_desc __initdata = {
|
||||
/* .bSlaveInterface0 = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_ether_desc ecm_desc __initdata = {
|
||||
static struct usb_cdc_ether_desc ecm_desc = {
|
||||
.bLength = sizeof ecm_desc,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
|
||||
@ -157,7 +157,7 @@ static struct usb_cdc_ether_desc ecm_desc __initdata = {
|
||||
|
||||
/* the default data interface has no endpoints ... */
|
||||
|
||||
static struct usb_interface_descriptor ecm_data_nop_intf __initdata = {
|
||||
static struct usb_interface_descriptor ecm_data_nop_intf = {
|
||||
.bLength = sizeof ecm_data_nop_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -172,7 +172,7 @@ static struct usb_interface_descriptor ecm_data_nop_intf __initdata = {
|
||||
|
||||
/* ... but the "real" data interface has two bulk endpoints */
|
||||
|
||||
static struct usb_interface_descriptor ecm_data_intf __initdata = {
|
||||
static struct usb_interface_descriptor ecm_data_intf = {
|
||||
.bLength = sizeof ecm_data_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -187,7 +187,7 @@ static struct usb_interface_descriptor ecm_data_intf __initdata = {
|
||||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor fs_ecm_notify_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor fs_ecm_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -197,7 +197,7 @@ static struct usb_endpoint_descriptor fs_ecm_notify_desc __initdata = {
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_ecm_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor fs_ecm_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -205,7 +205,7 @@ static struct usb_endpoint_descriptor fs_ecm_in_desc __initdata = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_ecm_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor fs_ecm_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -213,7 +213,7 @@ static struct usb_endpoint_descriptor fs_ecm_out_desc __initdata = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *ecm_fs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *ecm_fs_function[] = {
|
||||
/* CDC ECM control descriptors */
|
||||
(struct usb_descriptor_header *) &ecm_control_intf,
|
||||
(struct usb_descriptor_header *) &ecm_header_desc,
|
||||
@ -231,7 +231,7 @@ static struct usb_descriptor_header *ecm_fs_function[] __initdata = {
|
||||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ecm_notify_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -240,7 +240,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc __initdata = {
|
||||
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
};
|
||||
static struct usb_endpoint_descriptor hs_ecm_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor hs_ecm_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -249,7 +249,7 @@ static struct usb_endpoint_descriptor hs_ecm_in_desc __initdata = {
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ecm_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor hs_ecm_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -258,7 +258,7 @@ static struct usb_endpoint_descriptor hs_ecm_out_desc __initdata = {
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *ecm_hs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *ecm_hs_function[] = {
|
||||
/* CDC ECM control descriptors */
|
||||
(struct usb_descriptor_header *) &ecm_control_intf,
|
||||
(struct usb_descriptor_header *) &ecm_header_desc,
|
||||
@ -597,7 +597,7 @@ static void ecm_close(struct gether *geth)
|
||||
|
||||
/* ethernet function driver setup/binding */
|
||||
|
||||
static int __init
|
||||
static int
|
||||
ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
@ -763,7 +763,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int __init ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
int
|
||||
ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
{
|
||||
struct f_ecm *ecm;
|
||||
int status;
|
||||
|
2442
drivers/usb/gadget/f_fs.c
Normal file
2442
drivers/usb/gadget/f_fs.c
Normal file
File diff suppressed because it is too large
Load Diff
673
drivers/usb/gadget/f_hid.c
Normal file
673
drivers/usb/gadget/f_hid.c
Normal file
@ -0,0 +1,673 @@
|
||||
/*
|
||||
* f_hid.c -- USB HID function driver
|
||||
*
|
||||
* Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/usb/g_hid.h>
|
||||
|
||||
static int major, minors;
|
||||
static struct class *hidg_class;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* HID gadget struct */
|
||||
|
||||
struct f_hidg {
|
||||
/* configuration */
|
||||
unsigned char bInterfaceSubClass;
|
||||
unsigned char bInterfaceProtocol;
|
||||
unsigned short report_desc_length;
|
||||
char *report_desc;
|
||||
unsigned short report_length;
|
||||
|
||||
/* recv report */
|
||||
char *set_report_buff;
|
||||
unsigned short set_report_length;
|
||||
spinlock_t spinlock;
|
||||
wait_queue_head_t read_queue;
|
||||
|
||||
/* send report */
|
||||
struct mutex lock;
|
||||
bool write_pending;
|
||||
wait_queue_head_t write_queue;
|
||||
struct usb_request *req;
|
||||
|
||||
int minor;
|
||||
struct cdev cdev;
|
||||
struct usb_function func;
|
||||
struct usb_ep *in_ep;
|
||||
struct usb_endpoint_descriptor *fs_in_ep_desc;
|
||||
struct usb_endpoint_descriptor *hs_in_ep_desc;
|
||||
};
|
||||
|
||||
static inline struct f_hidg *func_to_hidg(struct usb_function *f)
|
||||
{
|
||||
return container_of(f, struct f_hidg, func);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Static descriptors */
|
||||
|
||||
static struct usb_interface_descriptor hidg_interface_desc = {
|
||||
.bLength = sizeof hidg_interface_desc,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
/* .bInterfaceNumber = DYNAMIC */
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_HID,
|
||||
/* .bInterfaceSubClass = DYNAMIC */
|
||||
/* .bInterfaceProtocol = DYNAMIC */
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct hid_descriptor hidg_desc = {
|
||||
.bLength = sizeof hidg_desc,
|
||||
.bDescriptorType = HID_DT_HID,
|
||||
.bcdHID = 0x0101,
|
||||
.bCountryCode = 0x00,
|
||||
.bNumDescriptors = 0x1,
|
||||
/*.desc[0].bDescriptorType = DYNAMIC */
|
||||
/*.desc[0].wDescriptorLenght = DYNAMIC */
|
||||
};
|
||||
|
||||
/* High-Speed Support */
|
||||
|
||||
static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
/*.wMaxPacketSize = DYNAMIC */
|
||||
.bInterval = 4, /* FIXME: Add this field in the
|
||||
* HID gadget configuration?
|
||||
* (struct hidg_func_descriptor)
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hidg_hs_descriptors[] = {
|
||||
(struct usb_descriptor_header *)&hidg_interface_desc,
|
||||
(struct usb_descriptor_header *)&hidg_desc,
|
||||
(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* Full-Speed Support */
|
||||
|
||||
static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
/*.wMaxPacketSize = DYNAMIC */
|
||||
.bInterval = 10, /* FIXME: Add this field in the
|
||||
* HID gadget configuration?
|
||||
* (struct hidg_func_descriptor)
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hidg_fs_descriptors[] = {
|
||||
(struct usb_descriptor_header *)&hidg_interface_desc,
|
||||
(struct usb_descriptor_header *)&hidg_desc,
|
||||
(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Char Device */
|
||||
|
||||
static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||
size_t count, loff_t *ptr)
|
||||
{
|
||||
struct f_hidg *hidg = (struct f_hidg *)file->private_data;
|
||||
char *tmp_buff = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
||||
|
||||
#define READ_COND (hidg->set_report_buff != NULL)
|
||||
|
||||
while (!READ_COND) {
|
||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible(hidg->read_queue, READ_COND))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
||||
}
|
||||
|
||||
|
||||
count = min_t(unsigned, count, hidg->set_report_length);
|
||||
tmp_buff = hidg->set_report_buff;
|
||||
hidg->set_report_buff = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
||||
|
||||
if (tmp_buff != NULL) {
|
||||
/* copy to user outside spinlock */
|
||||
count -= copy_to_user(buffer, tmp_buff, count);
|
||||
kfree(tmp_buff);
|
||||
} else
|
||||
count = -ENOMEM;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_hidg *hidg = (struct f_hidg *)ep->driver_data;
|
||||
|
||||
if (req->status != 0) {
|
||||
ERROR(hidg->func.config->cdev,
|
||||
"End Point Request ERROR: %d\n", req->status);
|
||||
}
|
||||
|
||||
hidg->write_pending = 0;
|
||||
wake_up(&hidg->write_queue);
|
||||
}
|
||||
|
||||
static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *offp)
|
||||
{
|
||||
struct f_hidg *hidg = (struct f_hidg *)file->private_data;
|
||||
ssize_t status = -ENOMEM;
|
||||
|
||||
if (!access_ok(VERIFY_READ, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&hidg->lock);
|
||||
|
||||
#define WRITE_COND (!hidg->write_pending)
|
||||
|
||||
/* write queue */
|
||||
while (!WRITE_COND) {
|
||||
mutex_unlock(&hidg->lock);
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
if (wait_event_interruptible_exclusive(
|
||||
hidg->write_queue, WRITE_COND))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
mutex_lock(&hidg->lock);
|
||||
}
|
||||
|
||||
count = min_t(unsigned, count, hidg->report_length);
|
||||
status = copy_from_user(hidg->req->buf, buffer, count);
|
||||
|
||||
if (status != 0) {
|
||||
ERROR(hidg->func.config->cdev,
|
||||
"copy_from_user error\n");
|
||||
mutex_unlock(&hidg->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hidg->req->status = 0;
|
||||
hidg->req->zero = 0;
|
||||
hidg->req->length = count;
|
||||
hidg->req->complete = f_hidg_req_complete;
|
||||
hidg->req->context = hidg;
|
||||
hidg->write_pending = 1;
|
||||
|
||||
status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
|
||||
if (status < 0) {
|
||||
ERROR(hidg->func.config->cdev,
|
||||
"usb_ep_queue error on int endpoint %zd\n", status);
|
||||
hidg->write_pending = 0;
|
||||
wake_up(&hidg->write_queue);
|
||||
} else {
|
||||
status = count;
|
||||
}
|
||||
|
||||
mutex_unlock(&hidg->lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static unsigned int f_hidg_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct f_hidg *hidg = (struct f_hidg *)file->private_data;
|
||||
unsigned int ret = 0;
|
||||
|
||||
poll_wait(file, &hidg->read_queue, wait);
|
||||
poll_wait(file, &hidg->write_queue, wait);
|
||||
|
||||
if (WRITE_COND)
|
||||
ret |= POLLOUT | POLLWRNORM;
|
||||
|
||||
if (READ_COND)
|
||||
ret |= POLLIN | POLLRDNORM;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef WRITE_COND
|
||||
#undef READ_COND
|
||||
|
||||
static int f_hidg_release(struct inode *inode, struct file *fd)
|
||||
{
|
||||
fd->private_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f_hidg_open(struct inode *inode, struct file *fd)
|
||||
{
|
||||
struct f_hidg *hidg =
|
||||
container_of(inode->i_cdev, struct f_hidg, cdev);
|
||||
|
||||
fd->private_data = hidg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* usb_function */
|
||||
|
||||
static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_hidg *hidg = (struct f_hidg *)req->context;
|
||||
|
||||
if (req->status != 0 || req->buf == NULL || req->actual == 0) {
|
||||
ERROR(hidg->func.config->cdev, "%s FAILED\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock(&hidg->spinlock);
|
||||
|
||||
hidg->set_report_buff = krealloc(hidg->set_report_buff,
|
||||
req->actual, GFP_ATOMIC);
|
||||
|
||||
if (hidg->set_report_buff == NULL) {
|
||||
spin_unlock(&hidg->spinlock);
|
||||
return;
|
||||
}
|
||||
hidg->set_report_length = req->actual;
|
||||
memcpy(hidg->set_report_buff, req->buf, req->actual);
|
||||
|
||||
spin_unlock(&hidg->spinlock);
|
||||
|
||||
wake_up(&hidg->read_queue);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int hidg_setup(struct usb_function *f,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
struct usb_request *req = cdev->req;
|
||||
int status = 0;
|
||||
__u16 value, length;
|
||||
|
||||
value = __le16_to_cpu(ctrl->wValue);
|
||||
length = __le16_to_cpu(ctrl->wLength);
|
||||
|
||||
VDBG(cdev, "hid_setup crtl_request : bRequestType:0x%x bRequest:0x%x "
|
||||
"Value:0x%x\n", ctrl->bRequestType, ctrl->bRequest, value);
|
||||
|
||||
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
||||
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
|
||||
| HID_REQ_GET_REPORT):
|
||||
VDBG(cdev, "get_report\n");
|
||||
|
||||
/* send an empty report */
|
||||
length = min_t(unsigned, length, hidg->report_length);
|
||||
memset(req->buf, 0x0, length);
|
||||
|
||||
goto respond;
|
||||
break;
|
||||
|
||||
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
|
||||
| HID_REQ_GET_PROTOCOL):
|
||||
VDBG(cdev, "get_protocol\n");
|
||||
goto stall;
|
||||
break;
|
||||
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
|
||||
| HID_REQ_SET_REPORT):
|
||||
VDBG(cdev, "set_report | wLenght=%d\n", ctrl->wLength);
|
||||
req->context = hidg;
|
||||
req->complete = hidg_set_report_complete;
|
||||
goto respond;
|
||||
break;
|
||||
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
|
||||
| HID_REQ_SET_PROTOCOL):
|
||||
VDBG(cdev, "set_protocol\n");
|
||||
goto stall;
|
||||
break;
|
||||
|
||||
case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8
|
||||
| USB_REQ_GET_DESCRIPTOR):
|
||||
switch (value >> 8) {
|
||||
case HID_DT_REPORT:
|
||||
VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
|
||||
length = min_t(unsigned short, length,
|
||||
hidg->report_desc_length);
|
||||
memcpy(req->buf, hidg->report_desc, length);
|
||||
goto respond;
|
||||
break;
|
||||
|
||||
default:
|
||||
VDBG(cdev, "Unknown decriptor request 0x%x\n",
|
||||
value >> 8);
|
||||
goto stall;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
VDBG(cdev, "Unknown request 0x%x\n",
|
||||
ctrl->bRequest);
|
||||
goto stall;
|
||||
break;
|
||||
}
|
||||
|
||||
stall:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
respond:
|
||||
req->zero = 0;
|
||||
req->length = length;
|
||||
status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (status < 0)
|
||||
ERROR(cdev, "usb_ep_queue error on ep0 %d\n", value);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void hidg_disable(struct usb_function *f)
|
||||
{
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
hidg->in_ep->driver_data = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
{
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
const struct usb_endpoint_descriptor *ep_desc;
|
||||
int status = 0;
|
||||
|
||||
VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
|
||||
|
||||
if (hidg->in_ep != NULL) {
|
||||
/* restart endpoint */
|
||||
if (hidg->in_ep->driver_data != NULL)
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
|
||||
ep_desc = ep_choose(f->config->cdev->gadget,
|
||||
hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
|
||||
status = usb_ep_enable(hidg->in_ep, ep_desc);
|
||||
if (status < 0) {
|
||||
ERROR(cdev, "Enable endpoint FAILED!\n");
|
||||
goto fail;
|
||||
}
|
||||
hidg->in_ep->driver_data = hidg;
|
||||
}
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct file_operations f_hidg_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = f_hidg_open,
|
||||
.release = f_hidg_release,
|
||||
.write = f_hidg_write,
|
||||
.read = f_hidg_read,
|
||||
.poll = f_hidg_poll,
|
||||
};
|
||||
|
||||
static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
int status;
|
||||
dev_t dev;
|
||||
|
||||
/* allocate instance-specific interface IDs, and patch descriptors */
|
||||
status = usb_interface_id(c, f);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
hidg_interface_desc.bInterfaceNumber = status;
|
||||
|
||||
|
||||
/* allocate instance-specific endpoints */
|
||||
status = -ENODEV;
|
||||
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
ep->driver_data = c->cdev; /* claim */
|
||||
hidg->in_ep = ep;
|
||||
|
||||
/* preallocate request and buffer */
|
||||
status = -ENOMEM;
|
||||
hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
|
||||
if (!hidg->req)
|
||||
goto fail;
|
||||
|
||||
|
||||
hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
|
||||
if (!hidg->req->buf)
|
||||
goto fail;
|
||||
|
||||
/* set descriptor dynamic values */
|
||||
hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
|
||||
hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
|
||||
hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
|
||||
hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
|
||||
hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
|
||||
hidg_desc.desc[0].wDescriptorLength =
|
||||
cpu_to_le16(hidg->report_desc_length);
|
||||
|
||||
hidg->set_report_buff = NULL;
|
||||
|
||||
/* copy descriptors */
|
||||
f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
|
||||
f->descriptors,
|
||||
&hidg_fs_in_ep_desc);
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hidg_hs_in_ep_desc.bEndpointAddress =
|
||||
hidg_fs_in_ep_desc.bEndpointAddress;
|
||||
f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
|
||||
f->hs_descriptors,
|
||||
&hidg_hs_in_ep_desc);
|
||||
} else {
|
||||
hidg->hs_in_ep_desc = NULL;
|
||||
}
|
||||
|
||||
mutex_init(&hidg->lock);
|
||||
spin_lock_init(&hidg->spinlock);
|
||||
init_waitqueue_head(&hidg->write_queue);
|
||||
init_waitqueue_head(&hidg->read_queue);
|
||||
|
||||
/* create char device */
|
||||
cdev_init(&hidg->cdev, &f_hidg_fops);
|
||||
dev = MKDEV(major, hidg->minor);
|
||||
status = cdev_add(&hidg->cdev, dev, 1);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ERROR(f->config->cdev, "hidg_bind FAILED\n");
|
||||
if (hidg->req != NULL) {
|
||||
kfree(hidg->req->buf);
|
||||
if (hidg->in_ep != NULL)
|
||||
usb_ep_free_request(hidg->in_ep, hidg->req);
|
||||
}
|
||||
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
|
||||
device_destroy(hidg_class, MKDEV(major, hidg->minor));
|
||||
cdev_del(&hidg->cdev);
|
||||
|
||||
/* disable/free request and end point */
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
usb_ep_dequeue(hidg->in_ep, hidg->req);
|
||||
kfree(hidg->req->buf);
|
||||
usb_ep_free_request(hidg->in_ep, hidg->req);
|
||||
|
||||
/* free descriptors copies */
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
||||
kfree(hidg->report_desc);
|
||||
kfree(hidg->set_report_buff);
|
||||
kfree(hidg);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Strings */
|
||||
|
||||
#define CT_FUNC_HID_IDX 0
|
||||
|
||||
static struct usb_string ct_func_string_defs[] = {
|
||||
[CT_FUNC_HID_IDX].s = "HID Interface",
|
||||
{}, /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings ct_func_string_table = {
|
||||
.language = 0x0409, /* en-US */
|
||||
.strings = ct_func_string_defs,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *ct_func_strings[] = {
|
||||
&ct_func_string_table,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* usb_configuration */
|
||||
|
||||
int __init hidg_bind_config(struct usb_configuration *c,
|
||||
struct hidg_func_descriptor *fdesc, int index)
|
||||
{
|
||||
struct f_hidg *hidg;
|
||||
int status;
|
||||
|
||||
if (index >= minors)
|
||||
return -ENOENT;
|
||||
|
||||
/* maybe allocate device-global string IDs, and patch descriptors */
|
||||
if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) {
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ct_func_string_defs[CT_FUNC_HID_IDX].id = status;
|
||||
hidg_interface_desc.iInterface = status;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
hidg = kzalloc(sizeof *hidg, GFP_KERNEL);
|
||||
if (!hidg)
|
||||
return -ENOMEM;
|
||||
|
||||
hidg->minor = index;
|
||||
hidg->bInterfaceSubClass = fdesc->subclass;
|
||||
hidg->bInterfaceProtocol = fdesc->protocol;
|
||||
hidg->report_length = fdesc->report_length;
|
||||
hidg->report_desc_length = fdesc->report_desc_length;
|
||||
hidg->report_desc = kmemdup(fdesc->report_desc,
|
||||
fdesc->report_desc_length,
|
||||
GFP_KERNEL);
|
||||
if (!hidg->report_desc) {
|
||||
kfree(hidg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hidg->func.name = "hid";
|
||||
hidg->func.strings = ct_func_strings;
|
||||
hidg->func.bind = hidg_bind;
|
||||
hidg->func.unbind = hidg_unbind;
|
||||
hidg->func.set_alt = hidg_set_alt;
|
||||
hidg->func.disable = hidg_disable;
|
||||
hidg->func.setup = hidg_setup;
|
||||
|
||||
status = usb_add_function(c, &hidg->func);
|
||||
if (status)
|
||||
kfree(hidg);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int __init ghid_setup(struct usb_gadget *g, int count)
|
||||
{
|
||||
int status;
|
||||
dev_t dev;
|
||||
|
||||
hidg_class = class_create(THIS_MODULE, "hidg");
|
||||
|
||||
status = alloc_chrdev_region(&dev, 0, count, "hidg");
|
||||
if (!status) {
|
||||
major = MAJOR(dev);
|
||||
minors = count;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void ghid_cleanup(void)
|
||||
{
|
||||
if (major) {
|
||||
unregister_chrdev_region(MKDEV(major, 0), minors);
|
||||
major = minors = 0;
|
||||
}
|
||||
|
||||
class_destroy(hidg_class);
|
||||
hidg_class = NULL;
|
||||
}
|
@ -163,6 +163,10 @@
|
||||
* ro setting are not allowed when the medium is loaded or if CD-ROM
|
||||
* emulation is being used.
|
||||
*
|
||||
* When a LUN receive an "eject" SCSI request (Start/Stop Unit),
|
||||
* if the LUN is removable, the backing file is released to simulate
|
||||
* ejection.
|
||||
*
|
||||
*
|
||||
* This function is heavily based on "File-backed Storage Gadget" by
|
||||
* Alan Stern which in turn is heavily based on "Gadget Zero" by David
|
||||
@ -302,7 +306,6 @@ static const char fsg_string_interface[] = "Mass Storage";
|
||||
|
||||
|
||||
#define FSG_NO_INTR_EP 1
|
||||
#define FSG_BUFFHD_STATIC_BUFFER 1
|
||||
#define FSG_NO_DEVICE_STRINGS 1
|
||||
#define FSG_NO_OTG 1
|
||||
#define FSG_NO_INTR_EP 1
|
||||
@ -1385,12 +1388,50 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
|
||||
|
||||
static int do_start_stop(struct fsg_common *common)
|
||||
{
|
||||
if (!common->curlun) {
|
||||
struct fsg_lun *curlun = common->curlun;
|
||||
int loej, start;
|
||||
|
||||
if (!curlun) {
|
||||
return -EINVAL;
|
||||
} else if (!common->curlun->removable) {
|
||||
common->curlun->sense_data = SS_INVALID_COMMAND;
|
||||
} else if (!curlun->removable) {
|
||||
curlun->sense_data = SS_INVALID_COMMAND;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
loej = common->cmnd[4] & 0x02;
|
||||
start = common->cmnd[4] & 0x01;
|
||||
|
||||
/* eject code from file_storage.c:do_start_stop() */
|
||||
|
||||
if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
|
||||
(common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
|
||||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!start) {
|
||||
/* Are we allowed to unload the media? */
|
||||
if (curlun->prevent_medium_removal) {
|
||||
LDBG(curlun, "unload attempt prevented\n");
|
||||
curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (loej) { /* Simulate an unload/eject */
|
||||
up_read(&common->filesem);
|
||||
down_write(&common->filesem);
|
||||
fsg_lun_close(curlun);
|
||||
up_write(&common->filesem);
|
||||
down_read(&common->filesem);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Our emulation doesn't support mounting; the medium is
|
||||
* available for use as soon as it is loaded. */
|
||||
if (!fsg_lun_is_open(curlun)) {
|
||||
curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2701,10 +2742,8 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
||||
/* Maybe allocate device-global string IDs, and patch descriptors */
|
||||
if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
|
||||
rc = usb_string_id(cdev);
|
||||
if (rc < 0) {
|
||||
kfree(common);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
if (unlikely(rc < 0))
|
||||
goto error_release;
|
||||
fsg_strings[FSG_STRING_INTERFACE].id = rc;
|
||||
fsg_intf_desc.iInterface = rc;
|
||||
}
|
||||
@ -2712,9 +2751,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
||||
/* Create the LUNs, open their backing files, and register the
|
||||
* LUN devices in sysfs. */
|
||||
curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL);
|
||||
if (!curlun) {
|
||||
kfree(common);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (unlikely(!curlun)) {
|
||||
rc = -ENOMEM;
|
||||
goto error_release;
|
||||
}
|
||||
common->luns = curlun;
|
||||
|
||||
@ -2762,13 +2801,19 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
||||
|
||||
|
||||
/* Data buffers cyclic list */
|
||||
/* Buffers in buffhds are static -- no need for additional
|
||||
* allocation. */
|
||||
bh = common->buffhds;
|
||||
i = FSG_NUM_BUFFERS - 1;
|
||||
i = FSG_NUM_BUFFERS;
|
||||
goto buffhds_first_it;
|
||||
do {
|
||||
bh->next = bh + 1;
|
||||
} while (++bh, --i);
|
||||
++bh;
|
||||
buffhds_first_it:
|
||||
bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
|
||||
if (unlikely(!bh->buf)) {
|
||||
rc = -ENOMEM;
|
||||
goto error_release;
|
||||
}
|
||||
} while (--i);
|
||||
bh->next = common->buffhds;
|
||||
|
||||
|
||||
@ -2867,10 +2912,7 @@ error_release:
|
||||
|
||||
static void fsg_common_release(struct kref *ref)
|
||||
{
|
||||
struct fsg_common *common =
|
||||
container_of(ref, struct fsg_common, ref);
|
||||
unsigned i = common->nluns;
|
||||
struct fsg_lun *lun = common->luns;
|
||||
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
|
||||
|
||||
/* If the thread isn't already dead, tell it to exit now */
|
||||
if (common->state != FSG_STATE_TERMINATED) {
|
||||
@ -2881,17 +2923,29 @@ static void fsg_common_release(struct kref *ref)
|
||||
complete(&common->thread_notifier);
|
||||
}
|
||||
|
||||
/* Beware tempting for -> do-while optimization: when in error
|
||||
* recovery nluns may be zero. */
|
||||
if (likely(common->luns)) {
|
||||
struct fsg_lun *lun = common->luns;
|
||||
unsigned i = common->nluns;
|
||||
|
||||
for (; i; --i, ++lun) {
|
||||
device_remove_file(&lun->dev, &dev_attr_ro);
|
||||
device_remove_file(&lun->dev, &dev_attr_file);
|
||||
fsg_lun_close(lun);
|
||||
device_unregister(&lun->dev);
|
||||
/* In error recovery common->nluns may be zero. */
|
||||
for (; i; --i, ++lun) {
|
||||
device_remove_file(&lun->dev, &dev_attr_ro);
|
||||
device_remove_file(&lun->dev, &dev_attr_file);
|
||||
fsg_lun_close(lun);
|
||||
device_unregister(&lun->dev);
|
||||
}
|
||||
|
||||
kfree(common->luns);
|
||||
}
|
||||
|
||||
{
|
||||
struct fsg_buffhd *bh = common->buffhds;
|
||||
unsigned i = FSG_NUM_BUFFERS;
|
||||
do {
|
||||
kfree(bh->buf);
|
||||
} while (++bh, --i);
|
||||
}
|
||||
|
||||
kfree(common->luns);
|
||||
if (common->free_storage_on_release)
|
||||
kfree(common);
|
||||
}
|
||||
@ -2906,11 +2960,13 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
DBG(fsg, "unbind\n");
|
||||
fsg_common_put(fsg->common);
|
||||
usb_free_descriptors(fsg->function.descriptors);
|
||||
usb_free_descriptors(fsg->function.hs_descriptors);
|
||||
kfree(fsg);
|
||||
}
|
||||
|
||||
|
||||
static int __init fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct fsg_dev *fsg = fsg_from_func(f);
|
||||
struct usb_gadget *gadget = c->cdev->gadget;
|
||||
@ -2946,7 +3002,9 @@ static int __init fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
fsg_fs_bulk_in_desc.bEndpointAddress;
|
||||
fsg_hs_bulk_out_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_out_desc.bEndpointAddress;
|
||||
f->hs_descriptors = fsg_hs_function;
|
||||
f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
|
||||
if (unlikely(!f->hs_descriptors))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2978,7 +3036,11 @@ static int fsg_add(struct usb_composite_dev *cdev,
|
||||
|
||||
fsg->function.name = FSG_DRIVER_DESC;
|
||||
fsg->function.strings = fsg_strings_array;
|
||||
fsg->function.descriptors = fsg_fs_function;
|
||||
fsg->function.descriptors = usb_copy_descriptors(fsg_fs_function);
|
||||
if (unlikely(!fsg->function.descriptors)) {
|
||||
rc = -ENOMEM;
|
||||
goto error_free_fsg;
|
||||
}
|
||||
fsg->function.bind = fsg_bind;
|
||||
fsg->function.unbind = fsg_unbind;
|
||||
fsg->function.setup = fsg_setup;
|
||||
@ -2993,11 +3055,19 @@ static int fsg_add(struct usb_composite_dev *cdev,
|
||||
* call to usb_add_function() was successful. */
|
||||
|
||||
rc = usb_add_function(c, &fsg->function);
|
||||
if (unlikely(rc))
|
||||
goto error_free_all;
|
||||
|
||||
if (likely(rc == 0))
|
||||
fsg_common_get(fsg->common);
|
||||
else
|
||||
kfree(fsg);
|
||||
fsg_common_get(fsg->common);
|
||||
return 0;
|
||||
|
||||
error_free_all:
|
||||
usb_free_descriptors(fsg->function.descriptors);
|
||||
/* fsg_bind() might have copied those; or maybe not? who cares
|
||||
* -- free it just in case. */
|
||||
usb_free_descriptors(fsg->function.hs_descriptors);
|
||||
error_free_fsg:
|
||||
kfree(fsg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ static unsigned int bitrate(struct usb_gadget *g)
|
||||
|
||||
/* interface descriptor: */
|
||||
|
||||
static struct usb_interface_descriptor rndis_control_intf __initdata = {
|
||||
static struct usb_interface_descriptor rndis_control_intf = {
|
||||
.bLength = sizeof rndis_control_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -135,7 +135,7 @@ static struct usb_interface_descriptor rndis_control_intf __initdata = {
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_header_desc header_desc __initdata = {
|
||||
static struct usb_cdc_header_desc header_desc = {
|
||||
.bLength = sizeof header_desc,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
@ -143,7 +143,7 @@ static struct usb_cdc_header_desc header_desc __initdata = {
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
|
||||
static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
|
||||
.bLength = sizeof call_mgmt_descriptor,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
|
||||
@ -152,7 +152,7 @@ static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
|
||||
.bDataInterface = 0x01,
|
||||
};
|
||||
|
||||
static struct usb_cdc_acm_descriptor rndis_acm_descriptor __initdata = {
|
||||
static struct usb_cdc_acm_descriptor rndis_acm_descriptor = {
|
||||
.bLength = sizeof rndis_acm_descriptor,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||
@ -160,7 +160,7 @@ static struct usb_cdc_acm_descriptor rndis_acm_descriptor __initdata = {
|
||||
.bmCapabilities = 0x00,
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc rndis_union_desc __initdata = {
|
||||
static struct usb_cdc_union_desc rndis_union_desc = {
|
||||
.bLength = sizeof(rndis_union_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||
@ -170,7 +170,7 @@ static struct usb_cdc_union_desc rndis_union_desc __initdata = {
|
||||
|
||||
/* the data interface has two bulk endpoints */
|
||||
|
||||
static struct usb_interface_descriptor rndis_data_intf __initdata = {
|
||||
static struct usb_interface_descriptor rndis_data_intf = {
|
||||
.bLength = sizeof rndis_data_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -198,7 +198,7 @@ rndis_iad_descriptor = {
|
||||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor fs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -208,7 +208,7 @@ static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor fs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -216,7 +216,7 @@ static struct usb_endpoint_descriptor fs_in_desc __initdata = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor fs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -224,7 +224,7 @@ static struct usb_endpoint_descriptor fs_out_desc __initdata = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *eth_fs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *eth_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &rndis_iad_descriptor,
|
||||
/* control interface matches ACM, not Ethernet */
|
||||
(struct usb_descriptor_header *) &rndis_control_intf,
|
||||
@ -242,7 +242,7 @@ static struct usb_descriptor_header *eth_fs_function[] __initdata = {
|
||||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor hs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -251,7 +251,7 @@ static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
};
|
||||
static struct usb_endpoint_descriptor hs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor hs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -260,7 +260,7 @@ static struct usb_endpoint_descriptor hs_in_desc __initdata = {
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor hs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -269,7 +269,7 @@ static struct usb_endpoint_descriptor hs_out_desc __initdata = {
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *eth_hs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *eth_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &rndis_iad_descriptor,
|
||||
/* control interface matches ACM, not Ethernet */
|
||||
(struct usb_descriptor_header *) &rndis_control_intf,
|
||||
@ -594,7 +594,7 @@ static void rndis_close(struct gether *geth)
|
||||
|
||||
/* ethernet function driver setup/binding */
|
||||
|
||||
static int __init
|
||||
static int
|
||||
rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
@ -786,7 +786,8 @@ static inline bool can_support_rndis(struct usb_configuration *c)
|
||||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
int
|
||||
rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
{
|
||||
struct f_rndis *rndis;
|
||||
int status;
|
||||
|
661
drivers/usb/gadget/f_uvc.c
Normal file
661
drivers/usb/gadget/f_uvc.c
Normal file
@ -0,0 +1,661 @@
|
||||
/*
|
||||
* uvc_gadget.c -- USB Video Class Gadget driver
|
||||
*
|
||||
* Copyright (C) 2009-2010
|
||||
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/video.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-event.h>
|
||||
|
||||
#include "uvc.h"
|
||||
|
||||
unsigned int uvc_trace_param;
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Function descriptors
|
||||
*/
|
||||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
#define UVC_STRING_ASSOCIATION_IDX 0
|
||||
#define UVC_STRING_CONTROL_IDX 1
|
||||
#define UVC_STRING_STREAMING_IDX 2
|
||||
|
||||
static struct usb_string uvc_en_us_strings[] = {
|
||||
[UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera",
|
||||
[UVC_STRING_CONTROL_IDX].s = "Video Control",
|
||||
[UVC_STRING_STREAMING_IDX].s = "Video Streaming",
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings uvc_stringtab = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = uvc_en_us_strings,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *uvc_function_strings[] = {
|
||||
&uvc_stringtab,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#define UVC_INTF_VIDEO_CONTROL 0
|
||||
#define UVC_INTF_VIDEO_STREAMING 1
|
||||
|
||||
static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
|
||||
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||
.bFirstInterface = 0,
|
||||
.bInterfaceCount = 2,
|
||||
.bFunctionClass = USB_CLASS_VIDEO,
|
||||
.bFunctionSubClass = 0x03,
|
||||
.bFunctionProtocol = 0x00,
|
||||
.iFunction = 0,
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor uvc_control_intf __initdata = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = UVC_INTF_VIDEO_CONTROL,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_VIDEO,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(16),
|
||||
.bInterval = 8,
|
||||
};
|
||||
|
||||
static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
|
||||
.bLength = UVC_DT_CONTROL_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_ENDPOINT,
|
||||
.bDescriptorSubType = UVC_EP_INTERRUPT,
|
||||
.wMaxTransferSize = cpu_to_le16(16),
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = UVC_INTF_VIDEO_STREAMING,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 0,
|
||||
.bInterfaceClass = USB_CLASS_VIDEO,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0,
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = UVC_INTF_VIDEO_STREAMING,
|
||||
.bAlternateSetting = 1,
|
||||
.bNumEndpoints = 1,
|
||||
.bInterfaceClass = USB_CLASS_VIDEO,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_streaming_ep = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
|
||||
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
|
||||
(struct usb_descriptor_header *) &uvc_streaming_ep,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
|
||||
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
|
||||
(struct usb_descriptor_header *) &uvc_streaming_ep,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Control requests
|
||||
*/
|
||||
|
||||
static void
|
||||
uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct uvc_device *uvc = req->context;
|
||||
struct v4l2_event v4l2_event;
|
||||
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
|
||||
|
||||
if (uvc->event_setup_out) {
|
||||
uvc->event_setup_out = 0;
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_DATA;
|
||||
uvc_event->data.length = req->actual;
|
||||
memcpy(&uvc_event->data.data, req->buf, req->actual);
|
||||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
struct v4l2_event v4l2_event;
|
||||
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
|
||||
|
||||
/* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n",
|
||||
* ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue),
|
||||
* le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength));
|
||||
*/
|
||||
|
||||
if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
|
||||
INFO(f->config->cdev, "invalid request type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Stall too big requests. */
|
||||
if (le16_to_cpu(ctrl->wLength) > UVC_MAX_REQUEST_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_SETUP;
|
||||
memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
|
||||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_function_get_alt(struct usb_function *f, unsigned interface)
|
||||
{
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
|
||||
INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface);
|
||||
|
||||
if (interface == uvc->control_intf)
|
||||
return 0;
|
||||
else if (interface != uvc->streaming_intf)
|
||||
return -EINVAL;
|
||||
else
|
||||
return uvc->state == UVC_STATE_STREAMING ? 1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
||||
{
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
struct v4l2_event v4l2_event;
|
||||
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
|
||||
|
||||
INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
|
||||
|
||||
if (interface == uvc->control_intf) {
|
||||
if (alt)
|
||||
return -EINVAL;
|
||||
|
||||
if (uvc->state == UVC_STATE_DISCONNECTED) {
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_CONNECT;
|
||||
uvc_event->speed = f->config->cdev->gadget->speed;
|
||||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
|
||||
uvc->state = UVC_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (interface != uvc->streaming_intf)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO
|
||||
if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
|
||||
return alt ? -EINVAL : 0;
|
||||
*/
|
||||
|
||||
switch (alt) {
|
||||
case 0:
|
||||
if (uvc->state != UVC_STATE_STREAMING)
|
||||
return 0;
|
||||
|
||||
if (uvc->video.ep)
|
||||
usb_ep_disable(uvc->video.ep);
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_STREAMOFF;
|
||||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
|
||||
uvc->state = UVC_STATE_CONNECTED;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (uvc->state != UVC_STATE_CONNECTED)
|
||||
return 0;
|
||||
|
||||
if (uvc->video.ep)
|
||||
usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_STREAMON;
|
||||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
|
||||
uvc->state = UVC_STATE_STREAMING;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
uvc_function_disable(struct usb_function *f)
|
||||
{
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
struct v4l2_event v4l2_event;
|
||||
|
||||
INFO(f->config->cdev, "uvc_function_disable\n");
|
||||
|
||||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_DISCONNECT;
|
||||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
|
||||
uvc->state = UVC_STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Connection / disconnection
|
||||
*/
|
||||
|
||||
void
|
||||
uvc_function_connect(struct uvc_device *uvc)
|
||||
{
|
||||
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_function_activate(&uvc->func)) < 0)
|
||||
INFO(cdev, "UVC connect failed with %d\n", ret);
|
||||
}
|
||||
|
||||
void
|
||||
uvc_function_disconnect(struct uvc_device *uvc)
|
||||
{
|
||||
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_function_deactivate(&uvc->func)) < 0)
|
||||
INFO(cdev, "UVC disconnect failed with %d\n", ret);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* USB probe and disconnect
|
||||
*/
|
||||
|
||||
static int
|
||||
uvc_register_video(struct uvc_device *uvc)
|
||||
{
|
||||
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
||||
struct video_device *video;
|
||||
|
||||
/* TODO reference counting. */
|
||||
video = video_device_alloc();
|
||||
if (video == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
video->parent = &cdev->gadget->dev;
|
||||
video->minor = -1;
|
||||
video->fops = &uvc_v4l2_fops;
|
||||
video->release = video_device_release;
|
||||
strncpy(video->name, cdev->gadget->name, sizeof(video->name));
|
||||
|
||||
uvc->vdev = video;
|
||||
video_set_drvdata(video, uvc);
|
||||
|
||||
return video_register_device(video, VFL_TYPE_GRABBER, -1);
|
||||
}
|
||||
|
||||
#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
|
||||
do { \
|
||||
memcpy(mem, desc, (desc)->bLength); \
|
||||
*(dst)++ = mem; \
|
||||
mem += (desc)->bLength; \
|
||||
} while (0);
|
||||
|
||||
#define UVC_COPY_DESCRIPTORS(mem, dst, src) \
|
||||
do { \
|
||||
const struct usb_descriptor_header * const *__src; \
|
||||
for (__src = src; *__src; ++__src) { \
|
||||
memcpy(mem, *__src, (*__src)->bLength); \
|
||||
*dst++ = mem; \
|
||||
mem += (*__src)->bLength; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static struct usb_descriptor_header ** __init
|
||||
uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
||||
{
|
||||
struct uvc_input_header_descriptor *uvc_streaming_header;
|
||||
struct uvc_header_descriptor *uvc_control_header;
|
||||
const struct uvc_descriptor_header * const *uvc_streaming_cls;
|
||||
const struct usb_descriptor_header * const *uvc_streaming_std;
|
||||
const struct usb_descriptor_header * const *src;
|
||||
struct usb_descriptor_header **dst;
|
||||
struct usb_descriptor_header **hdr;
|
||||
unsigned int control_size;
|
||||
unsigned int streaming_size;
|
||||
unsigned int n_desc;
|
||||
unsigned int bytes;
|
||||
void *mem;
|
||||
|
||||
uvc_streaming_cls = (speed == USB_SPEED_FULL)
|
||||
? uvc->desc.fs_streaming : uvc->desc.hs_streaming;
|
||||
uvc_streaming_std = (speed == USB_SPEED_FULL)
|
||||
? uvc_fs_streaming : uvc_hs_streaming;
|
||||
|
||||
/* Descriptors layout
|
||||
*
|
||||
* uvc_iad
|
||||
* uvc_control_intf
|
||||
* Class-specific UVC control descriptors
|
||||
* uvc_control_ep
|
||||
* uvc_control_cs_ep
|
||||
* uvc_streaming_intf_alt0
|
||||
* Class-specific UVC streaming descriptors
|
||||
* uvc_{fs|hs}_streaming
|
||||
*/
|
||||
|
||||
/* Count descriptors and compute their size. */
|
||||
control_size = 0;
|
||||
streaming_size = 0;
|
||||
bytes = uvc_iad.bLength + uvc_control_intf.bLength
|
||||
+ uvc_control_ep.bLength + uvc_control_cs_ep.bLength
|
||||
+ uvc_streaming_intf_alt0.bLength;
|
||||
n_desc = 5;
|
||||
|
||||
for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) {
|
||||
control_size += (*src)->bLength;
|
||||
bytes += (*src)->bLength;
|
||||
n_desc++;
|
||||
}
|
||||
for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) {
|
||||
streaming_size += (*src)->bLength;
|
||||
bytes += (*src)->bLength;
|
||||
n_desc++;
|
||||
}
|
||||
for (src = uvc_streaming_std; *src; ++src) {
|
||||
bytes += (*src)->bLength;
|
||||
n_desc++;
|
||||
}
|
||||
|
||||
mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL);
|
||||
if (mem == NULL)
|
||||
return NULL;
|
||||
|
||||
hdr = mem;
|
||||
dst = mem;
|
||||
mem += (n_desc + 1) * sizeof(*src);
|
||||
|
||||
/* Copy the descriptors. */
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad);
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf);
|
||||
|
||||
uvc_control_header = mem;
|
||||
UVC_COPY_DESCRIPTORS(mem, dst,
|
||||
(const struct usb_descriptor_header**)uvc->desc.control);
|
||||
uvc_control_header->wTotalLength = cpu_to_le16(control_size);
|
||||
uvc_control_header->bInCollection = 1;
|
||||
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
|
||||
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
|
||||
|
||||
uvc_streaming_header = mem;
|
||||
UVC_COPY_DESCRIPTORS(mem, dst,
|
||||
(const struct usb_descriptor_header**)uvc_streaming_cls);
|
||||
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
|
||||
uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress;
|
||||
|
||||
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
|
||||
|
||||
*dst = NULL;
|
||||
return hdr;
|
||||
}
|
||||
|
||||
static void
|
||||
uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
|
||||
INFO(cdev, "uvc_function_unbind\n");
|
||||
|
||||
if (uvc->vdev) {
|
||||
if (uvc->vdev->minor == -1)
|
||||
video_device_release(uvc->vdev);
|
||||
else
|
||||
video_unregister_device(uvc->vdev);
|
||||
uvc->vdev = NULL;
|
||||
}
|
||||
|
||||
if (uvc->control_ep)
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
if (uvc->video.ep)
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
|
||||
if (uvc->control_req) {
|
||||
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
|
||||
kfree(uvc->control_buf);
|
||||
}
|
||||
|
||||
kfree(f->descriptors);
|
||||
kfree(f->hs_descriptors);
|
||||
|
||||
kfree(uvc);
|
||||
}
|
||||
|
||||
static int __init
|
||||
uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
struct usb_ep *ep;
|
||||
int ret = -EINVAL;
|
||||
|
||||
INFO(cdev, "uvc_function_bind\n");
|
||||
|
||||
/* Allocate endpoints. */
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
|
||||
if (!ep) {
|
||||
INFO(cdev, "Unable to allocate control EP\n");
|
||||
goto error;
|
||||
}
|
||||
uvc->control_ep = ep;
|
||||
ep->driver_data = uvc;
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep);
|
||||
if (!ep) {
|
||||
INFO(cdev, "Unable to allocate streaming EP\n");
|
||||
goto error;
|
||||
}
|
||||
uvc->video.ep = ep;
|
||||
ep->driver_data = uvc;
|
||||
|
||||
/* Allocate interface IDs. */
|
||||
if ((ret = usb_interface_id(c, f)) < 0)
|
||||
goto error;
|
||||
uvc_iad.bFirstInterface = ret;
|
||||
uvc_control_intf.bInterfaceNumber = ret;
|
||||
uvc->control_intf = ret;
|
||||
|
||||
if ((ret = usb_interface_id(c, f)) < 0)
|
||||
goto error;
|
||||
uvc_streaming_intf_alt0.bInterfaceNumber = ret;
|
||||
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
|
||||
uvc->streaming_intf = ret;
|
||||
|
||||
/* Copy descriptors. */
|
||||
f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
|
||||
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
|
||||
|
||||
/* Preallocate control endpoint request. */
|
||||
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
|
||||
uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
|
||||
if (uvc->control_req == NULL || uvc->control_buf == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
uvc->control_req->buf = uvc->control_buf;
|
||||
uvc->control_req->complete = uvc_function_ep0_complete;
|
||||
uvc->control_req->context = uvc;
|
||||
|
||||
/* Avoid letting this gadget enumerate until the userspace server is
|
||||
* active.
|
||||
*/
|
||||
if ((ret = usb_function_deactivate(f)) < 0)
|
||||
goto error;
|
||||
|
||||
/* Initialise video. */
|
||||
ret = uvc_video_init(&uvc->video);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
/* Register a V4L2 device. */
|
||||
ret = uvc_register_video(uvc);
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "Unable to register video device\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uvc_function_unbind(c, f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* USB gadget function
|
||||
*/
|
||||
|
||||
/**
|
||||
* uvc_bind_config - add a UVC function to a configuration
|
||||
* @c: the configuration to support the UVC instance
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller must have called @uvc_setup(). Caller is also responsible for
|
||||
* calling @uvc_cleanup() before module unload.
|
||||
*/
|
||||
int __init
|
||||
uvc_bind_config(struct usb_configuration *c,
|
||||
const struct uvc_descriptor_header * const *control,
|
||||
const struct uvc_descriptor_header * const *fs_streaming,
|
||||
const struct uvc_descriptor_header * const *hs_streaming)
|
||||
{
|
||||
struct uvc_device *uvc;
|
||||
int ret = 0;
|
||||
|
||||
/* TODO Check if the USB device controller supports the required
|
||||
* features.
|
||||
*/
|
||||
if (!gadget_is_dualspeed(c->cdev->gadget))
|
||||
return -EINVAL;
|
||||
|
||||
uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
|
||||
if (uvc == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
uvc->state = UVC_STATE_DISCONNECTED;
|
||||
|
||||
/* Validate the descriptors. */
|
||||
if (control == NULL || control[0] == NULL ||
|
||||
control[0]->bDescriptorSubType != UVC_DT_HEADER)
|
||||
goto error;
|
||||
|
||||
if (fs_streaming == NULL || fs_streaming[0] == NULL ||
|
||||
fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
if (hs_streaming == NULL || hs_streaming[0] == NULL ||
|
||||
hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
uvc->desc.control = control;
|
||||
uvc->desc.fs_streaming = fs_streaming;
|
||||
uvc->desc.hs_streaming = hs_streaming;
|
||||
|
||||
/* Allocate string descriptor numbers. */
|
||||
if ((ret = usb_string_id(c->cdev)) < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret;
|
||||
uvc_iad.iFunction = ret;
|
||||
|
||||
if ((ret = usb_string_id(c->cdev)) < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret;
|
||||
uvc_control_intf.iInterface = ret;
|
||||
|
||||
if ((ret = usb_string_id(c->cdev)) < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret;
|
||||
uvc_streaming_intf_alt0.iInterface = ret;
|
||||
uvc_streaming_intf_alt1.iInterface = ret;
|
||||
|
||||
/* Register the function. */
|
||||
uvc->func.name = "uvc";
|
||||
uvc->func.strings = uvc_function_strings;
|
||||
uvc->func.bind = uvc_function_bind;
|
||||
uvc->func.unbind = uvc_function_unbind;
|
||||
uvc->func.get_alt = uvc_function_get_alt;
|
||||
uvc->func.set_alt = uvc_function_set_alt;
|
||||
uvc->func.disable = uvc_function_disable;
|
||||
uvc->func.setup = uvc_function_setup;
|
||||
|
||||
ret = usb_add_function(c, &uvc->func);
|
||||
if (ret)
|
||||
kfree(uvc);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(uvc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(trace, "Trace level bitmask");
|
||||
|
376
drivers/usb/gadget/f_uvc.h
Normal file
376
drivers/usb/gadget/f_uvc.h
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
* f_uvc.h -- USB Video Class Gadget driver
|
||||
*
|
||||
* Copyright (C) 2009-2010
|
||||
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _F_UVC_H_
|
||||
#define _F_UVC_H_
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
#define USB_CLASS_VIDEO_CONTROL 1
|
||||
#define USB_CLASS_VIDEO_STREAMING 2
|
||||
|
||||
struct uvc_descriptor_header {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct uvc_header_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u16 bcdUVC;
|
||||
__u16 wTotalLength;
|
||||
__u32 dwClockFrequency;
|
||||
__u8 bInCollection;
|
||||
__u8 baInterfaceNr[];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_HEADER_DESCRIPTOR(n) uvc_header_descriptor_##n
|
||||
|
||||
#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \
|
||||
struct UVC_HEADER_DESCRIPTOR(n) { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubType; \
|
||||
__u16 bcdUVC; \
|
||||
__u16 wTotalLength; \
|
||||
__u32 dwClockFrequency; \
|
||||
__u8 bInCollection; \
|
||||
__u8 baInterfaceNr[n]; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
struct uvc_input_terminal_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bTerminalID;
|
||||
__u16 wTerminalType;
|
||||
__u8 bAssocTerminal;
|
||||
__u8 iTerminal;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uvc_output_terminal_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bTerminalID;
|
||||
__u16 wTerminalType;
|
||||
__u8 bAssocTerminal;
|
||||
__u8 bSourceID;
|
||||
__u8 iTerminal;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uvc_camera_terminal_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bTerminalID;
|
||||
__u16 wTerminalType;
|
||||
__u8 bAssocTerminal;
|
||||
__u8 iTerminal;
|
||||
__u16 wObjectiveFocalLengthMin;
|
||||
__u16 wObjectiveFocalLengthMax;
|
||||
__u16 wOcularFocalLength;
|
||||
__u8 bControlSize;
|
||||
__u8 bmControls[3];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uvc_selector_unit_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bUnitID;
|
||||
__u8 bNrInPins;
|
||||
__u8 baSourceID[0];
|
||||
__u8 iSelector;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
|
||||
uvc_selector_unit_descriptor_##n
|
||||
|
||||
#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
|
||||
struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubType; \
|
||||
__u8 bUnitID; \
|
||||
__u8 bNrInPins; \
|
||||
__u8 baSourceID[n]; \
|
||||
__u8 iSelector; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
struct uvc_processing_unit_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bUnitID;
|
||||
__u8 bSourceID;
|
||||
__u16 wMaxMultiplier;
|
||||
__u8 bControlSize;
|
||||
__u8 bmControls[2];
|
||||
__u8 iProcessing;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uvc_extension_unit_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bUnitID;
|
||||
__u8 guidExtensionCode[16];
|
||||
__u8 bNumControls;
|
||||
__u8 bNrInPins;
|
||||
__u8 baSourceID[0];
|
||||
__u8 bControlSize;
|
||||
__u8 bmControls[0];
|
||||
__u8 iExtension;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
|
||||
uvc_extension_unit_descriptor_##p_##n
|
||||
|
||||
#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
|
||||
struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubType; \
|
||||
__u8 bUnitID; \
|
||||
__u8 guidExtensionCode[16]; \
|
||||
__u8 bNumControls; \
|
||||
__u8 bNrInPins; \
|
||||
__u8 baSourceID[p]; \
|
||||
__u8 bControlSize; \
|
||||
__u8 bmControls[n]; \
|
||||
__u8 iExtension; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
struct uvc_control_endpoint_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u16 wMaxTransferSize;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_DT_HEADER 1
|
||||
#define UVC_DT_INPUT_TERMINAL 2
|
||||
#define UVC_DT_OUTPUT_TERMINAL 3
|
||||
#define UVC_DT_SELECTOR_UNIT 4
|
||||
#define UVC_DT_PROCESSING_UNIT 5
|
||||
#define UVC_DT_EXTENSION_UNIT 6
|
||||
|
||||
#define UVC_DT_HEADER_SIZE(n) (12+(n))
|
||||
#define UVC_DT_INPUT_TERMINAL_SIZE 8
|
||||
#define UVC_DT_OUTPUT_TERMINAL_SIZE 9
|
||||
#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n))
|
||||
#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n))
|
||||
#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n))
|
||||
#define UVC_DT_EXTENSION_UNIT_SIZE(p,n) (24+(p)+(n))
|
||||
#define UVC_DT_CONTROL_ENDPOINT_SIZE 5
|
||||
|
||||
struct uvc_input_header_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bNumFormats;
|
||||
__u16 wTotalLength;
|
||||
__u8 bEndpointAddress;
|
||||
__u8 bmInfo;
|
||||
__u8 bTerminalLink;
|
||||
__u8 bStillCaptureMethod;
|
||||
__u8 bTriggerSupport;
|
||||
__u8 bTriggerUsage;
|
||||
__u8 bControlSize;
|
||||
__u8 bmaControls[];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
|
||||
uvc_input_header_descriptor_##n_##p
|
||||
|
||||
#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
|
||||
struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubType; \
|
||||
__u8 bNumFormats; \
|
||||
__u16 wTotalLength; \
|
||||
__u8 bEndpointAddress; \
|
||||
__u8 bmInfo; \
|
||||
__u8 bTerminalLink; \
|
||||
__u8 bStillCaptureMethod; \
|
||||
__u8 bTriggerSupport; \
|
||||
__u8 bTriggerUsage; \
|
||||
__u8 bControlSize; \
|
||||
__u8 bmaControls[p][n]; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
struct uvc_output_header_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bNumFormats;
|
||||
__u16 wTotalLength;
|
||||
__u8 bEndpointAddress;
|
||||
__u8 bTerminalLink;
|
||||
__u8 bControlSize;
|
||||
__u8 bmaControls[];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
|
||||
uvc_output_header_descriptor_##n_##p
|
||||
|
||||
#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
|
||||
struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubType; \
|
||||
__u8 bNumFormats; \
|
||||
__u16 wTotalLength; \
|
||||
__u8 bEndpointAddress; \
|
||||
__u8 bTerminalLink; \
|
||||
__u8 bControlSize; \
|
||||
__u8 bmaControls[p][n]; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
struct uvc_format_uncompressed {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bFormatIndex;
|
||||
__u8 bNumFrameDescriptors;
|
||||
__u8 guidFormat[16];
|
||||
__u8 bBitsPerPixel;
|
||||
__u8 bDefaultFrameIndex;
|
||||
__u8 bAspectRatioX;
|
||||
__u8 bAspectRatioY;
|
||||
__u8 bmInterfaceFlags;
|
||||
__u8 bCopyProtect;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uvc_frame_uncompressed {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bFrameIndex;
|
||||
__u8 bmCapabilities;
|
||||
__u16 wWidth;
|
||||
__u16 wHeight;
|
||||
__u32 dwMinBitRate;
|
||||
__u32 dwMaxBitRate;
|
||||
__u32 dwMaxVideoFrameBufferSize;
|
||||
__u32 dwDefaultFrameInterval;
|
||||
__u8 bFrameIntervalType;
|
||||
__u32 dwFrameInterval[];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_FRAME_UNCOMPRESSED(n) \
|
||||
uvc_frame_uncompressed_##n
|
||||
|
||||
#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \
|
||||
struct UVC_FRAME_UNCOMPRESSED(n) { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubType; \
|
||||
__u8 bFrameIndex; \
|
||||
__u8 bmCapabilities; \
|
||||
__u16 wWidth; \
|
||||
__u16 wHeight; \
|
||||
__u32 dwMinBitRate; \
|
||||
__u32 dwMaxBitRate; \
|
||||
__u32 dwMaxVideoFrameBufferSize; \
|
||||
__u32 dwDefaultFrameInterval; \
|
||||
__u8 bFrameIntervalType; \
|
||||
__u32 dwFrameInterval[n]; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
struct uvc_format_mjpeg {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bFormatIndex;
|
||||
__u8 bNumFrameDescriptors;
|
||||
__u8 bmFlags;
|
||||
__u8 bDefaultFrameIndex;
|
||||
__u8 bAspectRatioX;
|
||||
__u8 bAspectRatioY;
|
||||
__u8 bmInterfaceFlags;
|
||||
__u8 bCopyProtect;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uvc_frame_mjpeg {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bFrameIndex;
|
||||
__u8 bmCapabilities;
|
||||
__u16 wWidth;
|
||||
__u16 wHeight;
|
||||
__u32 dwMinBitRate;
|
||||
__u32 dwMaxBitRate;
|
||||
__u32 dwMaxVideoFrameBufferSize;
|
||||
__u32 dwDefaultFrameInterval;
|
||||
__u8 bFrameIntervalType;
|
||||
__u32 dwFrameInterval[];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_FRAME_MJPEG(n) \
|
||||
uvc_frame_mjpeg_##n
|
||||
|
||||
#define DECLARE_UVC_FRAME_MJPEG(n) \
|
||||
struct UVC_FRAME_MJPEG(n) { \
|
||||
__u8 bLength; \
|
||||
__u8 bDescriptorType; \
|
||||
__u8 bDescriptorSubType; \
|
||||
__u8 bFrameIndex; \
|
||||
__u8 bmCapabilities; \
|
||||
__u16 wWidth; \
|
||||
__u16 wHeight; \
|
||||
__u32 dwMinBitRate; \
|
||||
__u32 dwMaxBitRate; \
|
||||
__u32 dwMaxVideoFrameBufferSize; \
|
||||
__u32 dwDefaultFrameInterval; \
|
||||
__u8 bFrameIntervalType; \
|
||||
__u32 dwFrameInterval[n]; \
|
||||
} __attribute__ ((packed))
|
||||
|
||||
struct uvc_color_matching_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
__u8 bColorPrimaries;
|
||||
__u8 bTransferCharacteristics;
|
||||
__u8 bMatrixCoefficients;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UVC_DT_INPUT_HEADER 1
|
||||
#define UVC_DT_OUTPUT_HEADER 2
|
||||
#define UVC_DT_FORMAT_UNCOMPRESSED 4
|
||||
#define UVC_DT_FRAME_UNCOMPRESSED 5
|
||||
#define UVC_DT_FORMAT_MJPEG 6
|
||||
#define UVC_DT_FRAME_MJPEG 7
|
||||
#define UVC_DT_COLOR_MATCHING 13
|
||||
|
||||
#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p))
|
||||
#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p))
|
||||
#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27
|
||||
#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n))
|
||||
#define UVC_DT_FORMAT_MJPEG_SIZE 11
|
||||
#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n))
|
||||
#define UVC_DT_COLOR_MATCHING_SIZE 6
|
||||
|
||||
extern int uvc_bind_config(struct usb_configuration *c,
|
||||
const struct uvc_descriptor_header * const *control,
|
||||
const struct uvc_descriptor_header * const *fs_streaming,
|
||||
const struct uvc_descriptor_header * const *hs_streaming);
|
||||
|
||||
#endif /* _F_UVC_H_ */
|
||||
|
@ -50,12 +50,14 @@ int fsl_udc_clk_init(struct platform_device *pdev)
|
||||
goto egusb;
|
||||
}
|
||||
|
||||
freq = clk_get_rate(mxc_usb_clk);
|
||||
if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
|
||||
(freq < 59999000 || freq > 60001000)) {
|
||||
dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
|
||||
ret = -EINVAL;
|
||||
goto eclkrate;
|
||||
if (!cpu_is_mx51()) {
|
||||
freq = clk_get_rate(mxc_usb_clk);
|
||||
if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
|
||||
(freq < 59999000 || freq > 60001000)) {
|
||||
dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
|
||||
ret = -EINVAL;
|
||||
goto eclkrate;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_enable(mxc_usb_clk);
|
@ -489,7 +489,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
/* Calculate transactions needed for high bandwidth iso */
|
||||
mult = (unsigned char)(1 + ((max >> 11) & 0x03));
|
||||
max = max & 0x8ff; /* bit 0~10 */
|
||||
max = max & 0x7ff; /* bit 0~10 */
|
||||
/* 3 transactions at most */
|
||||
if (mult > 3)
|
||||
goto en_done;
|
||||
|
426
drivers/usb/gadget/g_ffs.c
Normal file
426
drivers/usb/gadget/g_ffs.c
Normal file
@ -0,0 +1,426 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/utsname.h>
|
||||
|
||||
|
||||
/*
|
||||
* kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
* separate compilation ... ensuring init/exit sections work to shrink
|
||||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
|
||||
#include "composite.c"
|
||||
#include "usbstring.c"
|
||||
#include "config.c"
|
||||
#include "epautoconf.c"
|
||||
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
# if defined USB_ETH_RNDIS
|
||||
# undef USB_ETH_RNDIS
|
||||
# endif
|
||||
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
# define USB_ETH_RNDIS y
|
||||
# endif
|
||||
|
||||
# include "f_ecm.c"
|
||||
# include "f_subset.c"
|
||||
# ifdef USB_ETH_RNDIS
|
||||
# include "f_rndis.c"
|
||||
# include "rndis.c"
|
||||
# endif
|
||||
# include "u_ether.c"
|
||||
|
||||
static u8 gfs_hostaddr[ETH_ALEN];
|
||||
#else
|
||||
# if !defined CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
# define CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
# endif
|
||||
# define gether_cleanup() do { } while (0)
|
||||
# define gether_setup(gadget, hostaddr) ((int)0)
|
||||
#endif
|
||||
|
||||
#include "f_fs.c"
|
||||
|
||||
|
||||
#define DRIVER_NAME "g_ffs"
|
||||
#define DRIVER_DESC "USB Function Filesystem"
|
||||
#define DRIVER_VERSION "24 Aug 2004"
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("Michal Nazarewicz");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static unsigned short gfs_vendor_id = 0x0525; /* XXX NetChip */
|
||||
static unsigned short gfs_product_id = 0xa4ac; /* XXX */
|
||||
|
||||
static struct usb_device_descriptor gfs_dev_desc = {
|
||||
.bLength = sizeof gfs_dev_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PER_INTERFACE,
|
||||
|
||||
/* Vendor and product id can be overridden by module parameters. */
|
||||
/* .idVendor = cpu_to_le16(gfs_vendor_id), */
|
||||
/* .idProduct = cpu_to_le16(gfs_product_id), */
|
||||
/* .bcdDevice = f(hardware) */
|
||||
/* .iManufacturer = DYNAMIC */
|
||||
/* .iProduct = DYNAMIC */
|
||||
/* NO SERIAL NUMBER */
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
#define GFS_MODULE_PARAM_DESC(name, field) \
|
||||
MODULE_PARM_DESC(name, "Value of the " #field " field of the device descriptor sent to the host. Takes effect only prior to the user-space driver registering to the FunctionFS.")
|
||||
|
||||
module_param_named(usb_class, gfs_dev_desc.bDeviceClass, byte, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_class, bDeviceClass);
|
||||
module_param_named(usb_subclass, gfs_dev_desc.bDeviceSubClass, byte, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_subclass, bDeviceSubClass);
|
||||
module_param_named(usb_protocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_protocol, bDeviceProtocol);
|
||||
module_param_named(usb_vendor, gfs_vendor_id, ushort, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_vendor, idVendor);
|
||||
module_param_named(usb_product, gfs_product_id, ushort, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_product, idProduct);
|
||||
|
||||
|
||||
|
||||
static const struct usb_descriptor_header *gfs_otg_desc[] = {
|
||||
(const struct usb_descriptor_header *)
|
||||
&(const struct usb_otg_descriptor) {
|
||||
.bLength = sizeof(struct usb_otg_descriptor),
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
/* REVISIT SRP-only hardware is possible, although
|
||||
* it would not be called "OTG" ... */
|
||||
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
|
||||
},
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
enum {
|
||||
GFS_STRING_MANUFACTURER_IDX,
|
||||
GFS_STRING_PRODUCT_IDX,
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
GFS_STRING_RNDIS_CONFIG_IDX,
|
||||
#endif
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
GFS_STRING_ECM_CONFIG_IDX,
|
||||
#endif
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
GFS_STRING_GENERIC_CONFIG_IDX,
|
||||
#endif
|
||||
};
|
||||
|
||||
static char gfs_manufacturer[50];
|
||||
static const char gfs_driver_desc[] = DRIVER_DESC;
|
||||
static const char gfs_short_name[] = DRIVER_NAME;
|
||||
|
||||
static struct usb_string gfs_strings[] = {
|
||||
[GFS_STRING_MANUFACTURER_IDX].s = gfs_manufacturer,
|
||||
[GFS_STRING_PRODUCT_IDX].s = gfs_driver_desc,
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
[GFS_STRING_RNDIS_CONFIG_IDX].s = "FunctionFS + RNDIS",
|
||||
#endif
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
[GFS_STRING_ECM_CONFIG_IDX].s = "FunctionFS + ECM",
|
||||
#endif
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
[GFS_STRING_GENERIC_CONFIG_IDX].s = "FunctionFS",
|
||||
#endif
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *gfs_dev_strings[] = {
|
||||
&(struct usb_gadget_strings) {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = gfs_strings,
|
||||
},
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
static int gfs_do_rndis_config(struct usb_configuration *c);
|
||||
|
||||
static struct usb_configuration gfs_rndis_config_driver = {
|
||||
.label = "FunctionFS + RNDIS",
|
||||
.bind = gfs_do_rndis_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
# define gfs_add_rndis_config(cdev) \
|
||||
usb_add_config(cdev, &gfs_rndis_config_driver)
|
||||
#else
|
||||
# define gfs_add_rndis_config(cdev) 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
static int gfs_do_ecm_config(struct usb_configuration *c);
|
||||
|
||||
static struct usb_configuration gfs_ecm_config_driver = {
|
||||
.label = "FunctionFS + ECM",
|
||||
.bind = gfs_do_ecm_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
# define gfs_add_ecm_config(cdev) \
|
||||
usb_add_config(cdev, &gfs_ecm_config_driver)
|
||||
#else
|
||||
# define gfs_add_ecm_config(cdev) 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
static int gfs_do_generic_config(struct usb_configuration *c);
|
||||
|
||||
static struct usb_configuration gfs_generic_config_driver = {
|
||||
.label = "FunctionFS",
|
||||
.bind = gfs_do_generic_config,
|
||||
.bConfigurationValue = 2,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
# define gfs_add_generic_config(cdev) \
|
||||
usb_add_config(cdev, &gfs_generic_config_driver)
|
||||
#else
|
||||
# define gfs_add_generic_config(cdev) 0
|
||||
#endif
|
||||
|
||||
|
||||
static int gfs_bind(struct usb_composite_dev *cdev);
|
||||
static int gfs_unbind(struct usb_composite_dev *cdev);
|
||||
|
||||
static struct usb_composite_driver gfs_driver = {
|
||||
.name = gfs_short_name,
|
||||
.dev = &gfs_dev_desc,
|
||||
.strings = gfs_dev_strings,
|
||||
.bind = gfs_bind,
|
||||
.unbind = gfs_unbind,
|
||||
};
|
||||
|
||||
|
||||
static struct ffs_data *gfs_ffs_data;
|
||||
static unsigned long gfs_registered;
|
||||
|
||||
|
||||
static int gfs_init(void)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
return functionfs_init();
|
||||
}
|
||||
module_init(gfs_init);
|
||||
|
||||
static void gfs_exit(void)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
if (test_and_clear_bit(0, &gfs_registered))
|
||||
usb_composite_unregister(&gfs_driver);
|
||||
|
||||
functionfs_cleanup();
|
||||
}
|
||||
module_exit(gfs_exit);
|
||||
|
||||
|
||||
static int functionfs_ready_callback(struct ffs_data *ffs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
|
||||
return -EBUSY;
|
||||
|
||||
gfs_ffs_data = ffs;
|
||||
ret = usb_composite_register(&gfs_driver);
|
||||
if (unlikely(ret < 0))
|
||||
clear_bit(0, &gfs_registered);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void functionfs_closed_callback(struct ffs_data *ffs)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
if (test_and_clear_bit(0, &gfs_registered))
|
||||
usb_composite_unregister(&gfs_driver);
|
||||
}
|
||||
|
||||
|
||||
static int functionfs_check_dev_callback(const char *dev_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int gfs_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (WARN_ON(!gfs_ffs_data))
|
||||
return -ENODEV;
|
||||
|
||||
ret = gether_setup(cdev->gadget, gfs_hostaddr);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_quick;
|
||||
|
||||
gfs_dev_desc.idVendor = cpu_to_le16(gfs_vendor_id);
|
||||
gfs_dev_desc.idProduct = cpu_to_le16(gfs_product_id);
|
||||
|
||||
snprintf(gfs_manufacturer, sizeof gfs_manufacturer, "%s %s with %s",
|
||||
init_utsname()->sysname, init_utsname()->release,
|
||||
cdev->gadget->name);
|
||||
ret = usb_string_id(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
gfs_strings[GFS_STRING_MANUFACTURER_IDX].id = ret;
|
||||
gfs_dev_desc.iManufacturer = ret;
|
||||
|
||||
ret = usb_string_id(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
gfs_strings[GFS_STRING_PRODUCT_IDX].id = ret;
|
||||
gfs_dev_desc.iProduct = ret;
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
ret = usb_string_id(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
gfs_strings[GFS_STRING_RNDIS_CONFIG_IDX].id = ret;
|
||||
gfs_rndis_config_driver.iConfiguration = ret;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
ret = usb_string_id(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
gfs_strings[GFS_STRING_ECM_CONFIG_IDX].id = ret;
|
||||
gfs_ecm_config_driver.iConfiguration = ret;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
ret = usb_string_id(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
gfs_strings[GFS_STRING_GENERIC_CONFIG_IDX].id = ret;
|
||||
gfs_generic_config_driver.iConfiguration = ret;
|
||||
#endif
|
||||
|
||||
ret = functionfs_bind(gfs_ffs_data, cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
|
||||
ret = gfs_add_rndis_config(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_unbind;
|
||||
|
||||
ret = gfs_add_ecm_config(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_unbind;
|
||||
|
||||
ret = gfs_add_generic_config(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_unbind;
|
||||
|
||||
return 0;
|
||||
|
||||
error_unbind:
|
||||
functionfs_unbind(gfs_ffs_data);
|
||||
error:
|
||||
gether_cleanup();
|
||||
error_quick:
|
||||
gfs_ffs_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gfs_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
/* We may have been called in an error recovery frem
|
||||
* composite_bind() after gfs_unbind() failure so we need to
|
||||
* check if gfs_ffs_data is not NULL since gfs_bind() handles
|
||||
* all error recovery itself. I'd rather we werent called
|
||||
* from composite on orror recovery, but what you're gonna
|
||||
* do...? */
|
||||
|
||||
if (gfs_ffs_data) {
|
||||
gether_cleanup();
|
||||
functionfs_unbind(gfs_ffs_data);
|
||||
gfs_ffs_data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __gfs_do_config(struct usb_configuration *c,
|
||||
int (*eth)(struct usb_configuration *c, u8 *ethaddr),
|
||||
u8 *ethaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!gfs_ffs_data))
|
||||
return -ENODEV;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
c->descriptors = gfs_otg_desc;
|
||||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
if (eth) {
|
||||
ret = eth(c, ethaddr);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = functionfs_add(c->cdev, c, gfs_ffs_data);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
static int gfs_do_rndis_config(struct usb_configuration *c)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
return __gfs_do_config(c, rndis_bind_config, gfs_hostaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
static int gfs_do_ecm_config(struct usb_configuration *c)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
return __gfs_do_config(c,
|
||||
can_support_ecm(c->cdev->gadget)
|
||||
? ecm_bind_config : geth_bind_config,
|
||||
gfs_hostaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
static int gfs_do_generic_config(struct usb_configuration *c)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
return __gfs_do_config(c, NULL, NULL);
|
||||
}
|
||||
#endif
|
298
drivers/usb/gadget/hid.c
Normal file
298
drivers/usb/gadget/hid.c
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* hid.c -- HID Composite driver
|
||||
*
|
||||
* Based on multi.c
|
||||
*
|
||||
* Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#define DRIVER_DESC "HID Gadget"
|
||||
#define DRIVER_VERSION "2010/03/16"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define HIDG_VENDOR_NUM 0x0525 /* XXX NetChip */
|
||||
#define HIDG_PRODUCT_NUM 0xa4ac /* Linux-USB HID gadget */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
* separate compilation ... ensuring init/exit sections work to shrink
|
||||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
|
||||
#include "composite.c"
|
||||
#include "usbstring.c"
|
||||
#include "config.c"
|
||||
#include "epautoconf.c"
|
||||
|
||||
#include "f_hid.c"
|
||||
|
||||
|
||||
struct hidg_func_node {
|
||||
struct list_head node;
|
||||
struct hidg_func_descriptor *func;
|
||||
};
|
||||
|
||||
static LIST_HEAD(hidg_func_list);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
|
||||
/* .bDeviceClass = USB_CLASS_COMM, */
|
||||
/* .bDeviceSubClass = 0, */
|
||||
/* .bDeviceProtocol = 0, */
|
||||
.bDeviceClass = 0xEF,
|
||||
.bDeviceSubClass = 2,
|
||||
.bDeviceProtocol = 1,
|
||||
/* .bMaxPacketSize0 = f(hardware) */
|
||||
|
||||
/* Vendor and product id can be overridden by module parameters. */
|
||||
.idVendor = cpu_to_le16(HIDG_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16(HIDG_PRODUCT_NUM),
|
||||
/* .bcdDevice = f(hardware) */
|
||||
/* .iManufacturer = DYNAMIC */
|
||||
/* .iProduct = DYNAMIC */
|
||||
/* NO SERIAL NUMBER */
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
static struct usb_otg_descriptor otg_descriptor = {
|
||||
.bLength = sizeof otg_descriptor,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
/* REVISIT SRP-only hardware is possible, although
|
||||
* it would not be called "OTG" ...
|
||||
*/
|
||||
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header *otg_desc[] = {
|
||||
(struct usb_descriptor_header *) &otg_descriptor,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
#define STRING_MANUFACTURER_IDX 0
|
||||
#define STRING_PRODUCT_IDX 1
|
||||
|
||||
static char manufacturer[50];
|
||||
|
||||
static struct usb_string strings_dev[] = {
|
||||
[STRING_MANUFACTURER_IDX].s = manufacturer,
|
||||
[STRING_PRODUCT_IDX].s = DRIVER_DESC,
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings stringtab_dev = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = strings_dev,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *dev_strings[] = {
|
||||
&stringtab_dev,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/****************************** Configurations ******************************/
|
||||
|
||||
static int __init do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct hidg_func_node *e;
|
||||
int func = 0, status = 0;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
c->descriptors = otg_desc;
|
||||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
list_for_each_entry(e, &hidg_func_list, node) {
|
||||
status = hidg_bind_config(c, e->func, func++);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct usb_configuration config_driver = {
|
||||
.label = "HID Gadget",
|
||||
.bind = do_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
|
||||
/****************************** Gadget Bind ******************************/
|
||||
|
||||
static int __init hid_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
struct list_head *tmp;
|
||||
int status, gcnum, funcs = 0;
|
||||
|
||||
list_for_each(tmp, &hidg_func_list)
|
||||
funcs++;
|
||||
|
||||
if (!funcs)
|
||||
return -ENODEV;
|
||||
|
||||
/* set up HID */
|
||||
status = ghid_setup(cdev->gadget, funcs);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
gcnum = usb_gadget_controller_number(gadget);
|
||||
if (gcnum >= 0)
|
||||
device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
|
||||
else
|
||||
device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
|
||||
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
*/
|
||||
|
||||
/* device descriptor strings: manufacturer, product */
|
||||
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
|
||||
init_utsname()->sysname, init_utsname()->release,
|
||||
gadget->name);
|
||||
status = usb_string_id(cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
strings_dev[STRING_MANUFACTURER_IDX].id = status;
|
||||
device_desc.iManufacturer = status;
|
||||
|
||||
status = usb_string_id(cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
strings_dev[STRING_PRODUCT_IDX].id = status;
|
||||
device_desc.iProduct = status;
|
||||
|
||||
/* register our configuration */
|
||||
status = usb_add_config(cdev, &config_driver);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit hid_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
ghid_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init hidg_plat_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct hidg_func_descriptor *func = pdev->dev.platform_data;
|
||||
struct hidg_func_node *entry;
|
||||
|
||||
if (!func) {
|
||||
dev_err(&pdev->dev, "Platform data missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
entry->func = func;
|
||||
list_add_tail(&entry->node, &hidg_func_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit hidg_plat_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hidg_func_node *e, *n;
|
||||
|
||||
list_for_each_entry_safe(e, n, &hidg_func_list, node) {
|
||||
list_del(&e->node);
|
||||
kfree(e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************** Some noise ******************************/
|
||||
|
||||
|
||||
static struct usb_composite_driver hidg_driver = {
|
||||
.name = "g_hid",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = hid_bind,
|
||||
.unbind = __exit_p(hid_unbind),
|
||||
};
|
||||
|
||||
static struct platform_driver hidg_plat_driver = {
|
||||
.remove = __devexit_p(hidg_plat_driver_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hidg",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int __init hidg_init(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = platform_driver_probe(&hidg_plat_driver,
|
||||
hidg_plat_driver_probe);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
status = usb_composite_register(&hidg_driver);
|
||||
if (status < 0)
|
||||
platform_driver_unregister(&hidg_plat_driver);
|
||||
|
||||
return status;
|
||||
}
|
||||
module_init(hidg_init);
|
||||
|
||||
static void __exit hidg_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&hidg_plat_driver);
|
||||
usb_composite_unregister(&hidg_driver);
|
||||
}
|
||||
module_exit(hidg_cleanup);
|
@ -360,7 +360,7 @@ struct pxa_ep {
|
||||
* Specific pxa endpoint data, needed for hardware initialization
|
||||
*/
|
||||
unsigned dir_in:1;
|
||||
unsigned addr:3;
|
||||
unsigned addr:4;
|
||||
unsigned config:2;
|
||||
unsigned interface:3;
|
||||
unsigned alternate:3;
|
||||
|
@ -715,7 +715,7 @@ static u8 __init nibble(unsigned char c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init get_ether_addr(const char *str, u8 *dev_addr)
|
||||
static int get_ether_addr(const char *str, u8 *dev_addr)
|
||||
{
|
||||
if (str) {
|
||||
unsigned i;
|
||||
@ -764,7 +764,7 @@ static struct device_type gadget_type = {
|
||||
*
|
||||
* Returns negative errno, or zero on success
|
||||
*/
|
||||
int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
|
||||
int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
|
||||
{
|
||||
struct eth_dev *dev;
|
||||
struct net_device *net;
|
||||
|
241
drivers/usb/gadget/uvc.h
Normal file
241
drivers/usb/gadget/uvc.h
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* uvc_gadget.h -- USB Video Class Gadget driver
|
||||
*
|
||||
* Copyright (C) 2009-2010
|
||||
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UVC_GADGET_H_
|
||||
#define _UVC_GADGET_H_
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
#define UVC_EVENT_FIRST (V4L2_EVENT_PRIVATE_START + 0)
|
||||
#define UVC_EVENT_CONNECT (V4L2_EVENT_PRIVATE_START + 0)
|
||||
#define UVC_EVENT_DISCONNECT (V4L2_EVENT_PRIVATE_START + 1)
|
||||
#define UVC_EVENT_STREAMON (V4L2_EVENT_PRIVATE_START + 2)
|
||||
#define UVC_EVENT_STREAMOFF (V4L2_EVENT_PRIVATE_START + 3)
|
||||
#define UVC_EVENT_SETUP (V4L2_EVENT_PRIVATE_START + 4)
|
||||
#define UVC_EVENT_DATA (V4L2_EVENT_PRIVATE_START + 5)
|
||||
#define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 5)
|
||||
|
||||
struct uvc_request_data
|
||||
{
|
||||
unsigned int length;
|
||||
__u8 data[60];
|
||||
};
|
||||
|
||||
struct uvc_event
|
||||
{
|
||||
union {
|
||||
enum usb_device_speed speed;
|
||||
struct usb_ctrlrequest req;
|
||||
struct uvc_request_data data;
|
||||
};
|
||||
};
|
||||
|
||||
#define UVCIOC_SEND_RESPONSE _IOW('U', 1, struct uvc_request_data)
|
||||
|
||||
#define UVC_INTF_CONTROL 0
|
||||
#define UVC_INTF_STREAMING 1
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* UVC constants & structures
|
||||
*/
|
||||
|
||||
/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
|
||||
#define UVC_STREAM_EOH (1 << 7)
|
||||
#define UVC_STREAM_ERR (1 << 6)
|
||||
#define UVC_STREAM_STI (1 << 5)
|
||||
#define UVC_STREAM_RES (1 << 4)
|
||||
#define UVC_STREAM_SCR (1 << 3)
|
||||
#define UVC_STREAM_PTS (1 << 2)
|
||||
#define UVC_STREAM_EOF (1 << 1)
|
||||
#define UVC_STREAM_FID (1 << 0)
|
||||
|
||||
struct uvc_streaming_control {
|
||||
__u16 bmHint;
|
||||
__u8 bFormatIndex;
|
||||
__u8 bFrameIndex;
|
||||
__u32 dwFrameInterval;
|
||||
__u16 wKeyFrameRate;
|
||||
__u16 wPFrameRate;
|
||||
__u16 wCompQuality;
|
||||
__u16 wCompWindowSize;
|
||||
__u16 wDelay;
|
||||
__u32 dwMaxVideoFrameSize;
|
||||
__u32 dwMaxPayloadTransferSize;
|
||||
__u32 dwClockFrequency;
|
||||
__u8 bmFramingInfo;
|
||||
__u8 bPreferedVersion;
|
||||
__u8 bMinVersion;
|
||||
__u8 bMaxVersion;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Debugging, printing and logging
|
||||
*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/usb.h> /* For usb_endpoint_* */
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
|
||||
#include "uvc_queue.h"
|
||||
|
||||
#define UVC_TRACE_PROBE (1 << 0)
|
||||
#define UVC_TRACE_DESCR (1 << 1)
|
||||
#define UVC_TRACE_CONTROL (1 << 2)
|
||||
#define UVC_TRACE_FORMAT (1 << 3)
|
||||
#define UVC_TRACE_CAPTURE (1 << 4)
|
||||
#define UVC_TRACE_CALLS (1 << 5)
|
||||
#define UVC_TRACE_IOCTL (1 << 6)
|
||||
#define UVC_TRACE_FRAME (1 << 7)
|
||||
#define UVC_TRACE_SUSPEND (1 << 8)
|
||||
#define UVC_TRACE_STATUS (1 << 9)
|
||||
|
||||
#define UVC_WARN_MINMAX 0
|
||||
#define UVC_WARN_PROBE_DEF 1
|
||||
|
||||
extern unsigned int uvc_trace_param;
|
||||
|
||||
#define uvc_trace(flag, msg...) \
|
||||
do { \
|
||||
if (uvc_trace_param & flag) \
|
||||
printk(KERN_DEBUG "uvcvideo: " msg); \
|
||||
} while (0)
|
||||
|
||||
#define uvc_warn_once(dev, warn, msg...) \
|
||||
do { \
|
||||
if (!test_and_set_bit(warn, &dev->warnings)) \
|
||||
printk(KERN_INFO "uvcvideo: " msg); \
|
||||
} while (0)
|
||||
|
||||
#define uvc_printk(level, msg...) \
|
||||
printk(level "uvcvideo: " msg)
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Driver specific constants
|
||||
*/
|
||||
|
||||
#define DRIVER_VERSION "0.1.0"
|
||||
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
#define UVC_NUM_REQUESTS 4
|
||||
#define UVC_MAX_REQUEST_SIZE 64
|
||||
#define UVC_MAX_EVENTS 4
|
||||
|
||||
#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8
|
||||
#define USB_CLASS_MISC 0xef
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Structures
|
||||
*/
|
||||
|
||||
struct uvc_video
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
|
||||
/* Frame parameters */
|
||||
u8 bpp;
|
||||
u32 fcc;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int imagesize;
|
||||
|
||||
/* Requests */
|
||||
unsigned int req_size;
|
||||
struct usb_request *req[UVC_NUM_REQUESTS];
|
||||
__u8 *req_buffer[UVC_NUM_REQUESTS];
|
||||
struct list_head req_free;
|
||||
spinlock_t req_lock;
|
||||
|
||||
void (*encode) (struct usb_request *req, struct uvc_video *video,
|
||||
struct uvc_buffer *buf);
|
||||
|
||||
/* Context data used by the completion handler */
|
||||
__u32 payload_size;
|
||||
__u32 max_payload_size;
|
||||
|
||||
struct uvc_video_queue queue;
|
||||
unsigned int fid;
|
||||
};
|
||||
|
||||
enum uvc_state
|
||||
{
|
||||
UVC_STATE_DISCONNECTED,
|
||||
UVC_STATE_CONNECTED,
|
||||
UVC_STATE_STREAMING,
|
||||
};
|
||||
|
||||
struct uvc_device
|
||||
{
|
||||
struct video_device *vdev;
|
||||
enum uvc_state state;
|
||||
struct usb_function func;
|
||||
struct uvc_video video;
|
||||
|
||||
/* Descriptors */
|
||||
struct {
|
||||
const struct uvc_descriptor_header * const *control;
|
||||
const struct uvc_descriptor_header * const *fs_streaming;
|
||||
const struct uvc_descriptor_header * const *hs_streaming;
|
||||
} desc;
|
||||
|
||||
unsigned int control_intf;
|
||||
struct usb_ep *control_ep;
|
||||
struct usb_request *control_req;
|
||||
void *control_buf;
|
||||
|
||||
unsigned int streaming_intf;
|
||||
|
||||
/* Events */
|
||||
unsigned int event_length;
|
||||
unsigned int event_setup_out : 1;
|
||||
};
|
||||
|
||||
static inline struct uvc_device *to_uvc(struct usb_function *f)
|
||||
{
|
||||
return container_of(f, struct uvc_device, func);
|
||||
}
|
||||
|
||||
struct uvc_file_handle
|
||||
{
|
||||
struct v4l2_fh vfh;
|
||||
struct uvc_video *device;
|
||||
};
|
||||
|
||||
#define to_uvc_file_handle(handle) \
|
||||
container_of(handle, struct uvc_file_handle, vfh)
|
||||
|
||||
extern struct v4l2_file_operations uvc_v4l2_fops;
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Functions
|
||||
*/
|
||||
|
||||
extern int uvc_video_enable(struct uvc_video *video, int enable);
|
||||
extern int uvc_video_init(struct uvc_video *video);
|
||||
extern int uvc_video_pump(struct uvc_video *video);
|
||||
|
||||
extern void uvc_endpoint_stream(struct uvc_device *dev);
|
||||
|
||||
extern void uvc_function_connect(struct uvc_device *uvc);
|
||||
extern void uvc_function_disconnect(struct uvc_device *uvc);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _UVC_GADGET_H_ */
|
||||
|
583
drivers/usb/gadget/uvc_queue.c
Normal file
583
drivers/usb/gadget/uvc_queue.c
Normal file
@ -0,0 +1,583 @@
|
||||
/*
|
||||
* uvc_queue.c -- USB Video Class driver - Buffers management
|
||||
*
|
||||
* Copyright (C) 2005-2010
|
||||
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "uvc.h"
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Video buffers queue management.
|
||||
*
|
||||
* Video queues is initialized by uvc_queue_init(). The function performs
|
||||
* basic initialization of the uvc_video_queue struct and never fails.
|
||||
*
|
||||
* Video buffer allocation and freeing are performed by uvc_alloc_buffers and
|
||||
* uvc_free_buffers respectively. The former acquires the video queue lock,
|
||||
* while the later must be called with the lock held (so that allocation can
|
||||
* free previously allocated buffers). Trying to free buffers that are mapped
|
||||
* to user space will return -EBUSY.
|
||||
*
|
||||
* Video buffers are managed using two queues. However, unlike most USB video
|
||||
* drivers that use an in queue and an out queue, we use a main queue to hold
|
||||
* all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
|
||||
* hold empty buffers. This design (copied from video-buf) minimizes locking
|
||||
* in interrupt, as only one queue is shared between interrupt and user
|
||||
* contexts.
|
||||
*
|
||||
* Use cases
|
||||
* ---------
|
||||
*
|
||||
* Unless stated otherwise, all operations that modify the irq buffers queue
|
||||
* are protected by the irq spinlock.
|
||||
*
|
||||
* 1. The user queues the buffers, starts streaming and dequeues a buffer.
|
||||
*
|
||||
* The buffers are added to the main and irq queues. Both operations are
|
||||
* protected by the queue lock, and the later is protected by the irq
|
||||
* spinlock as well.
|
||||
*
|
||||
* The completion handler fetches a buffer from the irq queue and fills it
|
||||
* with video data. If no buffer is available (irq queue empty), the handler
|
||||
* returns immediately.
|
||||
*
|
||||
* When the buffer is full, the completion handler removes it from the irq
|
||||
* queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
|
||||
* At that point, any process waiting on the buffer will be woken up. If a
|
||||
* process tries to dequeue a buffer after it has been marked ready, the
|
||||
* dequeing will succeed immediately.
|
||||
*
|
||||
* 2. Buffers are queued, user is waiting on a buffer and the device gets
|
||||
* disconnected.
|
||||
*
|
||||
* When the device is disconnected, the kernel calls the completion handler
|
||||
* with an appropriate status code. The handler marks all buffers in the
|
||||
* irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
|
||||
* that any process waiting on a buffer gets woken up.
|
||||
*
|
||||
* Waking up up the first buffer on the irq list is not enough, as the
|
||||
* process waiting on the buffer might restart the dequeue operation
|
||||
* immediately.
|
||||
*
|
||||
*/
|
||||
|
||||
void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
|
||||
{
|
||||
mutex_init(&queue->mutex);
|
||||
spin_lock_init(&queue->irqlock);
|
||||
INIT_LIST_HEAD(&queue->mainqueue);
|
||||
INIT_LIST_HEAD(&queue->irqqueue);
|
||||
queue->type = type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the video buffers.
|
||||
*
|
||||
* Pages are reserved to make sure they will not be swapped, as they will be
|
||||
* filled in the URB completion handler.
|
||||
*
|
||||
* Buffers will be individually mapped, so they must all be page aligned.
|
||||
*/
|
||||
int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
|
||||
unsigned int buflength)
|
||||
{
|
||||
unsigned int bufsize = PAGE_ALIGN(buflength);
|
||||
unsigned int i;
|
||||
void *mem = NULL;
|
||||
int ret;
|
||||
|
||||
if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
|
||||
nbuffers = UVC_MAX_VIDEO_BUFFERS;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
if ((ret = uvc_free_buffers(queue)) < 0)
|
||||
goto done;
|
||||
|
||||
/* Bail out if no buffers should be allocated. */
|
||||
if (nbuffers == 0)
|
||||
goto done;
|
||||
|
||||
/* Decrement the number of buffers until allocation succeeds. */
|
||||
for (; nbuffers > 0; --nbuffers) {
|
||||
mem = vmalloc_32(nbuffers * bufsize);
|
||||
if (mem != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < nbuffers; ++i) {
|
||||
memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
|
||||
queue->buffer[i].buf.index = i;
|
||||
queue->buffer[i].buf.m.offset = i * bufsize;
|
||||
queue->buffer[i].buf.length = buflength;
|
||||
queue->buffer[i].buf.type = queue->type;
|
||||
queue->buffer[i].buf.sequence = 0;
|
||||
queue->buffer[i].buf.field = V4L2_FIELD_NONE;
|
||||
queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
|
||||
queue->buffer[i].buf.flags = 0;
|
||||
init_waitqueue_head(&queue->buffer[i].wait);
|
||||
}
|
||||
|
||||
queue->mem = mem;
|
||||
queue->count = nbuffers;
|
||||
queue->buf_size = bufsize;
|
||||
ret = nbuffers;
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the video buffers.
|
||||
*
|
||||
* This function must be called with the queue lock held.
|
||||
*/
|
||||
int uvc_free_buffers(struct uvc_video_queue *queue)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < queue->count; ++i) {
|
||||
if (queue->buffer[i].vma_use_count != 0)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (queue->count) {
|
||||
vfree(queue->mem);
|
||||
queue->count = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __uvc_query_buffer(struct uvc_buffer *buf,
|
||||
struct v4l2_buffer *v4l2_buf)
|
||||
{
|
||||
memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
|
||||
|
||||
if (buf->vma_use_count)
|
||||
v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
|
||||
|
||||
switch (buf->state) {
|
||||
case UVC_BUF_STATE_ERROR:
|
||||
case UVC_BUF_STATE_DONE:
|
||||
v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
|
||||
break;
|
||||
case UVC_BUF_STATE_QUEUED:
|
||||
case UVC_BUF_STATE_ACTIVE:
|
||||
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
|
||||
break;
|
||||
case UVC_BUF_STATE_IDLE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int uvc_query_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *v4l2_buf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (v4l2_buf->index >= queue->count) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
__uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue a video buffer. Attempting to queue a buffer that has already been
|
||||
* queued will return -EINVAL.
|
||||
*/
|
||||
int uvc_queue_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *v4l2_buf)
|
||||
{
|
||||
struct uvc_buffer *buf;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
|
||||
|
||||
if (v4l2_buf->type != queue->type ||
|
||||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
|
||||
"and/or memory (%u).\n", v4l2_buf->type,
|
||||
v4l2_buf->memory);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (v4l2_buf->index >= queue->count) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
buf = &queue->buffer[v4l2_buf->index];
|
||||
if (buf->state != UVC_BUF_STATE_IDLE) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
|
||||
"(%u).\n", buf->state);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
|
||||
v4l2_buf->bytesused > buf->buf.length) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
buf->buf.bytesused = 0;
|
||||
else
|
||||
buf->buf.bytesused = v4l2_buf->bytesused;
|
||||
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
if (queue->flags & UVC_QUEUE_DISCONNECTED) {
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
buf->state = UVC_BUF_STATE_QUEUED;
|
||||
|
||||
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
|
||||
queue->flags &= ~UVC_QUEUE_PAUSED;
|
||||
|
||||
list_add_tail(&buf->stream, &queue->mainqueue);
|
||||
list_add_tail(&buf->queue, &queue->irqqueue);
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
|
||||
{
|
||||
if (nonblocking) {
|
||||
return (buf->state != UVC_BUF_STATE_QUEUED &&
|
||||
buf->state != UVC_BUF_STATE_ACTIVE)
|
||||
? 0 : -EAGAIN;
|
||||
}
|
||||
|
||||
return wait_event_interruptible(buf->wait,
|
||||
buf->state != UVC_BUF_STATE_QUEUED &&
|
||||
buf->state != UVC_BUF_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dequeue a video buffer. If nonblocking is false, block until a buffer is
|
||||
* available.
|
||||
*/
|
||||
int uvc_dequeue_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *v4l2_buf, int nonblocking)
|
||||
{
|
||||
struct uvc_buffer *buf;
|
||||
int ret = 0;
|
||||
|
||||
if (v4l2_buf->type != queue->type ||
|
||||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
|
||||
"and/or memory (%u).\n", v4l2_buf->type,
|
||||
v4l2_buf->memory);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (list_empty(&queue->mainqueue)) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
|
||||
if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
|
||||
goto done;
|
||||
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
|
||||
buf->buf.index, buf->state, buf->buf.bytesused);
|
||||
|
||||
switch (buf->state) {
|
||||
case UVC_BUF_STATE_ERROR:
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
|
||||
"(transmission error).\n");
|
||||
ret = -EIO;
|
||||
case UVC_BUF_STATE_DONE:
|
||||
buf->state = UVC_BUF_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case UVC_BUF_STATE_IDLE:
|
||||
case UVC_BUF_STATE_QUEUED:
|
||||
case UVC_BUF_STATE_ACTIVE:
|
||||
default:
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
|
||||
"(driver bug?).\n", buf->state);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_del(&buf->stream);
|
||||
__uvc_query_buffer(buf, v4l2_buf);
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll the video queue.
|
||||
*
|
||||
* This function implements video queue polling and is intended to be used by
|
||||
* the device poll handler.
|
||||
*/
|
||||
unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
|
||||
poll_table *wait)
|
||||
{
|
||||
struct uvc_buffer *buf;
|
||||
unsigned int mask = 0;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (list_empty(&queue->mainqueue))
|
||||
goto done;
|
||||
|
||||
buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
|
||||
|
||||
poll_wait(file, &buf->wait, wait);
|
||||
if (buf->state == UVC_BUF_STATE_DONE ||
|
||||
buf->state == UVC_BUF_STATE_ERROR)
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* VMA operations.
|
||||
*/
|
||||
static void uvc_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct uvc_buffer *buffer = vma->vm_private_data;
|
||||
buffer->vma_use_count++;
|
||||
}
|
||||
|
||||
static void uvc_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct uvc_buffer *buffer = vma->vm_private_data;
|
||||
buffer->vma_use_count--;
|
||||
}
|
||||
|
||||
static struct vm_operations_struct uvc_vm_ops = {
|
||||
.open = uvc_vm_open,
|
||||
.close = uvc_vm_close,
|
||||
};
|
||||
|
||||
/*
|
||||
* Memory-map a buffer.
|
||||
*
|
||||
* This function implements video buffer memory mapping and is intended to be
|
||||
* used by the device mmap handler.
|
||||
*/
|
||||
int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
|
||||
{
|
||||
struct uvc_buffer *uninitialized_var(buffer);
|
||||
struct page *page;
|
||||
unsigned long addr, start, size;
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
start = vma->vm_start;
|
||||
size = vma->vm_end - vma->vm_start;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
for (i = 0; i < queue->count; ++i) {
|
||||
buffer = &queue->buffer[i];
|
||||
if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == queue->count || size != queue->buf_size) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* VM_IO marks the area as being an mmaped region for I/O to a
|
||||
* device. It also prevents the region from being core dumped.
|
||||
*/
|
||||
vma->vm_flags |= VM_IO;
|
||||
|
||||
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
|
||||
while (size > 0) {
|
||||
page = vmalloc_to_page((void *)addr);
|
||||
if ((ret = vm_insert_page(vma, start, page)) < 0)
|
||||
goto done;
|
||||
|
||||
start += PAGE_SIZE;
|
||||
addr += PAGE_SIZE;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
vma->vm_ops = &uvc_vm_ops;
|
||||
vma->vm_private_data = buffer;
|
||||
uvc_vm_open(vma);
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or disable the video buffers queue.
|
||||
*
|
||||
* The queue must be enabled before starting video acquisition and must be
|
||||
* disabled after stopping it. This ensures that the video buffers queue
|
||||
* state can be properly initialized before buffers are accessed from the
|
||||
* interrupt handler.
|
||||
*
|
||||
* Enabling the video queue initializes parameters (such as sequence number,
|
||||
* sync pattern, ...). If the queue is already enabled, return -EBUSY.
|
||||
*
|
||||
* Disabling the video queue cancels the queue and removes all buffers from
|
||||
* the main queue.
|
||||
*
|
||||
* This function can't be called from interrupt context. Use
|
||||
* uvc_queue_cancel() instead.
|
||||
*/
|
||||
int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (enable) {
|
||||
if (uvc_queue_streaming(queue)) {
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
queue->sequence = 0;
|
||||
queue->flags |= UVC_QUEUE_STREAMING;
|
||||
queue->buf_used = 0;
|
||||
} else {
|
||||
uvc_queue_cancel(queue, 0);
|
||||
INIT_LIST_HEAD(&queue->mainqueue);
|
||||
|
||||
for (i = 0; i < queue->count; ++i)
|
||||
queue->buffer[i].state = UVC_BUF_STATE_IDLE;
|
||||
|
||||
queue->flags &= ~UVC_QUEUE_STREAMING;
|
||||
}
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel the video buffers queue.
|
||||
*
|
||||
* Cancelling the queue marks all buffers on the irq queue as erroneous,
|
||||
* wakes them up and removes them from the queue.
|
||||
*
|
||||
* If the disconnect parameter is set, further calls to uvc_queue_buffer will
|
||||
* fail with -ENODEV.
|
||||
*
|
||||
* This function acquires the irq spinlock and can be called from interrupt
|
||||
* context.
|
||||
*/
|
||||
void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
|
||||
{
|
||||
struct uvc_buffer *buf;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
while (!list_empty(&queue->irqqueue)) {
|
||||
buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
|
||||
queue);
|
||||
list_del(&buf->queue);
|
||||
buf->state = UVC_BUF_STATE_ERROR;
|
||||
wake_up(&buf->wait);
|
||||
}
|
||||
/* This must be protected by the irqlock spinlock to avoid race
|
||||
* conditions between uvc_queue_buffer and the disconnection event that
|
||||
* could result in an interruptible wait in uvc_dequeue_buffer. Do not
|
||||
* blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
|
||||
* state outside the queue code.
|
||||
*/
|
||||
if (disconnect)
|
||||
queue->flags |= UVC_QUEUE_DISCONNECTED;
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
}
|
||||
|
||||
struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
|
||||
struct uvc_buffer *buf)
|
||||
{
|
||||
struct uvc_buffer *nextbuf;
|
||||
unsigned long flags;
|
||||
|
||||
if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
|
||||
buf->buf.length != buf->buf.bytesused) {
|
||||
buf->state = UVC_BUF_STATE_QUEUED;
|
||||
buf->buf.bytesused = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
list_del(&buf->queue);
|
||||
if (!list_empty(&queue->irqqueue))
|
||||
nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
|
||||
queue);
|
||||
else
|
||||
nextbuf = NULL;
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
|
||||
buf->buf.sequence = queue->sequence++;
|
||||
do_gettimeofday(&buf->buf.timestamp);
|
||||
|
||||
wake_up(&buf->wait);
|
||||
return nextbuf;
|
||||
}
|
||||
|
||||
struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue)
|
||||
{
|
||||
struct uvc_buffer *buf = NULL;
|
||||
|
||||
if (!list_empty(&queue->irqqueue))
|
||||
buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
|
||||
queue);
|
||||
else
|
||||
queue->flags |= UVC_QUEUE_PAUSED;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
89
drivers/usb/gadget/uvc_queue.h
Normal file
89
drivers/usb/gadget/uvc_queue.h
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef _UVC_QUEUE_H_
|
||||
#define _UVC_QUEUE_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
/* Maximum frame size in bytes, for sanity checking. */
|
||||
#define UVC_MAX_FRAME_SIZE (16*1024*1024)
|
||||
/* Maximum number of video buffers. */
|
||||
#define UVC_MAX_VIDEO_BUFFERS 32
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Structures.
|
||||
*/
|
||||
|
||||
enum uvc_buffer_state {
|
||||
UVC_BUF_STATE_IDLE = 0,
|
||||
UVC_BUF_STATE_QUEUED = 1,
|
||||
UVC_BUF_STATE_ACTIVE = 2,
|
||||
UVC_BUF_STATE_DONE = 3,
|
||||
UVC_BUF_STATE_ERROR = 4,
|
||||
};
|
||||
|
||||
struct uvc_buffer {
|
||||
unsigned long vma_use_count;
|
||||
struct list_head stream;
|
||||
|
||||
/* Touched by interrupt handler. */
|
||||
struct v4l2_buffer buf;
|
||||
struct list_head queue;
|
||||
wait_queue_head_t wait;
|
||||
enum uvc_buffer_state state;
|
||||
};
|
||||
|
||||
#define UVC_QUEUE_STREAMING (1 << 0)
|
||||
#define UVC_QUEUE_DISCONNECTED (1 << 1)
|
||||
#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
|
||||
#define UVC_QUEUE_PAUSED (1 << 3)
|
||||
|
||||
struct uvc_video_queue {
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
void *mem;
|
||||
unsigned int flags;
|
||||
__u32 sequence;
|
||||
|
||||
unsigned int count;
|
||||
unsigned int buf_size;
|
||||
unsigned int buf_used;
|
||||
struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
|
||||
struct mutex mutex; /* protects buffers and mainqueue */
|
||||
spinlock_t irqlock; /* protects irqqueue */
|
||||
|
||||
struct list_head mainqueue;
|
||||
struct list_head irqqueue;
|
||||
};
|
||||
|
||||
extern void uvc_queue_init(struct uvc_video_queue *queue,
|
||||
enum v4l2_buf_type type);
|
||||
extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
|
||||
unsigned int nbuffers, unsigned int buflength);
|
||||
extern int uvc_free_buffers(struct uvc_video_queue *queue);
|
||||
extern int uvc_query_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *v4l2_buf);
|
||||
extern int uvc_queue_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *v4l2_buf);
|
||||
extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *v4l2_buf, int nonblocking);
|
||||
extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
|
||||
extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
|
||||
extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
|
||||
struct uvc_buffer *buf);
|
||||
extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
|
||||
struct file *file, poll_table *wait);
|
||||
extern int uvc_queue_mmap(struct uvc_video_queue *queue,
|
||||
struct vm_area_struct *vma);
|
||||
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
|
||||
{
|
||||
return queue->flags & UVC_QUEUE_STREAMING;
|
||||
}
|
||||
extern struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _UVC_QUEUE_H_ */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user