mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
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
261 changed files with 17242 additions and 8360 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,578 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2002 by David Brownell
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __USB_CORE_HCD_H
|
||||
#define __USB_CORE_HCD_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/rwsem.h>
|
||||
|
||||
#define MAX_TOPO_LEVEL 6
|
||||
|
||||
/* This file contains declarations of usbcore internals that are mostly
|
||||
* used or exposed by Host Controller Drivers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* USB Packet IDs (PIDs)
|
||||
*/
|
||||
#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */
|
||||
#define USB_PID_OUT 0xe1
|
||||
#define USB_PID_ACK 0xd2
|
||||
#define USB_PID_DATA0 0xc3
|
||||
#define USB_PID_PING 0xb4 /* USB 2.0 */
|
||||
#define USB_PID_SOF 0xa5
|
||||
#define USB_PID_NYET 0x96 /* USB 2.0 */
|
||||
#define USB_PID_DATA2 0x87 /* USB 2.0 */
|
||||
#define USB_PID_SPLIT 0x78 /* USB 2.0 */
|
||||
#define USB_PID_IN 0x69
|
||||
#define USB_PID_NAK 0x5a
|
||||
#define USB_PID_DATA1 0x4b
|
||||
#define USB_PID_PREAMBLE 0x3c /* Token mode */
|
||||
#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
|
||||
#define USB_PID_SETUP 0x2d
|
||||
#define USB_PID_STALL 0x1e
|
||||
#define USB_PID_MDATA 0x0f /* USB 2.0 */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* USB Host Controller Driver (usb_hcd) framework
|
||||
*
|
||||
* Since "struct usb_bus" is so thin, you can't share much code in it.
|
||||
* This framework is a layer over that, and should be more sharable.
|
||||
*
|
||||
* @authorized_default: Specifies if new devices are authorized to
|
||||
* connect by default or they require explicit
|
||||
* user space authorization; this bit is settable
|
||||
* through /sys/class/usb_host/X/authorized_default.
|
||||
* For the rest is RO, so we don't lock to r/w it.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct usb_hcd {
|
||||
|
||||
/*
|
||||
* housekeeping
|
||||
*/
|
||||
struct usb_bus self; /* hcd is-a bus */
|
||||
struct kref kref; /* reference counter */
|
||||
|
||||
const char *product_desc; /* product/vendor string */
|
||||
char irq_descr[24]; /* driver + bus # */
|
||||
|
||||
struct timer_list rh_timer; /* drives root-hub polling */
|
||||
struct urb *status_urb; /* the current status urb */
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
struct work_struct wakeup_work; /* for remote wakeup */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* hardware info/state
|
||||
*/
|
||||
const struct hc_driver *driver; /* hw-specific hooks */
|
||||
|
||||
/* Flags that need to be manipulated atomically */
|
||||
unsigned long flags;
|
||||
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
|
||||
#define HCD_FLAG_SAW_IRQ 0x00000002
|
||||
|
||||
unsigned rh_registered:1;/* is root hub registered? */
|
||||
|
||||
/* The next flag is a stopgap, to be removed when all the HCDs
|
||||
* support the new root-hub polling mechanism. */
|
||||
unsigned uses_new_polling:1;
|
||||
unsigned poll_rh:1; /* poll for rh status? */
|
||||
unsigned poll_pending:1; /* status has changed? */
|
||||
unsigned wireless:1; /* Wireless USB HCD */
|
||||
unsigned authorized_default:1;
|
||||
unsigned has_tt:1; /* Integrated TT in root hub */
|
||||
|
||||
int irq; /* irq allocated */
|
||||
void __iomem *regs; /* device memory/io */
|
||||
u64 rsrc_start; /* memory/io resource start */
|
||||
u64 rsrc_len; /* memory/io resource length */
|
||||
unsigned power_budget; /* in mA, 0 = no limit */
|
||||
|
||||
/* bandwidth_mutex should be taken before adding or removing
|
||||
* any new bus bandwidth constraints:
|
||||
* 1. Before adding a configuration for a new device.
|
||||
* 2. Before removing the configuration to put the device into
|
||||
* the addressed state.
|
||||
* 3. Before selecting a different configuration.
|
||||
* 4. Before selecting an alternate interface setting.
|
||||
*
|
||||
* bandwidth_mutex should be dropped after a successful control message
|
||||
* to the device, or resetting the bandwidth after a failed attempt.
|
||||
*/
|
||||
struct mutex bandwidth_mutex;
|
||||
|
||||
|
||||
#define HCD_BUFFER_POOLS 4
|
||||
struct dma_pool *pool [HCD_BUFFER_POOLS];
|
||||
|
||||
int state;
|
||||
# define __ACTIVE 0x01
|
||||
# define __SUSPEND 0x04
|
||||
# define __TRANSIENT 0x80
|
||||
|
||||
# define HC_STATE_HALT 0
|
||||
# define HC_STATE_RUNNING (__ACTIVE)
|
||||
# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
|
||||
# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
|
||||
# define HC_STATE_SUSPENDED (__SUSPEND)
|
||||
|
||||
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
|
||||
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
|
||||
|
||||
/* more shared queuing code would be good; it should support
|
||||
* smarter scheduling, handle transaction translators, etc;
|
||||
* input size of periodic table to an interrupt scheduler.
|
||||
* (ohci 32, uhci 1024, ehci 256/512/1024).
|
||||
*/
|
||||
|
||||
/* The HC driver's private data is stored at the end of
|
||||
* this structure.
|
||||
*/
|
||||
unsigned long hcd_priv[0]
|
||||
__attribute__ ((aligned(sizeof(unsigned long))));
|
||||
};
|
||||
|
||||
/* 2.4 does this a bit differently ... */
|
||||
static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
|
||||
{
|
||||
return &hcd->self;
|
||||
}
|
||||
|
||||
static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus)
|
||||
{
|
||||
return container_of(bus, struct usb_hcd, self);
|
||||
}
|
||||
|
||||
struct hcd_timeout { /* timeouts we allocate */
|
||||
struct list_head timeout_list;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
struct hc_driver {
|
||||
const char *description; /* "ehci-hcd" etc */
|
||||
const char *product_desc; /* product/vendor string */
|
||||
size_t hcd_priv_size; /* size of private data */
|
||||
|
||||
/* irq handler */
|
||||
irqreturn_t (*irq) (struct usb_hcd *hcd);
|
||||
|
||||
int flags;
|
||||
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
|
||||
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
|
||||
#define HCD_USB11 0x0010 /* USB 1.1 */
|
||||
#define HCD_USB2 0x0020 /* USB 2.0 */
|
||||
#define HCD_USB3 0x0040 /* USB 3.0 */
|
||||
#define HCD_MASK 0x0070
|
||||
|
||||
/* called to init HCD and root hub */
|
||||
int (*reset) (struct usb_hcd *hcd);
|
||||
int (*start) (struct usb_hcd *hcd);
|
||||
|
||||
/* NOTE: these suspend/resume calls relate to the HC as
|
||||
* a whole, not just the root hub; they're for PCI bus glue.
|
||||
*/
|
||||
/* called after suspending the hub, before entering D3 etc */
|
||||
int (*pci_suspend)(struct usb_hcd *hcd);
|
||||
|
||||
/* called after entering D0 (etc), before resuming the hub */
|
||||
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
|
||||
|
||||
/* cleanly make HCD stop writing memory and doing I/O */
|
||||
void (*stop) (struct usb_hcd *hcd);
|
||||
|
||||
/* shutdown HCD */
|
||||
void (*shutdown) (struct usb_hcd *hcd);
|
||||
|
||||
/* return current frame number */
|
||||
int (*get_frame_number) (struct usb_hcd *hcd);
|
||||
|
||||
/* manage i/o requests, device state */
|
||||
int (*urb_enqueue)(struct usb_hcd *hcd,
|
||||
struct urb *urb, gfp_t mem_flags);
|
||||
int (*urb_dequeue)(struct usb_hcd *hcd,
|
||||
struct urb *urb, int status);
|
||||
|
||||
/* hw synch, freeing endpoint resources that urb_dequeue can't */
|
||||
void (*endpoint_disable)(struct usb_hcd *hcd,
|
||||
struct usb_host_endpoint *ep);
|
||||
|
||||
/* (optional) reset any endpoint state such as sequence number
|
||||
and current window */
|
||||
void (*endpoint_reset)(struct usb_hcd *hcd,
|
||||
struct usb_host_endpoint *ep);
|
||||
|
||||
/* root hub support */
|
||||
int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
|
||||
int (*hub_control) (struct usb_hcd *hcd,
|
||||
u16 typeReq, u16 wValue, u16 wIndex,
|
||||
char *buf, u16 wLength);
|
||||
int (*bus_suspend)(struct usb_hcd *);
|
||||
int (*bus_resume)(struct usb_hcd *);
|
||||
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
|
||||
|
||||
/* force handover of high-speed port to full-speed companion */
|
||||
void (*relinquish_port)(struct usb_hcd *, int);
|
||||
/* has a port been handed over to a companion? */
|
||||
int (*port_handed_over)(struct usb_hcd *, int);
|
||||
|
||||
/* CLEAR_TT_BUFFER completion callback */
|
||||
void (*clear_tt_buffer_complete)(struct usb_hcd *,
|
||||
struct usb_host_endpoint *);
|
||||
|
||||
/* xHCI specific functions */
|
||||
/* Called by usb_alloc_dev to alloc HC device structures */
|
||||
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
|
||||
/* Called by usb_disconnect to free HC device structures */
|
||||
void (*free_dev)(struct usb_hcd *, struct usb_device *);
|
||||
|
||||
/* Bandwidth computation functions */
|
||||
/* Note that add_endpoint() can only be called once per endpoint before
|
||||
* check_bandwidth() or reset_bandwidth() must be called.
|
||||
* drop_endpoint() can only be called once per endpoint also.
|
||||
* A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will
|
||||
* add the endpoint to the schedule with possibly new parameters denoted by a
|
||||
* different endpoint descriptor in usb_host_endpoint.
|
||||
* A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is
|
||||
* not allowed.
|
||||
*/
|
||||
/* Allocate endpoint resources and add them to a new schedule */
|
||||
int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
|
||||
/* Drop an endpoint from a new schedule */
|
||||
int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
|
||||
/* Check that a new hardware configuration, set using
|
||||
* endpoint_enable and endpoint_disable, does not exceed bus
|
||||
* bandwidth. This must be called before any set configuration
|
||||
* or set interface requests are sent to the device.
|
||||
*/
|
||||
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||
/* Reset the device schedule to the last known good schedule,
|
||||
* which was set from a previous successful call to
|
||||
* check_bandwidth(). This reverts any add_endpoint() and
|
||||
* drop_endpoint() calls since that last successful call.
|
||||
* Used for when a check_bandwidth() call fails due to resource
|
||||
* or bandwidth constraints.
|
||||
*/
|
||||
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||
/* Returns the hardware-chosen device address */
|
||||
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
|
||||
/* Notifies the HCD after a hub descriptor is fetched.
|
||||
* Will block.
|
||||
*/
|
||||
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
int (*reset_device)(struct usb_hcd *, struct usb_device *);
|
||||
};
|
||||
|
||||
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
|
||||
extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
|
||||
int status);
|
||||
extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
|
||||
|
||||
extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags);
|
||||
extern int usb_hcd_unlink_urb(struct urb *urb, int status);
|
||||
extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
|
||||
int status);
|
||||
extern void usb_hcd_flush_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep);
|
||||
extern void usb_hcd_disable_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep);
|
||||
extern void usb_hcd_reset_endpoint(struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep);
|
||||
extern void usb_hcd_synchronize_unlinks(struct usb_device *udev);
|
||||
extern int usb_hcd_alloc_bandwidth(struct usb_device *udev,
|
||||
struct usb_host_config *new_config,
|
||||
struct usb_host_interface *old_alt,
|
||||
struct usb_host_interface *new_alt);
|
||||
extern int usb_hcd_get_frame_number(struct usb_device *udev);
|
||||
|
||||
extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
|
||||
struct device *dev, const char *bus_name);
|
||||
extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd);
|
||||
extern void usb_put_hcd(struct usb_hcd *hcd);
|
||||
extern int usb_add_hcd(struct usb_hcd *hcd,
|
||||
unsigned int irqnum, unsigned long irqflags);
|
||||
extern void usb_remove_hcd(struct usb_hcd *hcd);
|
||||
|
||||
struct platform_device;
|
||||
extern void usb_hcd_platform_shutdown(struct platform_device *dev);
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
struct pci_dev;
|
||||
struct pci_device_id;
|
||||
extern int usb_hcd_pci_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id);
|
||||
extern void usb_hcd_pci_remove(struct pci_dev *dev);
|
||||
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
|
||||
#endif
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
/* pci-ish (pdev null is ok) buffer alloc/mapping support */
|
||||
int hcd_buffer_create(struct usb_hcd *hcd);
|
||||
void hcd_buffer_destroy(struct usb_hcd *hcd);
|
||||
|
||||
void *hcd_buffer_alloc(struct usb_bus *bus, size_t size,
|
||||
gfp_t mem_flags, dma_addr_t *dma);
|
||||
void hcd_buffer_free(struct usb_bus *bus, size_t size,
|
||||
void *addr, dma_addr_t dma);
|
||||
|
||||
/* generic bus glue, needed for host controllers that don't use PCI */
|
||||
extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
|
||||
|
||||
extern void usb_hc_died(struct usb_hcd *hcd);
|
||||
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
|
||||
|
||||
/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
|
||||
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
|
||||
#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep)))
|
||||
#define usb_settoggle(dev, ep, out, bit) \
|
||||
((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \
|
||||
((bit) << (ep)))
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/* Enumeration is only for the hub driver, or HCD virtual root hubs */
|
||||
extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
||||
struct usb_bus *, unsigned port);
|
||||
extern int usb_new_device(struct usb_device *dev);
|
||||
extern void usb_disconnect(struct usb_device **);
|
||||
|
||||
extern int usb_get_configuration(struct usb_device *dev);
|
||||
extern void usb_destroy_configuration(struct usb_device *dev);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* HCD Root Hub support
|
||||
*/
|
||||
|
||||
#include "hub.h"
|
||||
|
||||
/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
|
||||
#define DeviceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
||||
#define DeviceOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
||||
|
||||
#define InterfaceRequest \
|
||||
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
||||
|
||||
#define EndpointRequest \
|
||||
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
||||
#define EndpointOutRequest \
|
||||
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
||||
|
||||
/* class requests from the USB 2.0 hub spec, table 11-15 */
|
||||
/* GetBusState and SetHubDescriptor are optional, omitted */
|
||||
#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
|
||||
#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
|
||||
#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
|
||||
#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS)
|
||||
#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS)
|
||||
#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
|
||||
#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Generic bandwidth allocation constants/support
|
||||
*/
|
||||
#define FRAME_TIME_USECS 1000L
|
||||
#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
|
||||
/* Trying not to use worst-case bit-stuffing
|
||||
* of (7/6 * 8 * bytecount) = 9.33 * bytecount */
|
||||
/* bytecount = data payload byte count */
|
||||
|
||||
#define NS_TO_US(ns) ((ns + 500L) / 1000L)
|
||||
/* convert & round nanoseconds to microseconds */
|
||||
|
||||
|
||||
/*
|
||||
* Full/low speed bandwidth allocation constants/support.
|
||||
*/
|
||||
#define BW_HOST_DELAY 1000L /* nanoseconds */
|
||||
#define BW_HUB_LS_SETUP 333L /* nanoseconds */
|
||||
/* 4 full-speed bit times (est.) */
|
||||
|
||||
#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */
|
||||
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
|
||||
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
|
||||
|
||||
/*
|
||||
* Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
|
||||
* ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
|
||||
* to preallocate bandwidth)
|
||||
*/
|
||||
#define USB2_HOST_DELAY 5 /* nsec, guess */
|
||||
#define HS_NSECS(bytes) (((55 * 8 * 2083) \
|
||||
+ (2083UL * (3 + BitTime(bytes))))/1000 \
|
||||
+ USB2_HOST_DELAY)
|
||||
#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \
|
||||
+ (2083UL * (3 + BitTime(bytes))))/1000 \
|
||||
+ USB2_HOST_DELAY)
|
||||
#define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
|
||||
#define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))
|
||||
|
||||
extern long usb_calc_bus_time(int speed, int is_input,
|
||||
int isoc, int bytecount);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
extern void usb_set_device_state(struct usb_device *udev,
|
||||
enum usb_device_state new_state);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* exported only within usbcore */
|
||||
|
||||
extern struct list_head usb_bus_list;
|
||||
extern struct mutex usb_bus_list_lock;
|
||||
extern wait_queue_head_t usb_kill_urb_queue;
|
||||
|
||||
extern int usb_find_interface_driver(struct usb_device *dev,
|
||||
struct usb_interface *interface);
|
||||
|
||||
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
|
||||
extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
|
||||
extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
|
||||
#else
|
||||
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_USB_SUSPEND */
|
||||
|
||||
|
||||
/*
|
||||
* USB device fs stuff
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_DEVICEFS
|
||||
|
||||
/*
|
||||
* these are expected to be called from the USB core/hub thread
|
||||
* with the kernel lock held
|
||||
*/
|
||||
extern void usbfs_update_special(void);
|
||||
extern int usbfs_init(void);
|
||||
extern void usbfs_cleanup(void);
|
||||
|
||||
#else /* CONFIG_USB_DEVICEFS */
|
||||
|
||||
static inline void usbfs_update_special(void) {}
|
||||
static inline int usbfs_init(void) { return 0; }
|
||||
static inline void usbfs_cleanup(void) { }
|
||||
|
||||
#endif /* CONFIG_USB_DEVICEFS */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
|
||||
|
||||
struct usb_mon_operations {
|
||||
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
|
||||
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
|
||||
void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
|
||||
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
|
||||
};
|
||||
|
||||
extern struct usb_mon_operations *mon_ops;
|
||||
|
||||
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb)
|
||||
{
|
||||
if (bus->monitored)
|
||||
(*mon_ops->urb_submit)(bus, urb);
|
||||
}
|
||||
|
||||
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
|
||||
int error)
|
||||
{
|
||||
if (bus->monitored)
|
||||
(*mon_ops->urb_submit_error)(bus, urb, error);
|
||||
}
|
||||
|
||||
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
|
||||
int status)
|
||||
{
|
||||
if (bus->monitored)
|
||||
(*mon_ops->urb_complete)(bus, urb, status);
|
||||
}
|
||||
|
||||
int usb_mon_register(struct usb_mon_operations *ops);
|
||||
void usb_mon_deregister(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
|
||||
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
|
||||
int error) {}
|
||||
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
|
||||
int status) {}
|
||||
|
||||
#endif /* CONFIG_USB_MON || CONFIG_USB_MON_MODULE */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
|
||||
/* bleech -- resurfaced in 2.4.11 or 2.4.12 */
|
||||
#define bitmap DeviceRemovable
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* random stuff */
|
||||
|
||||
#define RUN_CONTEXT (in_irq() ? "in_irq" \
|
||||
: (in_interrupt() ? "in_interrupt" : "can sleep"))
|
||||
|
||||
|
||||
/* This rwsem is for use only by the hub driver and ehci-hcd.
|
||||
* Nobody else should touch it.
|
||||
*/
|
||||
extern struct rw_semaphore ehci_cf_port_reset_rwsem;
|
||||
|
||||
/* Keep track of which host controller drivers are loaded */
|
||||
#define USB_UHCI_LOADED 0
|
||||
#define USB_OHCI_LOADED 1
|
||||
#define USB_EHCI_LOADED 2
|
||||
extern unsigned long usb_hcds_loaded;
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __USB_CORE_HCD_H */
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,205 +0,0 @@
|
|||
#ifndef __LINUX_HUB_H
|
||||
#define __LINUX_HUB_H
|
||||
|
||||
/*
|
||||
* Hub protocol and driver data structures.
|
||||
*
|
||||
* Some of these are known to the "virtual root hub" code
|
||||
* in host controller drivers.
|
||||
*/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/compiler.h> /* likely()/unlikely() */
|
||||
|
||||
/*
|
||||
* Hub request types
|
||||
*/
|
||||
|
||||
#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)
|
||||
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
|
||||
|
||||
/*
|
||||
* Hub class requests
|
||||
* See USB 2.0 spec Table 11-16
|
||||
*/
|
||||
#define HUB_CLEAR_TT_BUFFER 8
|
||||
#define HUB_RESET_TT 9
|
||||
#define HUB_GET_TT_STATE 10
|
||||
#define HUB_STOP_TT 11
|
||||
|
||||
/*
|
||||
* Hub Class feature numbers
|
||||
* See USB 2.0 spec Table 11-17
|
||||
*/
|
||||
#define C_HUB_LOCAL_POWER 0
|
||||
#define C_HUB_OVER_CURRENT 1
|
||||
|
||||
/*
|
||||
* Port feature numbers
|
||||
* See USB 2.0 spec Table 11-17
|
||||
*/
|
||||
#define USB_PORT_FEAT_CONNECTION 0
|
||||
#define USB_PORT_FEAT_ENABLE 1
|
||||
#define USB_PORT_FEAT_SUSPEND 2 /* L2 suspend */
|
||||
#define USB_PORT_FEAT_OVER_CURRENT 3
|
||||
#define USB_PORT_FEAT_RESET 4
|
||||
#define USB_PORT_FEAT_L1 5 /* L1 suspend */
|
||||
#define USB_PORT_FEAT_POWER 8
|
||||
#define USB_PORT_FEAT_LOWSPEED 9
|
||||
/* This value was never in Table 11-17 */
|
||||
#define USB_PORT_FEAT_HIGHSPEED 10
|
||||
/* This value is also fake */
|
||||
#define USB_PORT_FEAT_SUPERSPEED 11
|
||||
#define USB_PORT_FEAT_C_CONNECTION 16
|
||||
#define USB_PORT_FEAT_C_ENABLE 17
|
||||
#define USB_PORT_FEAT_C_SUSPEND 18
|
||||
#define USB_PORT_FEAT_C_OVER_CURRENT 19
|
||||
#define USB_PORT_FEAT_C_RESET 20
|
||||
#define USB_PORT_FEAT_TEST 21
|
||||
#define USB_PORT_FEAT_INDICATOR 22
|
||||
#define USB_PORT_FEAT_C_PORT_L1 23
|
||||
|
||||
/*
|
||||
* Hub Status and Hub Change results
|
||||
* See USB 2.0 spec Table 11-19 and Table 11-20
|
||||
*/
|
||||
struct usb_port_status {
|
||||
__le16 wPortStatus;
|
||||
__le16 wPortChange;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* wPortStatus bit field
|
||||
* See USB 2.0 spec Table 11-21
|
||||
*/
|
||||
#define USB_PORT_STAT_CONNECTION 0x0001
|
||||
#define USB_PORT_STAT_ENABLE 0x0002
|
||||
#define USB_PORT_STAT_SUSPEND 0x0004
|
||||
#define USB_PORT_STAT_OVERCURRENT 0x0008
|
||||
#define USB_PORT_STAT_RESET 0x0010
|
||||
#define USB_PORT_STAT_L1 0x0020
|
||||
/* bits 6 to 7 are reserved */
|
||||
#define USB_PORT_STAT_POWER 0x0100
|
||||
#define USB_PORT_STAT_LOW_SPEED 0x0200
|
||||
#define USB_PORT_STAT_HIGH_SPEED 0x0400
|
||||
#define USB_PORT_STAT_TEST 0x0800
|
||||
#define USB_PORT_STAT_INDICATOR 0x1000
|
||||
/* bits 13 to 15 are reserved */
|
||||
|
||||
/*
|
||||
* wPortChange bit field
|
||||
* See USB 2.0 spec Table 11-22
|
||||
* Bits 0 to 4 shown, bits 5 to 15 are reserved
|
||||
*/
|
||||
#define USB_PORT_STAT_C_CONNECTION 0x0001
|
||||
#define USB_PORT_STAT_C_ENABLE 0x0002
|
||||
#define USB_PORT_STAT_C_SUSPEND 0x0004
|
||||
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
|
||||
#define USB_PORT_STAT_C_RESET 0x0010
|
||||
#define USB_PORT_STAT_C_L1 0x0020
|
||||
|
||||
/*
|
||||
* wHubCharacteristics (masks)
|
||||
* See USB 2.0 spec Table 11-13, offset 3
|
||||
*/
|
||||
#define HUB_CHAR_LPSM 0x0003 /* D1 .. D0 */
|
||||
#define HUB_CHAR_COMPOUND 0x0004 /* D2 */
|
||||
#define HUB_CHAR_OCPM 0x0018 /* D4 .. D3 */
|
||||
#define HUB_CHAR_TTTT 0x0060 /* D6 .. D5 */
|
||||
#define HUB_CHAR_PORTIND 0x0080 /* D7 */
|
||||
|
||||
struct usb_hub_status {
|
||||
__le16 wHubStatus;
|
||||
__le16 wHubChange;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* Hub Status & Hub Change bit masks
|
||||
* See USB 2.0 spec Table 11-19 and Table 11-20
|
||||
* Bits 0 and 1 for wHubStatus and wHubChange
|
||||
* Bits 2 to 15 are reserved for both
|
||||
*/
|
||||
#define HUB_STATUS_LOCAL_POWER 0x0001
|
||||
#define HUB_STATUS_OVERCURRENT 0x0002
|
||||
#define HUB_CHANGE_LOCAL_POWER 0x0001
|
||||
#define HUB_CHANGE_OVERCURRENT 0x0002
|
||||
|
||||
|
||||
/*
|
||||
* Hub descriptor
|
||||
* See USB 2.0 spec Table 11-13
|
||||
*/
|
||||
|
||||
#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
|
||||
#define USB_DT_HUB_NONVAR_SIZE 7
|
||||
|
||||
struct usb_hub_descriptor {
|
||||
__u8 bDescLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bNbrPorts;
|
||||
__le16 wHubCharacteristics;
|
||||
__u8 bPwrOn2PwrGood;
|
||||
__u8 bHubContrCurrent;
|
||||
/* add 1 bit for hub status change; round to bytes */
|
||||
__u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
|
||||
__u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* port indicator status selectors, tables 11-7 and 11-25 */
|
||||
#define HUB_LED_AUTO 0
|
||||
#define HUB_LED_AMBER 1
|
||||
#define HUB_LED_GREEN 2
|
||||
#define HUB_LED_OFF 3
|
||||
|
||||
enum hub_led_mode {
|
||||
INDICATOR_AUTO = 0,
|
||||
INDICATOR_CYCLE,
|
||||
/* software blinks for attention: software, hardware, reserved */
|
||||
INDICATOR_GREEN_BLINK, INDICATOR_GREEN_BLINK_OFF,
|
||||
INDICATOR_AMBER_BLINK, INDICATOR_AMBER_BLINK_OFF,
|
||||
INDICATOR_ALT_BLINK, INDICATOR_ALT_BLINK_OFF
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct usb_device;
|
||||
|
||||
/* Transaction Translator Think Times, in bits */
|
||||
#define HUB_TTTT_8_BITS 0x00
|
||||
#define HUB_TTTT_16_BITS 0x20
|
||||
#define HUB_TTTT_24_BITS 0x40
|
||||
#define HUB_TTTT_32_BITS 0x60
|
||||
|
||||
/*
|
||||
* As of USB 2.0, full/low speed devices are segregated into trees.
|
||||
* One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
|
||||
* The other type grows from high speed hubs when they connect to
|
||||
* full/low speed devices using "Transaction Translators" (TTs).
|
||||
*
|
||||
* TTs should only be known to the hub driver, and high speed bus
|
||||
* drivers (only EHCI for now). They affect periodic scheduling and
|
||||
* sometimes control/bulk error recovery.
|
||||
*/
|
||||
struct usb_tt {
|
||||
struct usb_device *hub; /* upstream highspeed hub */
|
||||
int multi; /* true means one TT per port */
|
||||
unsigned think_time; /* think time in ns */
|
||||
|
||||
/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
|
||||
spinlock_t lock;
|
||||
struct list_head clear_list; /* of usb_tt_clear */
|
||||
struct work_struct clear_work;
|
||||
};
|
||||
|
||||
struct usb_tt_clear {
|
||||
struct list_head clear_list;
|
||||
unsigned tt;
|
||||
u16 devinfo;
|
||||
struct usb_hcd *hcd;
|
||||
struct usb_host_endpoint *ep;
|
||||
};
|
||||
|
||||
extern int usb_hub_clear_tt_buffer(struct urb *urb);
|
||||
extern void usb_ep0_reinit(struct usb_device *);
|
||||
|
||||
#endif /* __LINUX_HUB_H */
|
||||
|
|
@ -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_ */
|
||||
|
||||
374
drivers/usb/gadget/uvc_v4l2.c
Normal file
374
drivers/usb/gadget/uvc_v4l2.c
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* uvc_v4l2.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/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
|
||||
#include "uvc.h"
|
||||
#include "uvc_queue.h"
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Requests handling
|
||||
*/
|
||||
|
||||
static int
|
||||
uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
|
||||
{
|
||||
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
||||
struct usb_request *req = uvc->control_req;
|
||||
|
||||
if (data->length < 0)
|
||||
return usb_ep_set_halt(cdev->gadget->ep0);
|
||||
|
||||
req->length = min(uvc->event_length, data->length);
|
||||
req->zero = data->length < uvc->event_length;
|
||||
req->dma = DMA_ADDR_INVALID;
|
||||
|
||||
memcpy(req->buf, data->data, data->length);
|
||||
|
||||
return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* V4L2
|
||||
*/
|
||||
|
||||
struct uvc_format
|
||||
{
|
||||
u8 bpp;
|
||||
u32 fcc;
|
||||
};
|
||||
|
||||
static struct uvc_format uvc_formats[] = {
|
||||
{ 16, V4L2_PIX_FMT_YUYV },
|
||||
{ 0, V4L2_PIX_FMT_MJPEG },
|
||||
};
|
||||
|
||||
static int
|
||||
uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt)
|
||||
{
|
||||
fmt->fmt.pix.pixelformat = video->fcc;
|
||||
fmt->fmt.pix.width = video->width;
|
||||
fmt->fmt.pix.height = video->height;
|
||||
fmt->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
fmt->fmt.pix.bytesperline = video->bpp * video->width / 8;
|
||||
fmt->fmt.pix.sizeimage = video->imagesize;
|
||||
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
fmt->fmt.pix.priv = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
|
||||
{
|
||||
struct uvc_format *format;
|
||||
unsigned int imagesize;
|
||||
unsigned int bpl;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uvc_formats); ++i) {
|
||||
format = &uvc_formats[i];
|
||||
if (format->fcc == fmt->fmt.pix.pixelformat)
|
||||
break;
|
||||
}
|
||||
|
||||
if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
|
||||
printk(KERN_INFO "Unsupported format 0x%08x.\n",
|
||||
fmt->fmt.pix.pixelformat);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bpl = format->bpp * fmt->fmt.pix.width / 8;
|
||||
imagesize = bpl ? bpl * fmt->fmt.pix.height : fmt->fmt.pix.sizeimage;
|
||||
|
||||
video->fcc = format->fcc;
|
||||
video->bpp = format->bpp;
|
||||
video->width = fmt->fmt.pix.width;
|
||||
video->height = fmt->fmt.pix.height;
|
||||
video->imagesize = imagesize;
|
||||
|
||||
fmt->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
fmt->fmt.pix.bytesperline = bpl;
|
||||
fmt->fmt.pix.sizeimage = imagesize;
|
||||
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
fmt->fmt.pix.priv = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_open(struct file *file)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct uvc_device *uvc = video_get_drvdata(vdev);
|
||||
struct uvc_file_handle *handle;
|
||||
int ret;
|
||||
|
||||
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||
if (handle == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = v4l2_fh_init(&handle->vfh, vdev);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = v4l2_event_init(&handle->vfh);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = v4l2_event_alloc(&handle->vfh, 8);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
v4l2_fh_add(&handle->vfh);
|
||||
|
||||
handle->device = &uvc->video;
|
||||
file->private_data = &handle->vfh;
|
||||
|
||||
uvc_function_connect(uvc);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
v4l2_fh_exit(&handle->vfh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_release(struct file *file)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct uvc_device *uvc = video_get_drvdata(vdev);
|
||||
struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
|
||||
struct uvc_video *video = handle->device;
|
||||
|
||||
uvc_function_disconnect(uvc);
|
||||
|
||||
uvc_video_enable(video, 0);
|
||||
mutex_lock(&video->queue.mutex);
|
||||
if (uvc_free_buffers(&video->queue) < 0)
|
||||
printk(KERN_ERR "uvc_v4l2_release: Unable to free "
|
||||
"buffers.\n");
|
||||
mutex_unlock(&video->queue.mutex);
|
||||
|
||||
file->private_data = NULL;
|
||||
v4l2_fh_del(&handle->vfh);
|
||||
v4l2_fh_exit(&handle->vfh);
|
||||
kfree(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long
|
||||
uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct uvc_device *uvc = video_get_drvdata(vdev);
|
||||
struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
|
||||
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
||||
struct uvc_video *video = &uvc->video;
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
/* Query capabilities */
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *cap = arg;
|
||||
|
||||
memset(cap, 0, sizeof *cap);
|
||||
strncpy(cap->driver, "g_uvc", sizeof(cap->driver));
|
||||
strncpy(cap->card, cdev->gadget->name, sizeof(cap->card));
|
||||
strncpy(cap->bus_info, dev_name(&cdev->gadget->dev),
|
||||
sizeof cap->bus_info);
|
||||
cap->version = DRIVER_VERSION_NUMBER;
|
||||
cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get & Set format */
|
||||
case VIDIOC_G_FMT:
|
||||
{
|
||||
struct v4l2_format *fmt = arg;
|
||||
|
||||
if (fmt->type != video->queue.type)
|
||||
return -EINVAL;
|
||||
|
||||
return uvc_v4l2_get_format(video, fmt);
|
||||
}
|
||||
|
||||
case VIDIOC_S_FMT:
|
||||
{
|
||||
struct v4l2_format *fmt = arg;
|
||||
|
||||
if (fmt->type != video->queue.type)
|
||||
return -EINVAL;
|
||||
|
||||
return uvc_v4l2_set_format(video, fmt);
|
||||
}
|
||||
|
||||
/* Buffers & streaming */
|
||||
case VIDIOC_REQBUFS:
|
||||
{
|
||||
struct v4l2_requestbuffers *rb = arg;
|
||||
|
||||
if (rb->type != video->queue.type ||
|
||||
rb->memory != V4L2_MEMORY_MMAP)
|
||||
return -EINVAL;
|
||||
|
||||
ret = uvc_alloc_buffers(&video->queue, rb->count,
|
||||
video->imagesize);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rb->count = ret;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDIOC_QUERYBUF:
|
||||
{
|
||||
struct v4l2_buffer *buf = arg;
|
||||
|
||||
if (buf->type != video->queue.type)
|
||||
return -EINVAL;
|
||||
|
||||
return uvc_query_buffer(&video->queue, buf);
|
||||
}
|
||||
|
||||
case VIDIOC_QBUF:
|
||||
if ((ret = uvc_queue_buffer(&video->queue, arg)) < 0)
|
||||
return ret;
|
||||
|
||||
return uvc_video_pump(video);
|
||||
|
||||
case VIDIOC_DQBUF:
|
||||
return uvc_dequeue_buffer(&video->queue, arg,
|
||||
file->f_flags & O_NONBLOCK);
|
||||
|
||||
case VIDIOC_STREAMON:
|
||||
{
|
||||
int *type = arg;
|
||||
|
||||
if (*type != video->queue.type)
|
||||
return -EINVAL;
|
||||
|
||||
return uvc_video_enable(video, 1);
|
||||
}
|
||||
|
||||
case VIDIOC_STREAMOFF:
|
||||
{
|
||||
int *type = arg;
|
||||
|
||||
if (*type != video->queue.type)
|
||||
return -EINVAL;
|
||||
|
||||
return uvc_video_enable(video, 0);
|
||||
}
|
||||
|
||||
/* Events */
|
||||
case VIDIOC_DQEVENT:
|
||||
{
|
||||
struct v4l2_event *event = arg;
|
||||
|
||||
ret = v4l2_event_dequeue(&handle->vfh, event,
|
||||
file->f_flags & O_NONBLOCK);
|
||||
if (ret == 0 && event->type == UVC_EVENT_SETUP) {
|
||||
struct uvc_event *uvc_event = (void *)&event->u.data;
|
||||
|
||||
/* Tell the complete callback to generate an event for
|
||||
* the next request that will be enqueued by
|
||||
* uvc_event_write.
|
||||
*/
|
||||
uvc->event_setup_out =
|
||||
!(uvc_event->req.bRequestType & USB_DIR_IN);
|
||||
uvc->event_length = uvc_event->req.wLength;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
case VIDIOC_SUBSCRIBE_EVENT:
|
||||
{
|
||||
struct v4l2_event_subscription *sub = arg;
|
||||
|
||||
if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
|
||||
return -EINVAL;
|
||||
|
||||
return v4l2_event_subscribe(&handle->vfh, arg);
|
||||
}
|
||||
|
||||
case VIDIOC_UNSUBSCRIBE_EVENT:
|
||||
return v4l2_event_unsubscribe(&handle->vfh, arg);
|
||||
|
||||
case UVCIOC_SEND_RESPONSE:
|
||||
ret = uvc_send_response(uvc, arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long
|
||||
uvc_v4l2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct uvc_device *uvc = video_get_drvdata(vdev);
|
||||
|
||||
return uvc_queue_mmap(&uvc->video.queue, vma);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
uvc_v4l2_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct uvc_device *uvc = video_get_drvdata(vdev);
|
||||
struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
|
||||
unsigned int mask = 0;
|
||||
|
||||
poll_wait(file, &handle->vfh.events->wait, wait);
|
||||
if (v4l2_event_pending(&handle->vfh))
|
||||
mask |= POLLPRI;
|
||||
|
||||
mask |= uvc_queue_poll(&uvc->video.queue, file, wait);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
struct v4l2_file_operations uvc_v4l2_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = uvc_v4l2_open,
|
||||
.release = uvc_v4l2_release,
|
||||
.ioctl = uvc_v4l2_ioctl,
|
||||
.mmap = uvc_v4l2_mmap,
|
||||
.poll = uvc_v4l2_poll,
|
||||
};
|
||||
|
||||
386
drivers/usb/gadget/uvc_video.c
Normal file
386
drivers/usb/gadget/uvc_video.c
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* uvc_video.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/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include <media/v4l2-dev.h>
|
||||
|
||||
#include "uvc.h"
|
||||
#include "uvc_queue.h"
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Video codecs
|
||||
*/
|
||||
|
||||
static int
|
||||
uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
|
||||
u8 *data, int len)
|
||||
{
|
||||
data[0] = 2;
|
||||
data[1] = UVC_STREAM_EOH | video->fid;
|
||||
|
||||
if (buf->buf.bytesused - video->queue.buf_used <= len - 2)
|
||||
data[1] |= UVC_STREAM_EOF;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
|
||||
u8 *data, int len)
|
||||
{
|
||||
struct uvc_video_queue *queue = &video->queue;
|
||||
unsigned int nbytes;
|
||||
void *mem;
|
||||
|
||||
/* Copy video data to the USB buffer. */
|
||||
mem = queue->mem + buf->buf.m.offset + queue->buf_used;
|
||||
nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
|
||||
|
||||
memcpy(data, mem, nbytes);
|
||||
queue->buf_used += nbytes;
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static void
|
||||
uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
|
||||
struct uvc_buffer *buf)
|
||||
{
|
||||
void *mem = req->buf;
|
||||
int len = video->req_size;
|
||||
int ret;
|
||||
|
||||
/* Add a header at the beginning of the payload. */
|
||||
if (video->payload_size == 0) {
|
||||
ret = uvc_video_encode_header(video, buf, mem, len);
|
||||
video->payload_size += ret;
|
||||
mem += ret;
|
||||
len -= ret;
|
||||
}
|
||||
|
||||
/* Process video data. */
|
||||
len = min((int)(video->max_payload_size - video->payload_size), len);
|
||||
ret = uvc_video_encode_data(video, buf, mem, len);
|
||||
|
||||
video->payload_size += ret;
|
||||
len -= ret;
|
||||
|
||||
req->length = video->req_size - len;
|
||||
req->zero = video->payload_size == video->max_payload_size;
|
||||
|
||||
if (buf->buf.bytesused == video->queue.buf_used) {
|
||||
video->queue.buf_used = 0;
|
||||
buf->state = UVC_BUF_STATE_DONE;
|
||||
uvc_queue_next_buffer(&video->queue, buf);
|
||||
video->fid ^= UVC_STREAM_FID;
|
||||
|
||||
video->payload_size = 0;
|
||||
}
|
||||
|
||||
if (video->payload_size == video->max_payload_size ||
|
||||
buf->buf.bytesused == video->queue.buf_used)
|
||||
video->payload_size = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
|
||||
struct uvc_buffer *buf)
|
||||
{
|
||||
void *mem = req->buf;
|
||||
int len = video->req_size;
|
||||
int ret;
|
||||
|
||||
/* Add the header. */
|
||||
ret = uvc_video_encode_header(video, buf, mem, len);
|
||||
mem += ret;
|
||||
len -= ret;
|
||||
|
||||
/* Process video data. */
|
||||
ret = uvc_video_encode_data(video, buf, mem, len);
|
||||
len -= ret;
|
||||
|
||||
req->length = video->req_size - len;
|
||||
|
||||
if (buf->buf.bytesused == video->queue.buf_used) {
|
||||
video->queue.buf_used = 0;
|
||||
buf->state = UVC_BUF_STATE_DONE;
|
||||
uvc_queue_next_buffer(&video->queue, buf);
|
||||
video->fid ^= UVC_STREAM_FID;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Request handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* I somehow feel that synchronisation won't be easy to achieve here. We have
|
||||
* three events that control USB requests submission:
|
||||
*
|
||||
* - USB request completion: the completion handler will resubmit the request
|
||||
* if a video buffer is available.
|
||||
*
|
||||
* - USB interface setting selection: in response to a SET_INTERFACE request,
|
||||
* the handler will start streaming if a video buffer is available and if
|
||||
* video is not currently streaming.
|
||||
*
|
||||
* - V4L2 buffer queueing: the driver will start streaming if video is not
|
||||
* currently streaming.
|
||||
*
|
||||
* Race conditions between those 3 events might lead to deadlocks or other
|
||||
* nasty side effects.
|
||||
*
|
||||
* The "video currently streaming" condition can't be detected by the irqqueue
|
||||
* being empty, as a request can still be in flight. A separate "queue paused"
|
||||
* flag is thus needed.
|
||||
*
|
||||
* The paused flag will be set when we try to retrieve the irqqueue head if the
|
||||
* queue is empty, and cleared when we queue a buffer.
|
||||
*
|
||||
* The USB request completion handler will get the buffer at the irqqueue head
|
||||
* under protection of the queue spinlock. If the queue is empty, the streaming
|
||||
* paused flag will be set. Right after releasing the spinlock a userspace
|
||||
* application can queue a buffer. The flag will then cleared, and the ioctl
|
||||
* handler will restart the video stream.
|
||||
*/
|
||||
static void
|
||||
uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct uvc_video *video = req->context;
|
||||
struct uvc_buffer *buf;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
switch (req->status) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case -ESHUTDOWN:
|
||||
printk(KERN_INFO "VS request cancelled.\n");
|
||||
goto requeue;
|
||||
|
||||
default:
|
||||
printk(KERN_INFO "VS request completed with status %d.\n",
|
||||
req->status);
|
||||
goto requeue;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&video->queue.irqlock, flags);
|
||||
buf = uvc_queue_head(&video->queue);
|
||||
if (buf == NULL) {
|
||||
spin_unlock_irqrestore(&video->queue.irqlock, flags);
|
||||
goto requeue;
|
||||
}
|
||||
|
||||
video->encode(req, video, buf);
|
||||
|
||||
if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) {
|
||||
printk(KERN_INFO "Failed to queue request (%d).\n", ret);
|
||||
usb_ep_set_halt(ep);
|
||||
spin_unlock_irqrestore(&video->queue.irqlock, flags);
|
||||
goto requeue;
|
||||
}
|
||||
spin_unlock_irqrestore(&video->queue.irqlock, flags);
|
||||
|
||||
return;
|
||||
|
||||
requeue:
|
||||
spin_lock_irqsave(&video->req_lock, flags);
|
||||
list_add_tail(&req->list, &video->req_free);
|
||||
spin_unlock_irqrestore(&video->req_lock, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_video_free_requests(struct uvc_video *video)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
|
||||
if (video->req[i]) {
|
||||
usb_ep_free_request(video->ep, video->req[i]);
|
||||
video->req[i] = NULL;
|
||||
}
|
||||
|
||||
if (video->req_buffer[i]) {
|
||||
kfree(video->req_buffer[i]);
|
||||
video->req_buffer[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&video->req_free);
|
||||
video->req_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_video_alloc_requests(struct uvc_video *video)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
BUG_ON(video->req_size);
|
||||
|
||||
for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
|
||||
video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL);
|
||||
if (video->req_buffer[i] == NULL)
|
||||
goto error;
|
||||
|
||||
video->req[i] = usb_ep_alloc_request(video->ep, GFP_KERNEL);
|
||||
if (video->req[i] == NULL)
|
||||
goto error;
|
||||
|
||||
video->req[i]->buf = video->req_buffer[i];
|
||||
video->req[i]->length = 0;
|
||||
video->req[i]->dma = DMA_ADDR_INVALID;
|
||||
video->req[i]->complete = uvc_video_complete;
|
||||
video->req[i]->context = video;
|
||||
|
||||
list_add_tail(&video->req[i]->list, &video->req_free);
|
||||
}
|
||||
|
||||
video->req_size = video->ep->maxpacket;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uvc_video_free_requests(video);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Video streaming
|
||||
*/
|
||||
|
||||
/*
|
||||
* uvc_video_pump - Pump video data into the USB requests
|
||||
*
|
||||
* This function fills the available USB requests (listed in req_free) with
|
||||
* video data from the queued buffers.
|
||||
*/
|
||||
int
|
||||
uvc_video_pump(struct uvc_video *video)
|
||||
{
|
||||
struct usb_request *req;
|
||||
struct uvc_buffer *buf;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* FIXME TODO Race between uvc_video_pump and requests completion
|
||||
* handler ???
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
/* Retrieve the first available USB request, protected by the
|
||||
* request lock.
|
||||
*/
|
||||
spin_lock_irqsave(&video->req_lock, flags);
|
||||
if (list_empty(&video->req_free)) {
|
||||
spin_unlock_irqrestore(&video->req_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
req = list_first_entry(&video->req_free, struct usb_request,
|
||||
list);
|
||||
list_del(&req->list);
|
||||
spin_unlock_irqrestore(&video->req_lock, flags);
|
||||
|
||||
/* Retrieve the first available video buffer and fill the
|
||||
* request, protected by the video queue irqlock.
|
||||
*/
|
||||
spin_lock_irqsave(&video->queue.irqlock, flags);
|
||||
buf = uvc_queue_head(&video->queue);
|
||||
if (buf == NULL) {
|
||||
spin_unlock_irqrestore(&video->queue.irqlock, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
video->encode(req, video, buf);
|
||||
|
||||
/* Queue the USB request */
|
||||
if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) {
|
||||
printk(KERN_INFO "Failed to queue request (%d)\n", ret);
|
||||
usb_ep_set_halt(video->ep);
|
||||
spin_unlock_irqrestore(&video->queue.irqlock, flags);
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&video->queue.irqlock, flags);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&video->req_lock, flags);
|
||||
list_add_tail(&req->list, &video->req_free);
|
||||
spin_unlock_irqrestore(&video->req_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable or disable the video stream.
|
||||
*/
|
||||
int
|
||||
uvc_video_enable(struct uvc_video *video, int enable)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (video->ep == NULL) {
|
||||
printk(KERN_INFO "Video enable failed, device is "
|
||||
"uninitialized.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!enable) {
|
||||
for (i = 0; i < UVC_NUM_REQUESTS; ++i)
|
||||
usb_ep_dequeue(video->ep, video->req[i]);
|
||||
|
||||
uvc_video_free_requests(video);
|
||||
uvc_queue_enable(&video->queue, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = uvc_video_alloc_requests(video)) < 0)
|
||||
return ret;
|
||||
|
||||
if (video->max_payload_size) {
|
||||
video->encode = uvc_video_encode_bulk;
|
||||
video->payload_size = 0;
|
||||
} else
|
||||
video->encode = uvc_video_encode_isoc;
|
||||
|
||||
return uvc_video_pump(video);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the UVC video stream.
|
||||
*/
|
||||
int
|
||||
uvc_video_init(struct uvc_video *video)
|
||||
{
|
||||
INIT_LIST_HEAD(&video->req_free);
|
||||
spin_lock_init(&video->req_lock);
|
||||
|
||||
video->fcc = V4L2_PIX_FMT_YUYV;
|
||||
video->bpp = 16;
|
||||
video->width = 320;
|
||||
video->height = 240;
|
||||
video->imagesize = 320 * 240 * 2;
|
||||
|
||||
/* Initialize the video buffers queue. */
|
||||
uvc_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
399
drivers/usb/gadget/webcam.c
Normal file
399
drivers/usb/gadget/webcam.c
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
* webcam.c -- USB webcam 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/usb/video.h>
|
||||
|
||||
#include "f_uvc.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"
|
||||
|
||||
#include "f_uvc.c"
|
||||
#include "uvc_queue.c"
|
||||
#include "uvc_v4l2.c"
|
||||
#include "uvc_video.c"
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Device descriptor
|
||||
*/
|
||||
|
||||
#define WEBCAM_VENDOR_ID 0x1d6b /* Linux Foundation */
|
||||
#define WEBCAM_PRODUCT_ID 0x0102 /* Webcam A/V gadget */
|
||||
#define WEBCAM_DEVICE_BCD 0x0010 /* 0.10 */
|
||||
|
||||
static char webcam_vendor_label[] = "Linux Foundation";
|
||||
static char webcam_product_label[] = "Webcam gadget";
|
||||
static char webcam_config_label[] = "Video";
|
||||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
#define STRING_MANUFACTURER_IDX 0
|
||||
#define STRING_PRODUCT_IDX 1
|
||||
#define STRING_DESCRIPTION_IDX 2
|
||||
|
||||
static struct usb_string webcam_strings[] = {
|
||||
[STRING_MANUFACTURER_IDX].s = webcam_vendor_label,
|
||||
[STRING_PRODUCT_IDX].s = webcam_product_label,
|
||||
[STRING_DESCRIPTION_IDX].s = webcam_config_label,
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings webcam_stringtab = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = webcam_strings,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *webcam_device_strings[] = {
|
||||
&webcam_stringtab,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_device_descriptor webcam_device_descriptor = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_MISC,
|
||||
.bDeviceSubClass = 0x02,
|
||||
.bDeviceProtocol = 0x01,
|
||||
.bMaxPacketSize0 = 0, /* dynamic */
|
||||
.idVendor = cpu_to_le16(WEBCAM_VENDOR_ID),
|
||||
.idProduct = cpu_to_le16(WEBCAM_PRODUCT_ID),
|
||||
.bcdDevice = cpu_to_le16(WEBCAM_DEVICE_BCD),
|
||||
.iManufacturer = 0, /* dynamic */
|
||||
.iProduct = 0, /* dynamic */
|
||||
.iSerialNumber = 0, /* dynamic */
|
||||
.bNumConfigurations = 0, /* dynamic */
|
||||
};
|
||||
|
||||
DECLARE_UVC_HEADER_DESCRIPTOR(1);
|
||||
|
||||
static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
|
||||
.bLength = UVC_DT_HEADER_SIZE(1),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_HEADER,
|
||||
.bcdUVC = cpu_to_le16(0x0100),
|
||||
.wTotalLength = 0, /* dynamic */
|
||||
.dwClockFrequency = cpu_to_le32(48000000),
|
||||
.bInCollection = 0, /* dynamic */
|
||||
.baInterfaceNr[0] = 0, /* dynamic */
|
||||
};
|
||||
|
||||
static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
|
||||
.bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_INPUT_TERMINAL,
|
||||
.bTerminalID = 1,
|
||||
.wTerminalType = cpu_to_le16(0x0201),
|
||||
.bAssocTerminal = 0,
|
||||
.iTerminal = 0,
|
||||
.wObjectiveFocalLengthMin = cpu_to_le16(0),
|
||||
.wObjectiveFocalLengthMax = cpu_to_le16(0),
|
||||
.wOcularFocalLength = cpu_to_le16(0),
|
||||
.bControlSize = 3,
|
||||
.bmControls[0] = 2,
|
||||
.bmControls[1] = 0,
|
||||
.bmControls[2] = 0,
|
||||
};
|
||||
|
||||
static const struct uvc_processing_unit_descriptor uvc_processing = {
|
||||
.bLength = UVC_DT_PROCESSING_UNIT_SIZE(2),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_PROCESSING_UNIT,
|
||||
.bUnitID = 2,
|
||||
.bSourceID = 1,
|
||||
.wMaxMultiplier = cpu_to_le16(16*1024),
|
||||
.bControlSize = 2,
|
||||
.bmControls[0] = 1,
|
||||
.bmControls[1] = 0,
|
||||
.iProcessing = 0,
|
||||
};
|
||||
|
||||
static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
|
||||
.bLength = UVC_DT_OUTPUT_TERMINAL_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_OUTPUT_TERMINAL,
|
||||
.bTerminalID = 3,
|
||||
.wTerminalType = cpu_to_le16(0x0101),
|
||||
.bAssocTerminal = 0,
|
||||
.bSourceID = 2,
|
||||
.iTerminal = 0,
|
||||
};
|
||||
|
||||
DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
|
||||
|
||||
static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
|
||||
.bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_INPUT_HEADER,
|
||||
.bNumFormats = 2,
|
||||
.wTotalLength = 0, /* dynamic */
|
||||
.bEndpointAddress = 0, /* dynamic */
|
||||
.bmInfo = 0,
|
||||
.bTerminalLink = 3,
|
||||
.bStillCaptureMethod = 0,
|
||||
.bTriggerSupport = 0,
|
||||
.bTriggerUsage = 0,
|
||||
.bControlSize = 1,
|
||||
.bmaControls[0][0] = 0,
|
||||
.bmaControls[1][0] = 4,
|
||||
};
|
||||
|
||||
static const struct uvc_format_uncompressed uvc_format_yuv = {
|
||||
.bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_FORMAT_UNCOMPRESSED,
|
||||
.bFormatIndex = 1,
|
||||
.bNumFrameDescriptors = 2,
|
||||
.guidFormat =
|
||||
{ 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
|
||||
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
|
||||
.bBitsPerPixel = 16,
|
||||
.bDefaultFrameIndex = 1,
|
||||
.bAspectRatioX = 0,
|
||||
.bAspectRatioY = 0,
|
||||
.bmInterfaceFlags = 0,
|
||||
.bCopyProtect = 0,
|
||||
};
|
||||
|
||||
DECLARE_UVC_FRAME_UNCOMPRESSED(1);
|
||||
DECLARE_UVC_FRAME_UNCOMPRESSED(3);
|
||||
|
||||
static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
|
||||
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED,
|
||||
.bFrameIndex = 1,
|
||||
.bmCapabilities = 0,
|
||||
.wWidth = cpu_to_le16(640),
|
||||
.wHeight = cpu_to_le16(360),
|
||||
.dwMinBitRate = cpu_to_le32(18432000),
|
||||
.dwMaxBitRate = cpu_to_le32(55296000),
|
||||
.dwMaxVideoFrameBufferSize = cpu_to_le32(460800),
|
||||
.dwDefaultFrameInterval = cpu_to_le32(666666),
|
||||
.bFrameIntervalType = 3,
|
||||
.dwFrameInterval[0] = cpu_to_le32(666666),
|
||||
.dwFrameInterval[1] = cpu_to_le32(1000000),
|
||||
.dwFrameInterval[2] = cpu_to_le32(5000000),
|
||||
};
|
||||
|
||||
static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
|
||||
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED,
|
||||
.bFrameIndex = 2,
|
||||
.bmCapabilities = 0,
|
||||
.wWidth = cpu_to_le16(1280),
|
||||
.wHeight = cpu_to_le16(720),
|
||||
.dwMinBitRate = cpu_to_le32(29491200),
|
||||
.dwMaxBitRate = cpu_to_le32(29491200),
|
||||
.dwMaxVideoFrameBufferSize = cpu_to_le32(1843200),
|
||||
.dwDefaultFrameInterval = cpu_to_le32(5000000),
|
||||
.bFrameIntervalType = 1,
|
||||
.dwFrameInterval[0] = cpu_to_le32(5000000),
|
||||
};
|
||||
|
||||
static const struct uvc_format_mjpeg uvc_format_mjpg = {
|
||||
.bLength = UVC_DT_FORMAT_MJPEG_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_FORMAT_MJPEG,
|
||||
.bFormatIndex = 2,
|
||||
.bNumFrameDescriptors = 2,
|
||||
.bmFlags = 0,
|
||||
.bDefaultFrameIndex = 1,
|
||||
.bAspectRatioX = 0,
|
||||
.bAspectRatioY = 0,
|
||||
.bmInterfaceFlags = 0,
|
||||
.bCopyProtect = 0,
|
||||
};
|
||||
|
||||
DECLARE_UVC_FRAME_MJPEG(1);
|
||||
DECLARE_UVC_FRAME_MJPEG(3);
|
||||
|
||||
static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
|
||||
.bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_FRAME_MJPEG,
|
||||
.bFrameIndex = 1,
|
||||
.bmCapabilities = 0,
|
||||
.wWidth = cpu_to_le16(640),
|
||||
.wHeight = cpu_to_le16(360),
|
||||
.dwMinBitRate = cpu_to_le32(18432000),
|
||||
.dwMaxBitRate = cpu_to_le32(55296000),
|
||||
.dwMaxVideoFrameBufferSize = cpu_to_le32(460800),
|
||||
.dwDefaultFrameInterval = cpu_to_le32(666666),
|
||||
.bFrameIntervalType = 3,
|
||||
.dwFrameInterval[0] = cpu_to_le32(666666),
|
||||
.dwFrameInterval[1] = cpu_to_le32(1000000),
|
||||
.dwFrameInterval[2] = cpu_to_le32(5000000),
|
||||
};
|
||||
|
||||
static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
|
||||
.bLength = UVC_DT_FRAME_MJPEG_SIZE(1),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_FRAME_MJPEG,
|
||||
.bFrameIndex = 2,
|
||||
.bmCapabilities = 0,
|
||||
.wWidth = cpu_to_le16(1280),
|
||||
.wHeight = cpu_to_le16(720),
|
||||
.dwMinBitRate = cpu_to_le32(29491200),
|
||||
.dwMaxBitRate = cpu_to_le32(29491200),
|
||||
.dwMaxVideoFrameBufferSize = cpu_to_le32(1843200),
|
||||
.dwDefaultFrameInterval = cpu_to_le32(5000000),
|
||||
.bFrameIntervalType = 1,
|
||||
.dwFrameInterval[0] = cpu_to_le32(5000000),
|
||||
};
|
||||
|
||||
static const struct uvc_color_matching_descriptor uvc_color_matching = {
|
||||
.bLength = UVC_DT_COLOR_MATCHING_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = UVC_DT_COLOR_MATCHING,
|
||||
.bColorPrimaries = 1,
|
||||
.bTransferCharacteristics = 1,
|
||||
.bMatrixCoefficients = 4,
|
||||
};
|
||||
|
||||
static const struct uvc_descriptor_header * const uvc_control_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_control_header,
|
||||
(const struct uvc_descriptor_header *) &uvc_camera_terminal,
|
||||
(const struct uvc_descriptor_header *) &uvc_processing,
|
||||
(const struct uvc_descriptor_header *) &uvc_output_terminal,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_input_header,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_yuv,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_color_matching,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_input_header,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_yuv,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_color_matching,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* USB configuration
|
||||
*/
|
||||
|
||||
static int __init
|
||||
webcam_config_bind(struct usb_configuration *c)
|
||||
{
|
||||
return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls,
|
||||
uvc_hs_streaming_cls);
|
||||
}
|
||||
|
||||
static struct usb_configuration webcam_config_driver = {
|
||||
.label = webcam_config_label,
|
||||
.bind = webcam_config_bind,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 0, /* dynamic */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
.bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
|
||||
};
|
||||
|
||||
static int /* __init_or_exit */
|
||||
webcam_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
webcam_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string contents
|
||||
* can be overridden by the composite_dev glue.
|
||||
*/
|
||||
if ((ret = usb_string_id(cdev)) < 0)
|
||||
goto error;
|
||||
webcam_strings[STRING_MANUFACTURER_IDX].id = ret;
|
||||
webcam_device_descriptor.iManufacturer = ret;
|
||||
|
||||
if ((ret = usb_string_id(cdev)) < 0)
|
||||
goto error;
|
||||
webcam_strings[STRING_PRODUCT_IDX].id = ret;
|
||||
webcam_device_descriptor.iProduct = ret;
|
||||
|
||||
if ((ret = usb_string_id(cdev)) < 0)
|
||||
goto error;
|
||||
webcam_strings[STRING_DESCRIPTION_IDX].id = ret;
|
||||
webcam_config_driver.iConfiguration = ret;
|
||||
|
||||
/* Register our configuration. */
|
||||
if ((ret = usb_add_config(cdev, &webcam_config_driver)) < 0)
|
||||
goto error;
|
||||
|
||||
INFO(cdev, "Webcam Video Gadget\n");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
webcam_unbind(cdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Driver
|
||||
*/
|
||||
|
||||
static struct usb_composite_driver webcam_driver = {
|
||||
.name = "g_webcam",
|
||||
.dev = &webcam_device_descriptor,
|
||||
.strings = webcam_device_strings,
|
||||
.bind = webcam_bind,
|
||||
.unbind = webcam_unbind,
|
||||
};
|
||||
|
||||
static int __init
|
||||
webcam_init(void)
|
||||
{
|
||||
return usb_composite_register(&webcam_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
webcam_cleanup(void)
|
||||
{
|
||||
usb_composite_unregister(&webcam_driver);
|
||||
}
|
||||
|
||||
module_init(webcam_init);
|
||||
module_exit(webcam_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Laurent Pinchart");
|
||||
MODULE_DESCRIPTION("Webcam Video Gadget");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.1.0");
|
||||
|
||||
|
|
@ -207,6 +207,21 @@ config USB_OHCI_HCD
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ohci-hcd.
|
||||
|
||||
config USB_OHCI_HCD_OMAP1
|
||||
bool "OHCI support for OMAP1/2 chips"
|
||||
depends on USB_OHCI_HCD && (ARCH_OMAP1 || ARCH_OMAP2)
|
||||
default y
|
||||
---help---
|
||||
Enables support for the OHCI controller on OMAP1/2 chips.
|
||||
|
||||
config USB_OHCI_HCD_OMAP3
|
||||
bool "OHCI support for OMAP3 and later chips"
|
||||
depends on USB_OHCI_HCD && (ARCH_OMAP3 || ARCH_OMAP4)
|
||||
default y
|
||||
---help---
|
||||
Enables support for the on-chip OHCI controller on
|
||||
OMAP3 and later chips.
|
||||
|
||||
config USB_OHCI_HCD_PPC_SOC
|
||||
bool "OHCI support for on-chip PPC USB controller"
|
||||
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,15 @@ static void au1xxx_stop_ehc(void)
|
|||
au_sync();
|
||||
}
|
||||
|
||||
static int au1xxx_ehci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int ret = ehci_init(hcd);
|
||||
|
||||
ehci->need_io_watchdog = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hc_driver ehci_au1xxx_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Au1xxx EHCI",
|
||||
|
|
@ -86,7 +95,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
|
|||
* FIXME -- ehci_init() doesn't do enough here.
|
||||
* See ehci-ppc-soc for a complete implementation.
|
||||
*/
|
||||
.reset = ehci_init,
|
||||
.reset = au1xxx_ehci_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
|
@ -215,26 +224,17 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
|||
msleep(10);
|
||||
|
||||
/* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible, bail out if RH has been resumed. Use
|
||||
* the spinlock to properly synchronize with possible pending
|
||||
* RH suspend or resume activity.
|
||||
*
|
||||
* This is still racy as hcd->state is manipulated outside of
|
||||
* any locks =P But that will be a different fix.
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
if (hcd->state != HC_STATE_SUSPENDED) {
|
||||
rc = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
ehci_prepare_ports_for_controller_suspend(ehci);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
au1xxx_stop_ehc();
|
||||
|
||||
bail:
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
// could save FLADJ in case of Vaux power loss
|
||||
|
|
@ -264,6 +264,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
|
|||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ static int ehci_fsl_drv_suspend(struct device *dev)
|
|||
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd));
|
||||
if (!fsl_deep_sleep())
|
||||
return 0;
|
||||
|
||||
|
|
@ -327,6 +328,7 @@ static int ehci_fsl_drv_resume(struct device *dev)
|
|||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!fsl_deep_sleep())
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,13 +31,12 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "../core/hcd.h"
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
|
|
|||
|
|
@ -106,12 +106,75 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
|
|||
ehci->owned_ports = 0;
|
||||
}
|
||||
|
||||
static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
bool suspending)
|
||||
{
|
||||
int port;
|
||||
u32 temp;
|
||||
|
||||
/* If remote wakeup is enabled for the root hub but disabled
|
||||
* for the controller, we must adjust all the port wakeup flags
|
||||
* when the controller is suspended or resumed. In all other
|
||||
* cases they don't need to be changed.
|
||||
*/
|
||||
if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup ||
|
||||
device_may_wakeup(ehci_to_hcd(ehci)->self.controller))
|
||||
return;
|
||||
|
||||
/* clear phy low-power mode before changing wakeup flags */
|
||||
if (ehci->has_hostpc) {
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * port);
|
||||
temp = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
|
||||
}
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *reg = &ehci->regs->port_status[port];
|
||||
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
|
||||
u32 t2 = t1 & ~PORT_WAKE_BITS;
|
||||
|
||||
/* If we are suspending the controller, clear the flags.
|
||||
* If we are resuming the controller, set the wakeup flags.
|
||||
*/
|
||||
if (!suspending) {
|
||||
if (t1 & PORT_CONNECT)
|
||||
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
|
||||
else
|
||||
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
|
||||
}
|
||||
ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
|
||||
port + 1, t1, t2);
|
||||
ehci_writel(ehci, t2, reg);
|
||||
}
|
||||
|
||||
/* enter phy low-power mode again */
|
||||
if (ehci->has_hostpc) {
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * port);
|
||||
temp = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ehci_bus_suspend (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||
int port;
|
||||
int mask;
|
||||
u32 __iomem *hostpc_reg = NULL;
|
||||
int changed;
|
||||
|
||||
ehci_dbg(ehci, "suspend root hub\n");
|
||||
|
||||
|
|
@ -155,15 +218,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
|||
*/
|
||||
ehci->bus_suspended = 0;
|
||||
ehci->owned_ports = 0;
|
||||
changed = 0;
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *reg = &ehci->regs->port_status [port];
|
||||
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
|
||||
u32 t2 = t1;
|
||||
u32 t2 = t1 & ~PORT_WAKE_BITS;
|
||||
|
||||
if (ehci->has_hostpc)
|
||||
hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
|
||||
+ HOSTPC0 + 4 * (port & 0xff));
|
||||
/* keep track of which ports we suspend */
|
||||
if (t1 & PORT_OWNER)
|
||||
set_bit(port, &ehci->owned_ports);
|
||||
|
|
@ -172,40 +233,45 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
|||
set_bit(port, &ehci->bus_suspended);
|
||||
}
|
||||
|
||||
/* enable remote wakeup on all ports */
|
||||
/* enable remote wakeup on all ports, if told to do so */
|
||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||
/* only enable appropriate wake bits, otherwise the
|
||||
* hardware can not go phy low power mode. If a race
|
||||
* condition happens here(connection change during bits
|
||||
* set), the port change detection will finally fix it.
|
||||
*/
|
||||
if (t1 & PORT_CONNECT) {
|
||||
if (t1 & PORT_CONNECT)
|
||||
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
|
||||
t2 &= ~PORT_WKCONN_E;
|
||||
} else {
|
||||
else
|
||||
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
|
||||
t2 &= ~PORT_WKDISC_E;
|
||||
}
|
||||
} else
|
||||
t2 &= ~PORT_WAKE_BITS;
|
||||
}
|
||||
|
||||
if (t1 != t2) {
|
||||
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
|
||||
port + 1, t1, t2);
|
||||
ehci_writel(ehci, t2, reg);
|
||||
if (hostpc_reg) {
|
||||
u32 t3;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
msleep(5);/* 5ms for HCD enter low pwr mode */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
t3 = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
|
||||
t3 = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
|
||||
if (changed && ehci->has_hostpc) {
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
msleep(5); /* 5 ms for HCD to enter low-power mode */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
u32 t3;
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * port);
|
||||
t3 = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
|
||||
t3 = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_dbg(ehci, "Port %d phy low-power mode %s\n",
|
||||
port, (t3 & HOSTPC_PHCD) ?
|
||||
"succeeded" : "failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -291,6 +357,25 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
|||
msleep(8);
|
||||
spin_lock_irq(&ehci->lock);
|
||||
|
||||
/* clear phy low-power mode before resume */
|
||||
if (ehci->bus_suspended && ehci->has_hostpc) {
|
||||
i = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (i--) {
|
||||
if (test_bit(i, &ehci->bus_suspended)) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * i);
|
||||
temp = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp & ~HOSTPC_PHCD,
|
||||
hostpc_reg);
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
msleep(5);
|
||||
spin_lock_irq(&ehci->lock);
|
||||
}
|
||||
|
||||
/* manually resume the ports we suspended during bus_suspend() */
|
||||
i = HCS_N_PORTS (ehci->hcs_params);
|
||||
while (i--) {
|
||||
|
|
@ -659,7 +744,7 @@ static int ehci_hub_control (
|
|||
* Even if OWNER is set, so the port is owned by the
|
||||
* companion controller, khubd needs to be able to clear
|
||||
* the port-change status bits (especially
|
||||
* USB_PORT_FEAT_C_CONNECTION).
|
||||
* USB_PORT_STAT_C_CONNECTION).
|
||||
*/
|
||||
|
||||
switch (wValue) {
|
||||
|
|
@ -675,16 +760,25 @@ static int ehci_hub_control (
|
|||
goto error;
|
||||
if (ehci->no_selective_suspend)
|
||||
break;
|
||||
if (temp & PORT_SUSPEND) {
|
||||
if ((temp & PORT_PE) == 0)
|
||||
goto error;
|
||||
/* resume signaling for 20 msec */
|
||||
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
||||
ehci_writel(ehci, temp | PORT_RESUME,
|
||||
status_reg);
|
||||
ehci->reset_done [wIndex] = jiffies
|
||||
+ msecs_to_jiffies (20);
|
||||
if (!(temp & PORT_SUSPEND))
|
||||
break;
|
||||
if ((temp & PORT_PE) == 0)
|
||||
goto error;
|
||||
|
||||
/* clear phy low-power mode before resume */
|
||||
if (hostpc_reg) {
|
||||
temp1 = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
|
||||
hostpc_reg);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
msleep(5);/* wait to leave low-power mode */
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
}
|
||||
/* resume signaling for 20 msec */
|
||||
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
||||
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
|
||||
ehci->reset_done[wIndex] = jiffies
|
||||
+ msecs_to_jiffies(20);
|
||||
break;
|
||||
case USB_PORT_FEAT_C_SUSPEND:
|
||||
clear_bit(wIndex, &ehci->port_c_suspend);
|
||||
|
|
@ -729,12 +823,12 @@ static int ehci_hub_control (
|
|||
|
||||
// wPortChange bits
|
||||
if (temp & PORT_CSC)
|
||||
status |= 1 << USB_PORT_FEAT_C_CONNECTION;
|
||||
status |= USB_PORT_STAT_C_CONNECTION << 16;
|
||||
if (temp & PORT_PEC)
|
||||
status |= 1 << USB_PORT_FEAT_C_ENABLE;
|
||||
status |= USB_PORT_STAT_C_ENABLE << 16;
|
||||
|
||||
if ((temp & PORT_OCC) && !ignore_oc){
|
||||
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
|
||||
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
|
||||
|
||||
/*
|
||||
* Hubs should disable port power on over-current.
|
||||
|
|
@ -791,7 +885,7 @@ static int ehci_hub_control (
|
|||
if ((temp & PORT_RESET)
|
||||
&& time_after_eq(jiffies,
|
||||
ehci->reset_done[wIndex])) {
|
||||
status |= 1 << USB_PORT_FEAT_C_RESET;
|
||||
status |= USB_PORT_STAT_C_RESET << 16;
|
||||
ehci->reset_done [wIndex] = 0;
|
||||
|
||||
/* force reset to complete */
|
||||
|
|
@ -833,7 +927,7 @@ static int ehci_hub_control (
|
|||
*/
|
||||
|
||||
if (temp & PORT_CONNECT) {
|
||||
status |= 1 << USB_PORT_FEAT_CONNECTION;
|
||||
status |= USB_PORT_STAT_CONNECTION;
|
||||
// status may be from integrated TT
|
||||
if (ehci->has_hostpc) {
|
||||
temp1 = ehci_readl(ehci, hostpc_reg);
|
||||
|
|
@ -842,11 +936,11 @@ static int ehci_hub_control (
|
|||
status |= ehci_port_speed(ehci, temp);
|
||||
}
|
||||
if (temp & PORT_PE)
|
||||
status |= 1 << USB_PORT_FEAT_ENABLE;
|
||||
status |= USB_PORT_STAT_ENABLE;
|
||||
|
||||
/* maybe the port was unsuspended without our knowledge */
|
||||
if (temp & (PORT_SUSPEND|PORT_RESUME)) {
|
||||
status |= 1 << USB_PORT_FEAT_SUSPEND;
|
||||
status |= USB_PORT_STAT_SUSPEND;
|
||||
} else if (test_bit(wIndex, &ehci->suspended_ports)) {
|
||||
clear_bit(wIndex, &ehci->suspended_ports);
|
||||
ehci->reset_done[wIndex] = 0;
|
||||
|
|
@ -855,13 +949,13 @@ static int ehci_hub_control (
|
|||
}
|
||||
|
||||
if (temp & PORT_OC)
|
||||
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
|
||||
status |= USB_PORT_STAT_OVERCURRENT;
|
||||
if (temp & PORT_RESET)
|
||||
status |= 1 << USB_PORT_FEAT_RESET;
|
||||
status |= USB_PORT_STAT_RESET;
|
||||
if (temp & PORT_POWER)
|
||||
status |= 1 << USB_PORT_FEAT_POWER;
|
||||
status |= USB_PORT_STAT_POWER;
|
||||
if (test_bit(wIndex, &ehci->port_c_suspend))
|
||||
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
|
||||
status |= USB_PORT_STAT_C_SUSPEND << 16;
|
||||
|
||||
#ifndef VERBOSE_DEBUG
|
||||
if (status & ~0xffff) /* only if wPortChange is interesting */
|
||||
|
|
|
|||
|
|
@ -116,6 +116,8 @@
|
|||
#define OMAP_UHH_DEBUG_CSR (0x44)
|
||||
|
||||
/* EHCI Register Set */
|
||||
#define EHCI_INSNREG04 (0xA0)
|
||||
#define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5)
|
||||
#define EHCI_INSNREG05_ULPI (0xA4)
|
||||
#define EHCI_INSNREG05_ULPI_CONTROL_SHIFT 31
|
||||
#define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT 24
|
||||
|
|
@ -352,8 +354,8 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
|
|||
reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
|
||||
|
||||
/* Bypass the TLL module for PHY mode operation */
|
||||
if (omap_rev() <= OMAP3430_REV_ES2_1) {
|
||||
dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1 \n");
|
||||
if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
|
||||
dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n");
|
||||
if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
|
||||
(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
|
||||
(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
|
||||
|
|
@ -382,6 +384,18 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
|
|||
dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
|
||||
|
||||
|
||||
/*
|
||||
* An undocumented "feature" in the OMAP3 EHCI controller,
|
||||
* causes suspended ports to be taken out of suspend when
|
||||
* the USBCMD.Run/Stop bit is cleared (for example when
|
||||
* we do ehci_bus_suspend).
|
||||
* This breaks suspend-resume if the root-hub is allowed
|
||||
* to suspend. Writing 1 to this undocumented register bit
|
||||
* disables this feature and restores normal behavior.
|
||||
*/
|
||||
ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04,
|
||||
EHCI_INSNREG04_DISABLE_UNSUSPEND);
|
||||
|
||||
if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
|
||||
(omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
|
||||
(omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {
|
||||
|
|
@ -659,6 +673,9 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
|||
goto err_add_hcd;
|
||||
}
|
||||
|
||||
/* root ports should always stay powered */
|
||||
ehci_port_power(omap->ehci, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_hcd:
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
|||
return retval;
|
||||
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_NEC:
|
||||
ehci->need_io_watchdog = 0;
|
||||
break;
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
ehci->need_io_watchdog = 0;
|
||||
if (pdev->device == 0x27cc) {
|
||||
|
|
@ -284,23 +287,15 @@ static int ehci_pci_suspend(struct usb_hcd *hcd)
|
|||
msleep(10);
|
||||
|
||||
/* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible, bail out if RH has been resumed. Use
|
||||
* the spinlock to properly synchronize with possible pending
|
||||
* RH suspend or resume activity.
|
||||
*
|
||||
* This is still racy as hcd->state is manipulated outside of
|
||||
* any locks =P But that will be a different fix.
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
if (hcd->state != HC_STATE_SUSPENDED) {
|
||||
rc = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
ehci_prepare_ports_for_controller_suspend(ehci);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
bail:
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
|
||||
// could save FLADJ in case of Vaux power loss
|
||||
|
|
@ -330,6 +325,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
|||
!hibernated) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ qh_urb_transaction (
|
|||
*/
|
||||
i = urb->num_sgs;
|
||||
if (len > 0 && i > 0) {
|
||||
sg = urb->sg->sg;
|
||||
sg = urb->sg;
|
||||
buf = sg_dma_address(sg);
|
||||
|
||||
/* urb->transfer_buffer_length may be smaller than the
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue