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: (97 commits) USB: qcserial: add device id for HP devices USB: isp1760: Add a delay before reading the SKIPMAP registers in isp1760-hcd.c USB: allow malformed LANGID descriptors USB: pxa27x_udc: typo fixes and code cleanups USB: gadget: gadget zero uses new suspend/resume hooks USB: gadget: composite device-level suspend/resume hooks USB: r8a66597-hcd: suspend/resume support USB: more u32 conversion after transfer_buffer_length and actual_length USB: Fix cp2101 USB serial device driver termios functions for console use USB: CP2101 New Device ID USB: ipaq: handle 4 endpoint devices USB: S3C: Move usb-control.h to platform include USB: ohci-hcd: Add ARCH_S3C24XX to the ohci-s3c2410.c glue USB: pedantic: spelling correction in comment for ch9.h USB: host: fix sparse warning: Using plain integer as NULL pointer USB: ohci-s3c2410: fix name of bus clock USB: ohci-s3c2410: remove <mach/hardware.h> include USB: serial: rename cp2101 driver to cp210x USB: CP2101 Reduce Error Logging USB: CP2101 Support AN205 baud rates ...
This commit is contained in:
Коммит
61a091827e
|
@ -229,16 +229,26 @@ struct usbmon_packet {
|
|||
int status; /* 28: */
|
||||
unsigned int length; /* 32: Length of data (submitted or actual) */
|
||||
unsigned int len_cap; /* 36: Delivered length */
|
||||
unsigned char setup[8]; /* 40: Only for Control 'S' */
|
||||
}; /* 48 bytes total */
|
||||
union { /* 40: */
|
||||
unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
|
||||
struct iso_rec { /* Only for ISO */
|
||||
int error_count;
|
||||
int numdesc;
|
||||
} iso;
|
||||
} s;
|
||||
int interval; /* 48: Only for Interrupt and ISO */
|
||||
int start_frame; /* 52: For ISO */
|
||||
unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */
|
||||
unsigned int ndesc; /* 60: Actual number of ISO descriptors */
|
||||
}; /* 64 total length */
|
||||
|
||||
These events can be received from a character device by reading with read(2),
|
||||
with an ioctl(2), or by accessing the buffer with mmap.
|
||||
with an ioctl(2), or by accessing the buffer with mmap. However, read(2)
|
||||
only returns first 48 bytes for compatibility reasons.
|
||||
|
||||
The character device is usually called /dev/usbmonN, where N is the USB bus
|
||||
number. Number zero (/dev/usbmon0) is special and means "all buses".
|
||||
However, this feature is not implemented yet. Note that specific naming
|
||||
policy is set by your Linux distribution.
|
||||
Note that specific naming policy is set by your Linux distribution.
|
||||
|
||||
If you create /dev/usbmon0 by hand, make sure that it is owned by root
|
||||
and has mode 0600. Otherwise, unpriviledged users will be able to snoop
|
||||
|
@ -279,9 +289,10 @@ size is out of [unspecified] bounds for this kernel, the call fails with
|
|||
This call returns the current size of the buffer in bytes.
|
||||
|
||||
MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
|
||||
MON_IOCX_GETX, defined as _IOW(MON_IOC_MAGIC, 10, struct mon_get_arg)
|
||||
|
||||
This call waits for events to arrive if none were in the kernel buffer,
|
||||
then returns the first event. Its argument is a pointer to the following
|
||||
These calls wait for events to arrive if none were in the kernel buffer,
|
||||
then return the first event. The argument is a pointer to the following
|
||||
structure:
|
||||
|
||||
struct mon_get_arg {
|
||||
|
@ -294,6 +305,8 @@ Before the call, hdr, data, and alloc should be filled. Upon return, the area
|
|||
pointed by hdr contains the next event structure, and the data buffer contains
|
||||
the data, if any. The event is removed from the kernel buffer.
|
||||
|
||||
The MON_IOCX_GET copies 48 bytes, MON_IOCX_GETX copies 64 bytes.
|
||||
|
||||
MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
|
||||
|
||||
This ioctl is primarily used when the application accesses the buffer
|
||||
|
|
|
@ -29,13 +29,14 @@
|
|||
|
||||
#include <mach/bast-map.h>
|
||||
#include <mach/bast-irq.h>
|
||||
#include <mach/usb-control.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <plat/usb-control.h>
|
||||
#include <plat/devs.h>
|
||||
|
||||
#include "usb-simtec.h"
|
||||
|
||||
/* control power and monitor over-current events on various Simtec
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* arch/arm/mach-s3c2410/include/mach/usb-control.h
|
||||
/* arch/arm/plat-s3c/include/plat/usb-control.h
|
||||
*
|
||||
* Copyright (c) 2004 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C2410 - usb port information
|
||||
* S3C - USB host port information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_USBCONTROL_H
|
||||
#define __ASM_ARCH_USBCONTROL_H "arch/arm/mach-s3c2410/include/mach/usb-control.h"
|
||||
#define __ASM_ARCH_USBCONTROL_H
|
||||
|
||||
#define S3C_HCDFLG_USED (1)
|
||||
|
|
@ -391,7 +391,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum);
|
|||
*/
|
||||
#ifdef CONFIG_USB_LIBUSUAL
|
||||
|
||||
#define ub_usb_ids storage_usb_ids
|
||||
#define ub_usb_ids usb_storage_usb_ids
|
||||
#else
|
||||
|
||||
static struct usb_device_id ub_usb_ids[] = {
|
||||
|
@ -2146,10 +2146,9 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
|
|||
ep = &altsetting->endpoint[i].desc;
|
||||
|
||||
/* Is it a BULK endpoint? */
|
||||
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||
== USB_ENDPOINT_XFER_BULK) {
|
||||
if (usb_endpoint_xfer_bulk(ep)) {
|
||||
/* BULK in or out? */
|
||||
if (ep->bEndpointAddress & USB_DIR_IN) {
|
||||
if (usb_endpoint_dir_in(ep)) {
|
||||
if (ep_in == NULL)
|
||||
ep_in = ep;
|
||||
} else {
|
||||
|
@ -2168,9 +2167,9 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
|
|||
sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0);
|
||||
sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0);
|
||||
sc->send_bulk_pipe = usb_sndbulkpipe(dev,
|
||||
ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
|
||||
usb_endpoint_num(ep_out));
|
||||
sc->recv_bulk_pipe = usb_rcvbulkpipe(dev,
|
||||
ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
|
||||
usb_endpoint_num(ep_in));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ obj-$(CONFIG_USB_SL811_HCD) += host/
|
|||
obj-$(CONFIG_USB_U132_HCD) += host/
|
||||
obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
||||
obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP1760_HCD) += host/
|
||||
|
||||
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
|
||||
|
||||
|
|
|
@ -880,16 +880,19 @@ static int usblp_wwait(struct usblp *usblp, int nonblock)
|
|||
if (rc <= 0)
|
||||
break;
|
||||
|
||||
if (usblp->flags & LP_ABORT) {
|
||||
if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
|
||||
if (schedule_timeout(msecs_to_jiffies(1500)) == 0) {
|
||||
if (usblp->flags & LP_ABORT) {
|
||||
err = usblp_check_status(usblp, err);
|
||||
if (err == 1) { /* Paper out */
|
||||
rc = -ENOSPC;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Prod the printer, Gentoo#251237. */
|
||||
mutex_lock(&usblp->mut);
|
||||
usblp_read_status(usblp, usblp->statusbuf);
|
||||
mutex_unlock(&usblp->mut);
|
||||
}
|
||||
} else {
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
|
|
@ -187,7 +187,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
|
|||
}
|
||||
|
||||
/* this isn't checking for illegal values */
|
||||
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
|
||||
switch (usb_endpoint_type(desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
type = "Ctrl";
|
||||
if (speed == USB_SPEED_HIGH) /* uframes per NAK */
|
||||
|
|
|
@ -104,7 +104,7 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
|
|||
|
||||
#define MAX_USBFS_BUFFER_SIZE 16384
|
||||
|
||||
static inline int connected(struct dev_state *ps)
|
||||
static int connected(struct dev_state *ps)
|
||||
{
|
||||
return (!list_empty(&ps->list) &&
|
||||
ps->dev->state != USB_STATE_NOTATTACHED);
|
||||
|
@ -248,7 +248,7 @@ static void free_async(struct async *as)
|
|||
kfree(as);
|
||||
}
|
||||
|
||||
static inline void async_newpending(struct async *as)
|
||||
static void async_newpending(struct async *as)
|
||||
{
|
||||
struct dev_state *ps = as->ps;
|
||||
unsigned long flags;
|
||||
|
@ -258,7 +258,7 @@ static inline void async_newpending(struct async *as)
|
|||
spin_unlock_irqrestore(&ps->lock, flags);
|
||||
}
|
||||
|
||||
static inline void async_removepending(struct async *as)
|
||||
static void async_removepending(struct async *as)
|
||||
{
|
||||
struct dev_state *ps = as->ps;
|
||||
unsigned long flags;
|
||||
|
@ -268,7 +268,7 @@ static inline void async_removepending(struct async *as)
|
|||
spin_unlock_irqrestore(&ps->lock, flags);
|
||||
}
|
||||
|
||||
static inline struct async *async_getcompleted(struct dev_state *ps)
|
||||
static struct async *async_getcompleted(struct dev_state *ps)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct async *as = NULL;
|
||||
|
@ -283,7 +283,7 @@ static inline struct async *async_getcompleted(struct dev_state *ps)
|
|||
return as;
|
||||
}
|
||||
|
||||
static inline struct async *async_getpending(struct dev_state *ps,
|
||||
static struct async *async_getpending(struct dev_state *ps,
|
||||
void __user *userurb)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -302,7 +302,7 @@ static inline struct async *async_getpending(struct dev_state *ps,
|
|||
|
||||
static void snoop_urb(struct urb *urb, void __user *userurb)
|
||||
{
|
||||
int j;
|
||||
unsigned j;
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
|
||||
if (!usbfs_snoop)
|
||||
|
@ -311,9 +311,9 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
|
|||
dev_info(&urb->dev->dev, "direction=%s\n",
|
||||
usb_urb_dir_in(urb) ? "IN" : "OUT");
|
||||
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
|
||||
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
|
||||
dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n",
|
||||
urb->transfer_buffer_length);
|
||||
dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length);
|
||||
dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length);
|
||||
dev_info(&urb->dev->dev, "data: ");
|
||||
for (j = 0; j < urb->transfer_buffer_length; ++j)
|
||||
printk("%02x ", data[j]);
|
||||
|
@ -376,7 +376,7 @@ static void destroy_async_on_interface(struct dev_state *ps,
|
|||
destroy_async(ps, &hitlist);
|
||||
}
|
||||
|
||||
static inline void destroy_all_async(struct dev_state *ps)
|
||||
static void destroy_all_async(struct dev_state *ps)
|
||||
{
|
||||
destroy_async(ps, &ps->async_pending);
|
||||
}
|
||||
|
@ -525,7 +525,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ps->dev->state != USB_STATE_ADDRESS
|
||||
if (ps->dev->state != USB_STATE_UNAUTHENTICATED
|
||||
&& ps->dev->state != USB_STATE_ADDRESS
|
||||
&& ps->dev->state != USB_STATE_CONFIGURED)
|
||||
return -EHOSTUNREACH;
|
||||
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
|
||||
|
|
|
@ -66,7 +66,7 @@ static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
|
|||
struct ep_device *ep = to_ep_device(dev);
|
||||
char *type = "unknown";
|
||||
|
||||
switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
|
||||
switch (usb_endpoint_type(ep->desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
type = "Control";
|
||||
break;
|
||||
|
@ -94,7 +94,7 @@ static ssize_t show_ep_interval(struct device *dev,
|
|||
|
||||
in = (ep->desc->bEndpointAddress & USB_DIR_IN);
|
||||
|
||||
switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
|
||||
switch (usb_endpoint_type(ep->desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
|
||||
interval = ep->desc->bInterval;
|
||||
|
@ -131,10 +131,9 @@ static ssize_t show_ep_direction(struct device *dev,
|
|||
struct ep_device *ep = to_ep_device(dev);
|
||||
char *direction;
|
||||
|
||||
if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
|
||||
USB_ENDPOINT_XFER_CONTROL)
|
||||
if (usb_endpoint_xfer_control(ep->desc))
|
||||
direction = "both";
|
||||
else if (ep->desc->bEndpointAddress & USB_DIR_IN)
|
||||
else if (usb_endpoint_dir_in(ep->desc))
|
||||
direction = "in";
|
||||
else
|
||||
direction = "out";
|
||||
|
|
|
@ -279,9 +279,9 @@ static const u8 hs_rh_config_descriptor [] = {
|
|||
* helper routine for returning string descriptors in UTF-16LE
|
||||
* input can actually be ISO-8859-1; ASCII is its 7-bit subset
|
||||
*/
|
||||
static int ascii2utf (char *s, u8 *utf, int utfmax)
|
||||
static unsigned ascii2utf(char *s, u8 *utf, int utfmax)
|
||||
{
|
||||
int retval;
|
||||
unsigned retval;
|
||||
|
||||
for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
|
||||
*utf++ = *s++;
|
||||
|
@ -304,19 +304,15 @@ static int ascii2utf (char *s, u8 *utf, int utfmax)
|
|||
* Produces either a manufacturer, product or serial number string for the
|
||||
* virtual root hub device.
|
||||
*/
|
||||
static int rh_string (
|
||||
int id,
|
||||
struct usb_hcd *hcd,
|
||||
u8 *data,
|
||||
int len
|
||||
) {
|
||||
static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len)
|
||||
{
|
||||
char buf [100];
|
||||
|
||||
// language ids
|
||||
if (id == 0) {
|
||||
buf[0] = 4; buf[1] = 3; /* 4 bytes string data */
|
||||
buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */
|
||||
len = min (len, 4);
|
||||
len = min_t(unsigned, len, 4);
|
||||
memcpy (data, buf, len);
|
||||
return len;
|
||||
|
||||
|
@ -332,10 +328,7 @@ static int rh_string (
|
|||
} else if (id == 3) {
|
||||
snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
|
||||
init_utsname()->release, hcd->driver->description);
|
||||
|
||||
// unsupported IDs --> "protocol stall"
|
||||
} else
|
||||
return -EPIPE;
|
||||
}
|
||||
|
||||
switch (len) { /* All cases fall through */
|
||||
default:
|
||||
|
@ -360,9 +353,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
|||
u8 tbuf [sizeof (struct usb_hub_descriptor)]
|
||||
__attribute__((aligned(4)));
|
||||
const u8 *bufp = tbuf;
|
||||
int len = 0;
|
||||
unsigned len = 0;
|
||||
int status;
|
||||
int n;
|
||||
u8 patch_wakeup = 0;
|
||||
u8 patch_protocol = 0;
|
||||
|
||||
|
@ -456,10 +448,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
|||
patch_wakeup = 1;
|
||||
break;
|
||||
case USB_DT_STRING << 8:
|
||||
n = rh_string (wValue & 0xff, hcd, ubuf, wLength);
|
||||
if (n < 0)
|
||||
if ((wValue & 0xff) < 4)
|
||||
urb->actual_length = rh_string(wValue & 0xff,
|
||||
hcd, ubuf, wLength);
|
||||
else /* unsupported IDs --> "protocol stall" */
|
||||
goto error;
|
||||
urb->actual_length = n;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
|
@ -629,7 +622,7 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
|
|||
{
|
||||
int retval;
|
||||
unsigned long flags;
|
||||
int len = 1 + (urb->dev->maxchild / 8);
|
||||
unsigned len = 1 + (urb->dev->maxchild / 8);
|
||||
|
||||
spin_lock_irqsave (&hcd_root_hub_lock, flags);
|
||||
if (hcd->status_urb || urb->transfer_buffer_length < len) {
|
||||
|
@ -901,7 +894,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
|
||||
usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
|
||||
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
|
||||
if (retval != sizeof usb_dev->descriptor) {
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
|
|
|
@ -392,7 +392,7 @@ static void hub_irq(struct urb *urb)
|
|||
{
|
||||
struct usb_hub *hub = urb->context;
|
||||
int status = urb->status;
|
||||
int i;
|
||||
unsigned i;
|
||||
unsigned long bits;
|
||||
|
||||
switch (status) {
|
||||
|
@ -1305,6 +1305,7 @@ void usb_set_device_state(struct usb_device *udev,
|
|||
recursively_mark_NOTATTACHED(udev);
|
||||
spin_unlock_irqrestore(&device_state_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_set_device_state);
|
||||
|
||||
/*
|
||||
* WUSB devices are simple: they have no hubs behind, so the mapping
|
||||
|
@ -2471,20 +2472,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
*/
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_VARIABLE: /* fixed at 512 */
|
||||
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
break;
|
||||
case USB_SPEED_HIGH: /* fixed at 64 */
|
||||
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
break;
|
||||
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
|
||||
/* to determine the ep0 maxpacket size, try to read
|
||||
* the device descriptor to get bMaxPacketSize0 and
|
||||
* then correct our initial guess.
|
||||
*/
|
||||
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
|
||||
break;
|
||||
case USB_SPEED_LOW: /* fixed at 8 */
|
||||
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(8);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
|
@ -3392,10 +3393,10 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
|||
udev->descriptor = descriptor; /* for disconnect() calls */
|
||||
goto re_enumerate;
|
||||
}
|
||||
|
||||
|
||||
/* Restore the device's previous configuration */
|
||||
if (!udev->actconfig)
|
||||
goto done;
|
||||
|
||||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_CONFIGURATION, 0,
|
||||
udev->actconfig->desc.bConfigurationValue, 0,
|
||||
|
@ -3408,16 +3409,25 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
|||
}
|
||||
usb_set_device_state(udev, USB_STATE_CONFIGURED);
|
||||
|
||||
/* Put interfaces back into the same altsettings as before.
|
||||
* Don't bother to send the Set-Interface request for interfaces
|
||||
* that were already in altsetting 0; besides being unnecessary,
|
||||
* many devices can't handle it. Instead just reset the host-side
|
||||
* endpoint state.
|
||||
*/
|
||||
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
|
||||
struct usb_interface *intf = udev->actconfig->interface[i];
|
||||
struct usb_interface_descriptor *desc;
|
||||
|
||||
/* set_interface resets host side toggle even
|
||||
* for altsetting zero. the interface may have no driver.
|
||||
*/
|
||||
desc = &intf->cur_altsetting->desc;
|
||||
ret = usb_set_interface(udev, desc->bInterfaceNumber,
|
||||
desc->bAlternateSetting);
|
||||
if (desc->bAlternateSetting == 0) {
|
||||
usb_disable_interface(udev, intf, true);
|
||||
usb_enable_interface(udev, intf, true);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = usb_set_interface(udev, desc->bInterfaceNumber,
|
||||
desc->bAlternateSetting);
|
||||
}
|
||||
if (ret < 0) {
|
||||
dev_err(&udev->dev, "failed to restore interface %d "
|
||||
"altsetting %d (error=%d)\n",
|
||||
|
|
|
@ -59,7 +59,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
|
|||
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
|
||||
|
||||
dev_dbg(&urb->dev->dev,
|
||||
"%s timed out on ep%d%s len=%d/%d\n",
|
||||
"%s timed out on ep%d%s len=%u/%u\n",
|
||||
current->comm,
|
||||
usb_endpoint_num(&urb->ep->desc),
|
||||
usb_urb_dir_in(urb) ? "in" : "out",
|
||||
|
@ -804,18 +804,16 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
|
|||
dev_err(&dev->dev,
|
||||
"string descriptor 0 read error: %d\n",
|
||||
err);
|
||||
goto errout;
|
||||
} else if (err < 4) {
|
||||
dev_err(&dev->dev, "string descriptor 0 too short\n");
|
||||
err = -EINVAL;
|
||||
goto errout;
|
||||
} else {
|
||||
dev->have_langid = 1;
|
||||
dev->string_langid = tbuf[2] | (tbuf[3] << 8);
|
||||
/* always use the first langid listed */
|
||||
dev_dbg(&dev->dev, "default language 0x%04x\n",
|
||||
dev->string_langid);
|
||||
}
|
||||
|
||||
dev->have_langid = 1;
|
||||
}
|
||||
|
||||
err = usb_string_sub(dev, dev->string_langid, index, tbuf);
|
||||
|
@ -1719,7 +1717,8 @@ free_interfaces:
|
|||
}
|
||||
kfree(new_interfaces);
|
||||
|
||||
if (cp->string == NULL)
|
||||
if (cp->string == NULL &&
|
||||
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
|
||||
|
||||
/* Now that all the interfaces are set up, register them
|
||||
|
|
|
@ -54,6 +54,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
|
||||
USB_QUIRK_STRING_FETCH_255 },
|
||||
|
||||
/* Saitek Cyborg Gold Joystick */
|
||||
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
|
||||
USB_QUIRK_CONFIG_INTF_STRINGS },
|
||||
|
||||
/* M-Systems Flash Disk Pioneers */
|
||||
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
#include "usb.h"
|
||||
|
||||
/* Active configuration fields */
|
||||
|
@ -813,7 +814,8 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
|
|||
if (intf->sysfs_files_created || intf->unregistering)
|
||||
return 0;
|
||||
|
||||
if (alt->string == NULL)
|
||||
if (alt->string == NULL &&
|
||||
!(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
alt->string = usb_cache_string(udev, alt->desc.iInterface);
|
||||
if (alt->string)
|
||||
retval = device_create_file(&intf->dev, &dev_attr_interface);
|
||||
|
|
|
@ -295,7 +295,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
|||
if (!urb || urb->hcpriv || !urb->complete)
|
||||
return -EINVAL;
|
||||
dev = urb->dev;
|
||||
if ((!dev) || (dev->state < USB_STATE_DEFAULT))
|
||||
if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
|
||||
return -ENODEV;
|
||||
|
||||
/* For now, get the endpoint from the pipe. Eventually drivers
|
||||
|
@ -370,7 +370,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
|||
}
|
||||
|
||||
/* the I/O buffer must be mapped/unmapped, except when length=0 */
|
||||
if (urb->transfer_buffer_length < 0)
|
||||
if (urb->transfer_buffer_length > INT_MAX)
|
||||
return -EMSGSIZE;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -254,6 +254,7 @@ config USB_PXA25X_SMALL
|
|||
config USB_GADGET_PXA27X
|
||||
boolean "PXA 27x"
|
||||
depends on ARCH_PXA && PXA27x
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
Intel's PXA 27x series XScale ARM v5TE processors include
|
||||
an integrated full speed USB 1.1 device controller.
|
||||
|
|
|
@ -551,7 +551,7 @@ udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
|
|||
dma_desc->status = AMD_ADDBITS(dma_desc->status,
|
||||
UDC_DMA_STP_STS_BS_HOST_BUSY,
|
||||
UDC_DMA_STP_STS_BS);
|
||||
dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
|
||||
dma_desc->bufptr = cpu_to_le32(DMA_DONT_USE);
|
||||
req->td_data = dma_desc;
|
||||
req->td_data_last = NULL;
|
||||
req->chain_len = 1;
|
||||
|
|
|
@ -1017,7 +1017,7 @@ static struct usb_endpoint_descriptor usba_ep0_desc = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 0,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(64),
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
/* FIXME: I have no idea what to put here */
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
@ -1207,21 +1207,21 @@ static int do_test_mode(struct usba_udc *udc)
|
|||
/* Avoid overly long expressions */
|
||||
static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
|
||||
{
|
||||
if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
|
||||
if (crq->wValue == cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
|
||||
{
|
||||
if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
|
||||
if (crq->wValue == cpu_to_le16(USB_DEVICE_TEST_MODE))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
|
||||
{
|
||||
if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
|
||||
if (crq->wValue == cpu_to_le16(USB_ENDPOINT_HALT))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -1239,7 +1239,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
|
|||
status = cpu_to_le16(udc->devstatus);
|
||||
} else if (crq->bRequestType
|
||||
== (USB_DIR_IN | USB_RECIP_INTERFACE)) {
|
||||
status = __constant_cpu_to_le16(0);
|
||||
status = cpu_to_le16(0);
|
||||
} else if (crq->bRequestType
|
||||
== (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
|
||||
struct usba_ep *target;
|
||||
|
@ -1250,12 +1250,12 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
|
|||
|
||||
status = 0;
|
||||
if (is_stalled(udc, target))
|
||||
status |= __constant_cpu_to_le16(1);
|
||||
status |= cpu_to_le16(1);
|
||||
} else
|
||||
goto delegate;
|
||||
|
||||
/* Write directly to the FIFO. No queueing is done. */
|
||||
if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
|
||||
if (crq->wLength != cpu_to_le16(sizeof(status)))
|
||||
goto stall;
|
||||
ep->state = DATA_STAGE_IN;
|
||||
__raw_writew(status, ep->fifo);
|
||||
|
@ -1274,7 +1274,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
|
|||
} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
|
||||
struct usba_ep *target;
|
||||
|
||||
if (crq->wLength != __constant_cpu_to_le16(0)
|
||||
if (crq->wLength != cpu_to_le16(0)
|
||||
|| !feature_is_ep_halt(crq))
|
||||
goto stall;
|
||||
target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
|
||||
|
@ -1308,7 +1308,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
|
|||
} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
|
||||
struct usba_ep *target;
|
||||
|
||||
if (crq->wLength != __constant_cpu_to_le16(0)
|
||||
if (crq->wLength != cpu_to_le16(0)
|
||||
|| !feature_is_ep_halt(crq))
|
||||
goto stall;
|
||||
|
||||
|
@ -1514,7 +1514,7 @@ restart:
|
|||
*/
|
||||
ep->state = DATA_STAGE_IN;
|
||||
} else {
|
||||
if (crq.crq.wLength != __constant_cpu_to_le16(0))
|
||||
if (crq.crq.wLength != cpu_to_le16(0))
|
||||
ep->state = DATA_STAGE_OUT;
|
||||
else
|
||||
ep->state = STATUS_STAGE_IN;
|
||||
|
|
|
@ -66,7 +66,7 @@ static struct usb_device_descriptor device_desc = {
|
|||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
|
||||
.bDeviceClass = USB_CLASS_COMM,
|
||||
.bDeviceSubClass = 0,
|
||||
|
@ -74,8 +74,8 @@ static struct usb_device_descriptor device_desc = {
|
|||
/* .bMaxPacketSize0 = f(hardware) */
|
||||
|
||||
/* Vendor and product id can be overridden by module parameters. */
|
||||
.idVendor = __constant_cpu_to_le16(CDC_VENDOR_NUM),
|
||||
.idProduct = __constant_cpu_to_le16(CDC_PRODUCT_NUM),
|
||||
.idVendor = cpu_to_le16(CDC_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16(CDC_PRODUCT_NUM),
|
||||
/* .bcdDevice = f(hardware) */
|
||||
/* .iManufacturer = DYNAMIC */
|
||||
/* .iProduct = DYNAMIC */
|
||||
|
@ -193,7 +193,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
|
|||
gadget->name,
|
||||
cdc_config_driver.label);
|
||||
device_desc.bcdDevice =
|
||||
__constant_cpu_to_le16(0x0300 | 0x0099);
|
||||
cpu_to_le16(0x0300 | 0x0099);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -149,16 +149,17 @@ done:
|
|||
int usb_function_deactivate(struct usb_function *function)
|
||||
{
|
||||
struct usb_composite_dev *cdev = function->config->cdev;
|
||||
unsigned long flags;
|
||||
int status = 0;
|
||||
|
||||
spin_lock(&cdev->lock);
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
|
||||
if (cdev->deactivations == 0)
|
||||
status = usb_gadget_disconnect(cdev->gadget);
|
||||
if (status == 0)
|
||||
cdev->deactivations++;
|
||||
|
||||
spin_unlock(&cdev->lock);
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1013,7 +1014,7 @@ composite_suspend(struct usb_gadget *gadget)
|
|||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
struct usb_function *f;
|
||||
|
||||
/* REVISIT: should we have config and device level
|
||||
/* REVISIT: should we have config level
|
||||
* suspend/resume callbacks?
|
||||
*/
|
||||
DBG(cdev, "suspend\n");
|
||||
|
@ -1023,6 +1024,8 @@ composite_suspend(struct usb_gadget *gadget)
|
|||
f->suspend(f);
|
||||
}
|
||||
}
|
||||
if (composite->suspend)
|
||||
composite->suspend(cdev);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1031,10 +1034,12 @@ composite_resume(struct usb_gadget *gadget)
|
|||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
struct usb_function *f;
|
||||
|
||||
/* REVISIT: should we have config and device level
|
||||
/* REVISIT: should we have config level
|
||||
* suspend/resume callbacks?
|
||||
*/
|
||||
DBG(cdev, "resume\n");
|
||||
if (composite->resume)
|
||||
composite->resume(cdev);
|
||||
if (cdev->config) {
|
||||
list_for_each_entry(f, &cdev->config->functions, list) {
|
||||
if (f->resume)
|
||||
|
|
|
@ -1437,7 +1437,7 @@ restart:
|
|||
}
|
||||
if (urb->transfer_buffer_length > 1)
|
||||
buf [1] = 0;
|
||||
urb->actual_length = min (2,
|
||||
urb->actual_length = min_t(u32, 2,
|
||||
urb->transfer_buffer_length);
|
||||
value = 0;
|
||||
status = 0;
|
||||
|
@ -1626,7 +1626,7 @@ static int dummy_hub_control (
|
|||
hub_descriptor ((struct usb_hub_descriptor *) buf);
|
||||
break;
|
||||
case GetHubStatus:
|
||||
*(__le32 *) buf = __constant_cpu_to_le32 (0);
|
||||
*(__le32 *) buf = cpu_to_le32 (0);
|
||||
break;
|
||||
case GetPortStatus:
|
||||
if (wIndex != 1)
|
||||
|
|
|
@ -148,7 +148,7 @@ ep_matches (
|
|||
return 0;
|
||||
|
||||
/* BOTH: "high bandwidth" works only at high speed */
|
||||
if ((desc->wMaxPacketSize & __constant_cpu_to_le16(3<<11))) {
|
||||
if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
|
||||
if (!gadget->is_dualspeed)
|
||||
return 0;
|
||||
/* configure your hardware with enough buffering!! */
|
||||
|
|
|
@ -156,7 +156,7 @@ static struct usb_device_descriptor device_desc = {
|
|||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = __constant_cpu_to_le16 (0x0200),
|
||||
.bcdUSB = cpu_to_le16 (0x0200),
|
||||
|
||||
.bDeviceClass = USB_CLASS_COMM,
|
||||
.bDeviceSubClass = 0,
|
||||
|
@ -167,8 +167,8 @@ static struct usb_device_descriptor device_desc = {
|
|||
* we support. (As does bNumConfigurations.) These values can
|
||||
* also be overridden by module parameters.
|
||||
*/
|
||||
.idVendor = __constant_cpu_to_le16 (CDC_VENDOR_NUM),
|
||||
.idProduct = __constant_cpu_to_le16 (CDC_PRODUCT_NUM),
|
||||
.idVendor = cpu_to_le16 (CDC_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16 (CDC_PRODUCT_NUM),
|
||||
/* .bcdDevice = f(hardware) */
|
||||
/* .iManufacturer = DYNAMIC */
|
||||
/* .iProduct = DYNAMIC */
|
||||
|
@ -318,7 +318,7 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
|
|||
gadget->name,
|
||||
eth_config_driver.label);
|
||||
device_desc.bcdDevice =
|
||||
__constant_cpu_to_le16(0x0300 | 0x0099);
|
||||
cpu_to_le16(0x0300 | 0x0099);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ static struct usb_cdc_header_desc acm_header_desc __initdata = {
|
|||
.bLength = sizeof(acm_header_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
.bcdCDC = __constant_cpu_to_le16(0x0110),
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_call_mgmt_descriptor
|
||||
|
@ -159,7 +159,7 @@ static struct usb_endpoint_descriptor acm_fs_notify_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
|
||||
};
|
||||
|
||||
|
@ -197,7 +197,7 @@ static struct usb_endpoint_descriptor acm_hs_notify_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
|
||||
};
|
||||
|
||||
|
@ -205,14 +205,14 @@ static struct usb_endpoint_descriptor acm_hs_in_desc __initdata = {
|
|||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acm_hs_out_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *acm_hs_function[] __initdata = {
|
||||
|
|
|
@ -130,7 +130,7 @@ static struct usb_cdc_header_desc ecm_header_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
|
||||
.bcdCDC = __constant_cpu_to_le16(0x0110),
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc ecm_union_desc __initdata = {
|
||||
|
@ -148,9 +148,9 @@ static struct usb_cdc_ether_desc ecm_desc __initdata = {
|
|||
|
||||
/* this descriptor actually adds value, surprise! */
|
||||
/* .iMACAddress = DYNAMIC */
|
||||
.bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */
|
||||
.wMaxSegmentSize = __constant_cpu_to_le16(ETH_FRAME_LEN),
|
||||
.wNumberMCFilters = __constant_cpu_to_le16(0),
|
||||
.bmEthernetStatistics = cpu_to_le32(0), /* no statistics */
|
||||
.wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN),
|
||||
.wNumberMCFilters = cpu_to_le16(0),
|
||||
.bNumberPowerFilters = 0,
|
||||
};
|
||||
|
||||
|
@ -192,7 +192,7 @@ static struct usb_endpoint_descriptor fs_ecm_notify_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
};
|
||||
|
||||
|
@ -236,7 +236,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
};
|
||||
static struct usb_endpoint_descriptor hs_ecm_in_desc __initdata = {
|
||||
|
@ -245,7 +245,7 @@ static struct usb_endpoint_descriptor hs_ecm_in_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ecm_out_desc __initdata = {
|
||||
|
@ -254,7 +254,7 @@ static struct usb_endpoint_descriptor hs_ecm_out_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *ecm_hs_function[] __initdata = {
|
||||
|
|
|
@ -100,7 +100,7 @@ static struct usb_endpoint_descriptor hs_loop_source_desc = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_loop_sink_desc = {
|
||||
|
@ -108,7 +108,7 @@ static struct usb_endpoint_descriptor hs_loop_sink_desc = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_loopback_descs[] = {
|
||||
|
@ -359,7 +359,7 @@ static struct usb_configuration loopback_driver = {
|
|||
* loopback_add - add a loopback testing configuration to a device
|
||||
* @cdev: the device to support the loopback configuration
|
||||
*/
|
||||
int __init loopback_add(struct usb_composite_dev *cdev)
|
||||
int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)
|
||||
{
|
||||
int id;
|
||||
|
||||
|
@ -372,6 +372,10 @@ int __init loopback_add(struct usb_composite_dev *cdev)
|
|||
loopback_intf.iInterface = id;
|
||||
loopback_driver.iConfiguration = id;
|
||||
|
||||
/* support autoresume for remote wakeup testing */
|
||||
if (autoresume)
|
||||
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
|
||||
/* support OTG systems */
|
||||
if (gadget_is_otg(cdev->gadget)) {
|
||||
loopback_driver.descriptors = otg_desc;
|
||||
|
|
|
@ -123,7 +123,7 @@ static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = {
|
|||
.bLength = sizeof(obex_cdc_header_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
.bcdCDC = __constant_cpu_to_le16(0x0120),
|
||||
.bcdCDC = cpu_to_le16(0x0120),
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
|
||||
|
@ -138,7 +138,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = {
|
|||
.bLength = sizeof(obex_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_OBEX_TYPE,
|
||||
.bcdVersion = __constant_cpu_to_le16(0x0100),
|
||||
.bcdVersion = cpu_to_le16(0x0100),
|
||||
};
|
||||
|
||||
/* High-Speed Support */
|
||||
|
@ -149,7 +149,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
|
||||
|
@ -158,7 +158,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_function[] __initdata = {
|
||||
|
|
|
@ -79,7 +79,7 @@ pn_header_desc = {
|
|||
.bLength = sizeof pn_header_desc,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
.bcdCDC = __constant_cpu_to_le16(0x0110),
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static const struct usb_cdc_header_desc
|
||||
|
@ -87,7 +87,7 @@ pn_phonet_desc = {
|
|||
.bLength = sizeof pn_phonet_desc,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_PHONET_TYPE,
|
||||
.bcdCDC = __constant_cpu_to_le16(0x1505), /* ??? */
|
||||
.bcdCDC = cpu_to_le16(0x1505), /* ??? */
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc
|
||||
|
@ -138,7 +138,7 @@ pn_hs_sink_desc = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
|
@ -157,7 +157,7 @@ pn_hs_source_desc = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *fs_pn_function[] = {
|
||||
|
|
|
@ -137,7 +137,7 @@ static struct usb_cdc_header_desc header_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
|
||||
.bcdCDC = __constant_cpu_to_le16(0x0110),
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
|
||||
|
@ -187,7 +187,7 @@ static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
};
|
||||
|
||||
|
@ -230,7 +230,7 @@ static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
};
|
||||
static struct usb_endpoint_descriptor hs_in_desc __initdata = {
|
||||
|
@ -239,7 +239,7 @@ static struct usb_endpoint_descriptor hs_in_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_out_desc __initdata = {
|
||||
|
@ -248,7 +248,7 @@ static struct usb_endpoint_descriptor hs_out_desc __initdata = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *eth_hs_function[] __initdata = {
|
||||
|
@ -437,7 +437,7 @@ invalid:
|
|||
DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
req->zero = 0;
|
||||
req->zero = (value < w_length);
|
||||
req->length = value;
|
||||
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (value < 0)
|
||||
|
|
|
@ -89,14 +89,14 @@ static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
|
|||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *gser_hs_function[] __initdata = {
|
||||
|
|
|
@ -59,7 +59,6 @@ struct f_sourcesink {
|
|||
|
||||
struct usb_ep *in_ep;
|
||||
struct usb_ep *out_ep;
|
||||
struct timer_list resume;
|
||||
};
|
||||
|
||||
static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
|
||||
|
@ -67,10 +66,6 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
|
|||
return container_of(f, struct f_sourcesink, function);
|
||||
}
|
||||
|
||||
static unsigned autoresume;
|
||||
module_param(autoresume, uint, 0);
|
||||
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
|
||||
|
||||
static unsigned pattern;
|
||||
module_param(pattern, uint, 0);
|
||||
MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 ");
|
||||
|
@ -118,7 +113,7 @@ static struct usb_endpoint_descriptor hs_source_desc = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_sink_desc = {
|
||||
|
@ -126,7 +121,7 @@ static struct usb_endpoint_descriptor hs_sink_desc = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_source_sink_descs[] = {
|
||||
|
@ -155,21 +150,6 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void sourcesink_autoresume(unsigned long _c)
|
||||
{
|
||||
struct usb_composite_dev *cdev = (void *)_c;
|
||||
struct usb_gadget *g = cdev->gadget;
|
||||
|
||||
/* Normally the host would be woken up for something
|
||||
* more significant than just a timer firing; likely
|
||||
* because of some direct user request.
|
||||
*/
|
||||
if (g->speed != USB_SPEED_UNKNOWN) {
|
||||
int status = usb_gadget_wakeup(g);
|
||||
DBG(cdev, "%s --> %d\n", __func__, status);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init
|
||||
sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
|
@ -198,9 +178,6 @@ autoconf_fail:
|
|||
goto autoconf_fail;
|
||||
ss->out_ep->driver_data = cdev; /* claim */
|
||||
|
||||
setup_timer(&ss->resume, sourcesink_autoresume,
|
||||
(unsigned long) c->cdev);
|
||||
|
||||
/* support high speed hardware */
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hs_source_desc.bEndpointAddress =
|
||||
|
@ -359,7 +336,6 @@ static void disable_source_sink(struct f_sourcesink *ss)
|
|||
|
||||
cdev = ss->function.config->cdev;
|
||||
disable_endpoints(cdev, ss->in_ep, ss->out_ep);
|
||||
del_timer(&ss->resume);
|
||||
VDBG(cdev, "%s disabled\n", ss->function.name);
|
||||
}
|
||||
|
||||
|
@ -426,30 +402,6 @@ static void sourcesink_disable(struct usb_function *f)
|
|||
disable_source_sink(ss);
|
||||
}
|
||||
|
||||
static void sourcesink_suspend(struct usb_function *f)
|
||||
{
|
||||
struct f_sourcesink *ss = func_to_ss(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
|
||||
return;
|
||||
|
||||
if (autoresume) {
|
||||
mod_timer(&ss->resume, jiffies + (HZ * autoresume));
|
||||
DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
|
||||
} else
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static void sourcesink_resume(struct usb_function *f)
|
||||
{
|
||||
struct f_sourcesink *ss = func_to_ss(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
del_timer(&ss->resume);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init sourcesink_bind_config(struct usb_configuration *c)
|
||||
|
@ -467,8 +419,6 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
|
|||
ss->function.unbind = sourcesink_unbind;
|
||||
ss->function.set_alt = sourcesink_set_alt;
|
||||
ss->function.disable = sourcesink_disable;
|
||||
ss->function.suspend = sourcesink_suspend;
|
||||
ss->function.resume = sourcesink_resume;
|
||||
|
||||
status = usb_add_function(c, &ss->function);
|
||||
if (status)
|
||||
|
@ -559,7 +509,7 @@ static struct usb_configuration sourcesink_driver = {
|
|||
* sourcesink_add - add a source/sink testing configuration to a device
|
||||
* @cdev: the device to support the configuration
|
||||
*/
|
||||
int __init sourcesink_add(struct usb_composite_dev *cdev)
|
||||
int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
|
||||
{
|
||||
int id;
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ static struct usb_cdc_header_desc mdlm_header_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
|
||||
.bcdCDC = __constant_cpu_to_le16(0x0110),
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_mdlm_desc mdlm_desc __initdata = {
|
||||
|
@ -116,7 +116,7 @@ static struct usb_cdc_mdlm_desc mdlm_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_MDLM_TYPE,
|
||||
|
||||
.bcdVersion = __constant_cpu_to_le16(0x0100),
|
||||
.bcdVersion = cpu_to_le16(0x0100),
|
||||
.bGUID = {
|
||||
0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
|
||||
0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
|
||||
|
@ -144,9 +144,9 @@ static struct usb_cdc_ether_desc ether_desc __initdata = {
|
|||
|
||||
/* this descriptor actually adds value, surprise! */
|
||||
/* .iMACAddress = DYNAMIC */
|
||||
.bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */
|
||||
.wMaxSegmentSize = __constant_cpu_to_le16(ETH_FRAME_LEN),
|
||||
.wNumberMCFilters = __constant_cpu_to_le16(0),
|
||||
.bmEthernetStatistics = cpu_to_le32(0), /* no statistics */
|
||||
.wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN),
|
||||
.wNumberMCFilters = cpu_to_le16(0),
|
||||
.bNumberPowerFilters = 0,
|
||||
};
|
||||
|
||||
|
@ -186,7 +186,7 @@ static struct usb_endpoint_descriptor hs_subset_in_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_subset_out_desc __initdata = {
|
||||
|
@ -194,7 +194,7 @@ static struct usb_endpoint_descriptor hs_subset_out_desc __initdata = {
|
|||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_eth_function[] __initdata = {
|
||||
|
|
|
@ -847,13 +847,13 @@ device_desc = {
|
|||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PER_INTERFACE,
|
||||
|
||||
/* The next three values can be overridden by module parameters */
|
||||
.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),
|
||||
.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),
|
||||
.bcdDevice = __constant_cpu_to_le16(0xffff),
|
||||
.idVendor = cpu_to_le16(DRIVER_VENDOR_ID),
|
||||
.idProduct = cpu_to_le16(DRIVER_PRODUCT_ID),
|
||||
.bcdDevice = cpu_to_le16(0xffff),
|
||||
|
||||
.iManufacturer = STRING_MANUFACTURER,
|
||||
.iProduct = STRING_PRODUCT,
|
||||
|
@ -926,7 +926,7 @@ fs_intr_in_desc = {
|
|||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(2),
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 32, // frames -> 32 ms
|
||||
};
|
||||
|
||||
|
@ -954,7 +954,7 @@ dev_qualifier = {
|
|||
.bLength = sizeof dev_qualifier,
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PER_INTERFACE,
|
||||
|
||||
.bNumConfigurations = 1,
|
||||
|
@ -967,7 +967,7 @@ hs_bulk_in_desc = {
|
|||
|
||||
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
|
@ -977,7 +977,7 @@ hs_bulk_out_desc = {
|
|||
|
||||
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.bInterval = 1, // NAK every 1 uframe
|
||||
};
|
||||
|
||||
|
@ -988,7 +988,7 @@ hs_intr_in_desc = {
|
|||
|
||||
/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(2),
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms
|
||||
};
|
||||
|
||||
|
@ -2646,7 +2646,7 @@ static int send_status(struct fsg_dev *fsg)
|
|||
struct bulk_cs_wrap *csw = bh->buf;
|
||||
|
||||
/* Store and send the Bulk-only CSW */
|
||||
csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
|
||||
csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
|
||||
csw->Tag = fsg->tag;
|
||||
csw->Residue = cpu_to_le32(fsg->residue);
|
||||
csw->Status = status;
|
||||
|
@ -3089,7 +3089,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||
|
||||
/* Is the CBW valid? */
|
||||
if (req->actual != USB_BULK_CB_WRAP_LEN ||
|
||||
cbw->Signature != __constant_cpu_to_le32(
|
||||
cbw->Signature != cpu_to_le32(
|
||||
USB_BULK_CB_SIG)) {
|
||||
DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
|
||||
req->actual,
|
||||
|
|
|
@ -1802,7 +1802,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
out:
|
||||
if (retval)
|
||||
printk("gadget driver register failed %d\n", retval);
|
||||
printk(KERN_WARNING "gadget driver register failed %d\n",
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
|
@ -1847,7 +1848,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
|||
udc_controller->gadget.dev.driver = NULL;
|
||||
udc_controller->driver = NULL;
|
||||
|
||||
printk("unregistered gadget driver '%s'\n", driver->driver.name);
|
||||
printk(KERN_WARNING "unregistered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
@ -2455,7 +2457,7 @@ module_init(udc_init);
|
|||
static void __exit udc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&udc_driver);
|
||||
printk("%s unregistered\n", driver_desc);
|
||||
printk(KERN_WARNING "%s unregistered\n", driver_desc);
|
||||
}
|
||||
|
||||
module_exit(udc_exit);
|
||||
|
|
|
@ -19,7 +19,7 @@ void disable_endpoints(struct usb_composite_dev *cdev,
|
|||
struct usb_ep *in, struct usb_ep *out);
|
||||
|
||||
/* configuration-specific linkup */
|
||||
int sourcesink_add(struct usb_composite_dev *cdev);
|
||||
int loopback_add(struct usb_composite_dev *cdev);
|
||||
int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume);
|
||||
int loopback_add(struct usb_composite_dev *cdev, bool autoresume);
|
||||
|
||||
#endif /* __G_ZERO_H */
|
||||
|
|
|
@ -199,10 +199,10 @@ DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
|
|||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PER_INTERFACE,
|
||||
.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
|
||||
.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
|
||||
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
|
||||
.iManufacturer = STRING_MANUFACTURER,
|
||||
.iProduct = STRING_PRODUCT,
|
||||
.bNumConfigurations = 1,
|
||||
|
@ -241,8 +241,8 @@ static const struct usb_ac_header_descriptor_1 ac_header_desc = {
|
|||
.bLength = USB_DT_AC_HEADER_SIZE(1),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubtype = USB_MS_HEADER,
|
||||
.bcdADC = __constant_cpu_to_le16(0x0100),
|
||||
.wTotalLength = __constant_cpu_to_le16(USB_DT_AC_HEADER_SIZE(1)),
|
||||
.bcdADC = cpu_to_le16(0x0100),
|
||||
.wTotalLength = cpu_to_le16(USB_DT_AC_HEADER_SIZE(1)),
|
||||
.bInCollection = 1,
|
||||
.baInterfaceNr = {
|
||||
[0] = GMIDI_MS_INTERFACE,
|
||||
|
@ -265,8 +265,8 @@ static const struct usb_ms_header_descriptor ms_header_desc = {
|
|||
.bLength = USB_DT_MS_HEADER_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubtype = USB_MS_HEADER,
|
||||
.bcdMSC = __constant_cpu_to_le16(0x0100),
|
||||
.wTotalLength = __constant_cpu_to_le16(USB_DT_MS_HEADER_SIZE
|
||||
.bcdMSC = cpu_to_le16(0x0100),
|
||||
.wTotalLength = cpu_to_le16(USB_DT_MS_HEADER_SIZE
|
||||
+ 2*USB_DT_MIDI_IN_SIZE
|
||||
+ 2*USB_DT_MIDI_OUT_SIZE(1)),
|
||||
};
|
||||
|
@ -1226,7 +1226,7 @@ autoconf_fail:
|
|||
*/
|
||||
pr_warning("%s: controller '%s' not recognized\n",
|
||||
shortname, gadget->name);
|
||||
device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
|
||||
device_desc.bcdDevice = cpu_to_le16(0x9999);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1472,7 +1472,7 @@ static void ep0_setup(struct goku_udc *dev)
|
|||
/* active endpoint */
|
||||
if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
|
||||
goto stall;
|
||||
if (ctrl.wIndex & __constant_cpu_to_le16(
|
||||
if (ctrl.wIndex & cpu_to_le16(
|
||||
USB_DIR_IN)) {
|
||||
if (!dev->ep[tmp].is_in)
|
||||
goto stall;
|
||||
|
@ -1480,7 +1480,7 @@ static void ep0_setup(struct goku_udc *dev)
|
|||
if (dev->ep[tmp].is_in)
|
||||
goto stall;
|
||||
}
|
||||
if (ctrl.wValue != __constant_cpu_to_le16(
|
||||
if (ctrl.wValue != cpu_to_le16(
|
||||
USB_ENDPOINT_HALT))
|
||||
goto stall;
|
||||
if (tmp)
|
||||
|
@ -1493,7 +1493,7 @@ succeed:
|
|||
return;
|
||||
case USB_RECIP_DEVICE:
|
||||
/* device remote wakeup: always clear */
|
||||
if (ctrl.wValue != __constant_cpu_to_le16(1))
|
||||
if (ctrl.wValue != cpu_to_le16(1))
|
||||
goto stall;
|
||||
VDBG(dev, "clear dev remote wakeup\n");
|
||||
goto succeed;
|
||||
|
@ -1519,7 +1519,7 @@ succeed:
|
|||
dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION
|
||||
&& ctrl.bRequestType == USB_RECIP_DEVICE);
|
||||
if (unlikely(dev->req_config))
|
||||
dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0));
|
||||
dev->configured = (ctrl.wValue != cpu_to_le16(0));
|
||||
|
||||
/* delegate everything to the gadget driver.
|
||||
* it may respond after this irq handler returns.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* driver/usb/gadget/imx_udc.c
|
||||
*
|
||||
* Copyright (C) 2005 Mike Lee(eemike@gmail.com)
|
||||
* Copyright (C) 2005 Mike Lee <eemike@gmail.com>
|
||||
* Copyright (C) 2008 Darius Augulis <augulis.darius@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,6 +28,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
@ -51,7 +52,8 @@ void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb,
|
|||
void imx_udc_enable(struct imx_udc_struct *imx_usb)
|
||||
{
|
||||
int temp = __raw_readl(imx_usb->base + USB_CTRL);
|
||||
__raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA, imx_usb->base + USB_CTRL);
|
||||
__raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA,
|
||||
imx_usb->base + USB_CTRL);
|
||||
imx_usb->gadget.speed = USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
|
@ -126,7 +128,8 @@ void imx_udc_config(struct imx_udc_struct *imx_usb)
|
|||
for (j = 0; j < 5; j++) {
|
||||
__raw_writeb(ep_conf[j],
|
||||
imx_usb->base + USB_DDAT);
|
||||
do {} while (__raw_readl(imx_usb->base + USB_DADR)
|
||||
do {} while (__raw_readl(imx_usb->base
|
||||
+ USB_DADR)
|
||||
& DADR_BSY);
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +186,8 @@ void imx_udc_init_ep(struct imx_udc_struct *imx_usb)
|
|||
temp = (EP_DIR(imx_ep) << 7) | (max << 5)
|
||||
| (imx_ep->bmAttributes << 3);
|
||||
__raw_writel(temp, imx_usb->base + USB_EP_STAT(i));
|
||||
__raw_writel(temp | EPSTAT_FLUSH, imx_usb->base + USB_EP_STAT(i));
|
||||
__raw_writel(temp | EPSTAT_FLUSH,
|
||||
imx_usb->base + USB_EP_STAT(i));
|
||||
D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i,
|
||||
__raw_readl(imx_usb->base + USB_EP_STAT(i)));
|
||||
}
|
||||
|
@ -278,15 +282,18 @@ void imx_ep_stall(struct imx_ep_struct *imx_ep)
|
|||
struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
|
||||
int temp, i;
|
||||
|
||||
D_ERR(imx_usb->dev, "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name);
|
||||
D_ERR(imx_usb->dev,
|
||||
"<%s> Forced stall on %s\n", __func__, imx_ep->ep.name);
|
||||
|
||||
imx_flush(imx_ep);
|
||||
|
||||
/* Special care for ep0 */
|
||||
if (EP_NO(imx_ep)) {
|
||||
if (!EP_NO(imx_ep)) {
|
||||
temp = __raw_readl(imx_usb->base + USB_CTRL);
|
||||
__raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, imx_usb->base + USB_CTRL);
|
||||
do { } while (__raw_readl(imx_usb->base + USB_CTRL) & CTRL_CMDOVER);
|
||||
__raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR,
|
||||
imx_usb->base + USB_CTRL);
|
||||
do { } while (__raw_readl(imx_usb->base + USB_CTRL)
|
||||
& CTRL_CMDOVER);
|
||||
temp = __raw_readl(imx_usb->base + USB_CTRL);
|
||||
__raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL);
|
||||
}
|
||||
|
@ -296,12 +303,13 @@ void imx_ep_stall(struct imx_ep_struct *imx_ep)
|
|||
imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
|
||||
|
||||
for (i = 0; i < 100; i ++) {
|
||||
temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
|
||||
temp = __raw_readl(imx_usb->base
|
||||
+ USB_EP_STAT(EP_NO(imx_ep)));
|
||||
if (!(temp & EPSTAT_STALL))
|
||||
break;
|
||||
udelay(20);
|
||||
}
|
||||
if (i == 50)
|
||||
if (i == 100)
|
||||
D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n",
|
||||
__func__, imx_ep->ep.name);
|
||||
}
|
||||
|
@ -325,7 +333,8 @@ static int imx_udc_wakeup(struct usb_gadget *_gadget)
|
|||
*******************************************************************************
|
||||
*/
|
||||
|
||||
static void ep_add_request(struct imx_ep_struct *imx_ep, struct imx_request *req)
|
||||
static void ep_add_request(struct imx_ep_struct *imx_ep,
|
||||
struct imx_request *req)
|
||||
{
|
||||
if (unlikely(!req))
|
||||
return;
|
||||
|
@ -334,7 +343,8 @@ static void ep_add_request(struct imx_ep_struct *imx_ep, struct imx_request *req
|
|||
list_add_tail(&req->queue, &imx_ep->queue);
|
||||
}
|
||||
|
||||
static void ep_del_request(struct imx_ep_struct *imx_ep, struct imx_request *req)
|
||||
static void ep_del_request(struct imx_ep_struct *imx_ep,
|
||||
struct imx_request *req)
|
||||
{
|
||||
if (unlikely(!req))
|
||||
return;
|
||||
|
@ -343,7 +353,8 @@ static void ep_del_request(struct imx_ep_struct *imx_ep, struct imx_request *req
|
|||
req->in_use = 0;
|
||||
}
|
||||
|
||||
static void done(struct imx_ep_struct *imx_ep, struct imx_request *req, int status)
|
||||
static void done(struct imx_ep_struct *imx_ep,
|
||||
struct imx_request *req, int status)
|
||||
{
|
||||
ep_del_request(imx_ep, req);
|
||||
|
||||
|
@ -494,7 +505,8 @@ static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
|
|||
__func__, imx_ep->ep.name, req,
|
||||
completed ? "completed" : "not completed");
|
||||
if (!EP_NO(imx_ep))
|
||||
ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE);
|
||||
ep0_chg_stat(__func__,
|
||||
imx_ep->imx_usb, EP0_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -539,10 +551,9 @@ static int handle_ep0(struct imx_ep_struct *imx_ep)
|
|||
struct imx_request *req = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!list_empty(&imx_ep->queue))
|
||||
if (!list_empty(&imx_ep->queue)) {
|
||||
req = list_entry(imx_ep->queue.next, struct imx_request, queue);
|
||||
|
||||
if (req) {
|
||||
switch (imx_ep->imx_usb->ep0state) {
|
||||
|
||||
case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR */
|
||||
|
@ -561,6 +572,10 @@ static int handle_ep0(struct imx_ep_struct *imx_ep)
|
|||
}
|
||||
}
|
||||
|
||||
else
|
||||
D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
|
||||
__func__, imx_ep->ep.name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -583,7 +598,8 @@ static void handle_ep0_devreq(struct imx_udc_struct *imx_usb)
|
|||
"<%s> no setup packet received\n", __func__);
|
||||
goto stall;
|
||||
}
|
||||
u.word[i] = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep)));
|
||||
u.word[i] = __raw_readl(imx_usb->base
|
||||
+ USB_EP_FDAT(EP_NO(imx_ep)));
|
||||
}
|
||||
|
||||
temp = imx_ep_empty(imx_ep);
|
||||
|
@ -759,7 +775,7 @@ static int imx_ep_queue
|
|||
*/
|
||||
if (imx_usb->set_config && !EP_NO(imx_ep)) {
|
||||
imx_usb->set_config = 0;
|
||||
D_EPX(imx_usb->dev,
|
||||
D_ERR(imx_usb->dev,
|
||||
"<%s> gadget reply set config\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
@ -779,28 +795,29 @@ static int imx_ep_queue
|
|||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* Debug */
|
||||
D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n",
|
||||
__func__, EP_NO(imx_ep),
|
||||
((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state == EP0_IN_DATA_PHASE)
|
||||
|| (EP_NO(imx_ep) && EP_DIR(imx_ep))) ? "IN" : "OUT", usb_req->length);
|
||||
((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
|
||||
== EP0_IN_DATA_PHASE)
|
||||
|| (EP_NO(imx_ep) && EP_DIR(imx_ep)))
|
||||
? "IN" : "OUT", usb_req->length);
|
||||
dump_req(__func__, imx_ep, usb_req);
|
||||
|
||||
if (imx_ep->stopped) {
|
||||
usb_req->status = -ESHUTDOWN;
|
||||
ret = -ESHUTDOWN;
|
||||
goto out;
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
if (req->in_use) {
|
||||
D_ERR(imx_usb->dev,
|
||||
"<%s> refusing to queue req %p (already queued)\n",
|
||||
__func__, req);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
usb_req->status = -EINPROGRESS;
|
||||
usb_req->actual = 0;
|
||||
|
||||
|
@ -810,7 +827,7 @@ static int imx_ep_queue
|
|||
ret = handle_ep0(imx_ep);
|
||||
else
|
||||
ret = handle_ep(imx_ep);
|
||||
out:
|
||||
|
||||
local_irq_restore(flags);
|
||||
return ret;
|
||||
}
|
||||
|
@ -997,71 +1014,32 @@ static void udc_stop_activity(struct imx_udc_struct *imx_usb,
|
|||
*******************************************************************************
|
||||
*/
|
||||
|
||||
static irqreturn_t imx_udc_irq(int irq, void *dev)
|
||||
/*
|
||||
* Called when timer expires.
|
||||
* Timer is started when CFG_CHG is received.
|
||||
*/
|
||||
static void handle_config(unsigned long data)
|
||||
{
|
||||
struct imx_udc_struct *imx_usb = dev;
|
||||
struct imx_udc_struct *imx_usb = (void *)data;
|
||||
struct usb_ctrlrequest u;
|
||||
int temp, cfg, intf, alt;
|
||||
int intr = __raw_readl(imx_usb->base + USB_INTR);
|
||||
|
||||
if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START
|
||||
| INTR_RESET_STOP | INTR_CFG_CHG)) {
|
||||
dump_intr(__func__, intr, imx_usb->dev);
|
||||
dump_usb_stat(__func__, imx_usb);
|
||||
}
|
||||
local_irq_disable();
|
||||
|
||||
if (!imx_usb->driver) {
|
||||
/*imx_udc_disable(imx_usb);*/
|
||||
goto end_irq;
|
||||
}
|
||||
temp = __raw_readl(imx_usb->base + USB_STAT);
|
||||
cfg = (temp & STAT_CFG) >> 5;
|
||||
intf = (temp & STAT_INTF) >> 3;
|
||||
alt = temp & STAT_ALTSET;
|
||||
|
||||
if (intr & INTR_WAKEUP) {
|
||||
if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN
|
||||
&& imx_usb->driver && imx_usb->driver->resume)
|
||||
imx_usb->driver->resume(&imx_usb->gadget);
|
||||
imx_usb->set_config = 0;
|
||||
imx_usb->gadget.speed = USB_SPEED_FULL;
|
||||
}
|
||||
D_REQ(imx_usb->dev,
|
||||
"<%s> orig config C=%d, I=%d, A=%d / "
|
||||
"req config C=%d, I=%d, A=%d\n",
|
||||
__func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt,
|
||||
cfg, intf, alt);
|
||||
|
||||
if (intr & INTR_SUSPEND) {
|
||||
if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN
|
||||
&& imx_usb->driver && imx_usb->driver->suspend)
|
||||
imx_usb->driver->suspend(&imx_usb->gadget);
|
||||
imx_usb->set_config = 0;
|
||||
imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
}
|
||||
if (cfg == 1 || cfg == 2) {
|
||||
|
||||
if (intr & INTR_RESET_START) {
|
||||
__raw_writel(intr, imx_usb->base + USB_INTR);
|
||||
udc_stop_activity(imx_usb, imx_usb->driver);
|
||||
imx_usb->set_config = 0;
|
||||
imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
if (intr & INTR_RESET_STOP)
|
||||
imx_usb->gadget.speed = USB_SPEED_FULL;
|
||||
|
||||
if (intr & INTR_CFG_CHG) {
|
||||
__raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR);
|
||||
temp = __raw_readl(imx_usb->base + USB_STAT);
|
||||
cfg = (temp & STAT_CFG) >> 5;
|
||||
intf = (temp & STAT_INTF) >> 3;
|
||||
alt = temp & STAT_ALTSET;
|
||||
|
||||
D_REQ(imx_usb->dev,
|
||||
"<%s> orig config C=%d, I=%d, A=%d / "
|
||||
"req config C=%d, I=%d, A=%d\n",
|
||||
__func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt,
|
||||
cfg, intf, alt);
|
||||
|
||||
if (cfg != 1 && cfg != 2)
|
||||
goto end_irq;
|
||||
|
||||
imx_usb->set_config = 0;
|
||||
|
||||
/* Config setup */
|
||||
if (imx_usb->cfg != cfg) {
|
||||
D_REQ(imx_usb->dev, "<%s> Change config start\n",__func__);
|
||||
u.bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
u.bRequestType = USB_DIR_OUT |
|
||||
USB_TYPE_STANDARD |
|
||||
|
@ -1070,14 +1048,10 @@ static irqreturn_t imx_udc_irq(int irq, void *dev)
|
|||
u.wIndex = 0;
|
||||
u.wLength = 0;
|
||||
imx_usb->cfg = cfg;
|
||||
imx_usb->set_config = 1;
|
||||
imx_usb->driver->setup(&imx_usb->gadget, &u);
|
||||
imx_usb->set_config = 0;
|
||||
D_REQ(imx_usb->dev, "<%s> Change config done\n",__func__);
|
||||
|
||||
}
|
||||
if (imx_usb->intf != intf || imx_usb->alt != alt) {
|
||||
D_REQ(imx_usb->dev, "<%s> Change interface start\n",__func__);
|
||||
u.bRequest = USB_REQ_SET_INTERFACE;
|
||||
u.bRequestType = USB_DIR_OUT |
|
||||
USB_TYPE_STANDARD |
|
||||
|
@ -1087,20 +1061,92 @@ static irqreturn_t imx_udc_irq(int irq, void *dev)
|
|||
u.wLength = 0;
|
||||
imx_usb->intf = intf;
|
||||
imx_usb->alt = alt;
|
||||
imx_usb->set_config = 1;
|
||||
imx_usb->driver->setup(&imx_usb->gadget, &u);
|
||||
imx_usb->set_config = 0;
|
||||
D_REQ(imx_usb->dev, "<%s> Change interface done\n",__func__);
|
||||
}
|
||||
}
|
||||
|
||||
imx_usb->set_config = 0;
|
||||
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static irqreturn_t imx_udc_irq(int irq, void *dev)
|
||||
{
|
||||
struct imx_udc_struct *imx_usb = dev;
|
||||
int intr = __raw_readl(imx_usb->base + USB_INTR);
|
||||
int temp;
|
||||
|
||||
if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START
|
||||
| INTR_RESET_STOP | INTR_CFG_CHG)) {
|
||||
dump_intr(__func__, intr, imx_usb->dev);
|
||||
dump_usb_stat(__func__, imx_usb);
|
||||
}
|
||||
|
||||
if (!imx_usb->driver)
|
||||
goto end_irq;
|
||||
|
||||
if (intr & INTR_SOF) {
|
||||
/* Copy from Freescale BSP.
|
||||
We must enable SOF intr and set CMDOVER.
|
||||
Datasheet don't specifiy this action, but it
|
||||
is done in Freescale BSP, so just copy it.
|
||||
*/
|
||||
if (imx_usb->ep0state == EP0_IDLE) {
|
||||
temp = __raw_readl(imx_usb->base + USB_CTRL);
|
||||
__raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL);
|
||||
__raw_writel(temp | CTRL_CMDOVER,
|
||||
imx_usb->base + USB_CTRL);
|
||||
}
|
||||
}
|
||||
|
||||
if (intr & INTR_CFG_CHG) {
|
||||
/* A workaround of serious IMX UDC bug.
|
||||
Handling of CFG_CHG should be delayed for some time, because
|
||||
IMX does not NACK the host when CFG_CHG interrupt is pending.
|
||||
There is no time to handle current CFG_CHG
|
||||
if next CFG_CHG or SETUP packed is send immediately.
|
||||
We have to clear CFG_CHG, start the timer and
|
||||
NACK the host by setting CTRL_CMDOVER
|
||||
if it sends any SETUP packet.
|
||||
When timer expires, handler is called to handle configuration
|
||||
changes. While CFG_CHG is not handled (set_config=1),
|
||||
we must NACK the host to every SETUP packed.
|
||||
This delay prevents from going out of sync with host.
|
||||
*/
|
||||
__raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR);
|
||||
imx_usb->set_config = 1;
|
||||
mod_timer(&imx_usb->timer, jiffies + 5);
|
||||
goto end_irq;
|
||||
}
|
||||
|
||||
if (intr & INTR_WAKEUP) {
|
||||
if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN
|
||||
&& imx_usb->driver && imx_usb->driver->resume)
|
||||
imx_usb->driver->resume(&imx_usb->gadget);
|
||||
imx_usb->set_config = 0;
|
||||
del_timer(&imx_usb->timer);
|
||||
imx_usb->gadget.speed = USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
if (intr & INTR_SUSPEND) {
|
||||
if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN
|
||||
&& imx_usb->driver && imx_usb->driver->suspend)
|
||||
imx_usb->driver->suspend(&imx_usb->gadget);
|
||||
imx_usb->set_config = 0;
|
||||
del_timer(&imx_usb->timer);
|
||||
imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
if (intr & INTR_RESET_START) {
|
||||
__raw_writel(intr, imx_usb->base + USB_INTR);
|
||||
udc_stop_activity(imx_usb, imx_usb->driver);
|
||||
imx_usb->set_config = 0;
|
||||
del_timer(&imx_usb->timer);
|
||||
imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
if (intr & INTR_RESET_STOP)
|
||||
imx_usb->gadget.speed = USB_SPEED_FULL;
|
||||
|
||||
end_irq:
|
||||
__raw_writel(intr, imx_usb->base + USB_INTR);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -1109,6 +1155,7 @@ end_irq:
|
|||
static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
|
||||
{
|
||||
struct imx_udc_struct *imx_usb = dev;
|
||||
struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
|
||||
int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0));
|
||||
|
||||
dump_ep_intr(__func__, 0, intr, imx_usb->dev);
|
||||
|
@ -1118,16 +1165,15 @@ static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* DEVREQ IRQ has highest priority */
|
||||
/* DEVREQ has highest priority */
|
||||
if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ))
|
||||
handle_ep0_devreq(imx_usb);
|
||||
/* Seem i.MX is missing EOF interrupt sometimes.
|
||||
* Therefore we monitor both EOF and FIFO_EMPTY interrups
|
||||
* when transmiting, and both EOF and FIFO_FULL when
|
||||
* receiving data.
|
||||
* Therefore we don't monitor EOF.
|
||||
* We call handle_ep0() only if a request is queued for ep0.
|
||||
*/
|
||||
else if (intr & (EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL))
|
||||
handle_ep0(&imx_usb->imx_ep[0]);
|
||||
else if (!list_empty(&imx_ep->queue))
|
||||
handle_ep0(imx_ep);
|
||||
|
||||
__raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
|
||||
|
||||
|
@ -1318,6 +1364,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
udc_stop_activity(imx_usb, driver);
|
||||
imx_udc_disable(imx_usb);
|
||||
del_timer(&imx_usb->timer);
|
||||
|
||||
driver->unbind(&imx_usb->gadget);
|
||||
imx_usb->gadget.dev.driver = NULL;
|
||||
|
@ -1435,6 +1482,10 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
|||
usb_init_data(imx_usb);
|
||||
imx_udc_init(imx_usb);
|
||||
|
||||
init_timer(&imx_usb->timer);
|
||||
imx_usb->timer.function = handle_config;
|
||||
imx_usb->timer.data = (unsigned long)imx_usb;
|
||||
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
|
@ -1457,6 +1508,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
|
|||
int i;
|
||||
|
||||
imx_udc_disable(imx_usb);
|
||||
del_timer(&imx_usb->timer);
|
||||
|
||||
for (i = 0; i < IMX_USB_NB_EP + 1; i++)
|
||||
free_irq(imx_usb->usbd_int[i], imx_usb);
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
/* Helper macros */
|
||||
#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */
|
||||
#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0)
|
||||
#define irq_to_ep(irq) (((irq) >= USBD_INT0) || ((irq) <= USBD_INT6) ? ((irq) - USBD_INT0) : (USBD_INT6)) /*should not happen*/
|
||||
#define irq_to_ep(irq) (((irq) >= USBD_INT0) || ((irq) <= USBD_INT6) \
|
||||
? ((irq) - USBD_INT0) : (USBD_INT6)) /*should not happen*/
|
||||
#define ep_to_irq(ep) (EP_NO((ep)) + USBD_INT0)
|
||||
#define IMX_USB_NB_EP 6
|
||||
|
||||
|
@ -58,6 +59,7 @@ struct imx_udc_struct {
|
|||
struct device *dev;
|
||||
struct imx_ep_struct imx_ep[IMX_USB_NB_EP];
|
||||
struct clk *clk;
|
||||
struct timer_list timer;
|
||||
enum ep0_state ep0state;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
|
@ -88,8 +90,8 @@ struct imx_udc_struct {
|
|||
#define USB_EP_FDAT3(x) (0x3F + (x*0x30)) /* USB FIFO data */
|
||||
#define USB_EP_FSTAT(x) (0x40 + (x*0x30)) /* USB FIFO status */
|
||||
#define USB_EP_FCTRL(x) (0x44 + (x*0x30)) /* USB FIFO control */
|
||||
#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last read frame pointer */
|
||||
#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last write frame pointer */
|
||||
#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last rd f. pointer */
|
||||
#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last wr f. pointer */
|
||||
#define USB_EP_FALRM(x) (0x50 + (x*0x30)) /* USB FIFO alarm */
|
||||
#define USB_EP_FRDP(x) (0x54 + (x*0x30)) /* USB FIFO read pointer */
|
||||
#define USB_EP_FWRP(x) (0x58 + (x*0x30)) /* USB FIFO write pointer */
|
||||
|
@ -170,7 +172,7 @@ struct imx_udc_struct {
|
|||
/* #define DEBUG_IRQ */
|
||||
/* #define DEBUG_EPIRQ */
|
||||
/* #define DEBUG_DUMP */
|
||||
#define DEBUG_ERR
|
||||
/* #define DEBUG_ERR */
|
||||
|
||||
#ifdef DEBUG_REQ
|
||||
#define D_REQ(dev, args...) dev_dbg(dev, ## args)
|
||||
|
@ -228,7 +230,8 @@ struct imx_udc_struct {
|
|||
#endif /* DEBUG_IRQ */
|
||||
|
||||
#ifdef DEBUG_EPIRQ
|
||||
static void dump_ep_intr(const char *label, int nr, int irqreg, struct device *dev)
|
||||
static void dump_ep_intr(const char *label, int nr, int irqreg,
|
||||
struct device *dev)
|
||||
{
|
||||
dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr,
|
||||
(irqreg & EPINTR_FIFO_FULL) ? " full" : "",
|
||||
|
@ -246,7 +249,8 @@ struct imx_udc_struct {
|
|||
#endif /* DEBUG_IRQ */
|
||||
|
||||
#ifdef DEBUG_DUMP
|
||||
static void dump_usb_stat(const char *label, struct imx_udc_struct *imx_usb)
|
||||
static void dump_usb_stat(const char *label,
|
||||
struct imx_udc_struct *imx_usb)
|
||||
{
|
||||
int temp = __raw_readl(imx_usb->base + USB_STAT);
|
||||
|
||||
|
@ -259,12 +263,15 @@ struct imx_udc_struct {
|
|||
(temp & STAT_ALTSET));
|
||||
}
|
||||
|
||||
static void dump_ep_stat(const char *label, struct imx_ep_struct *imx_ep)
|
||||
static void dump_ep_stat(const char *label,
|
||||
struct imx_ep_struct *imx_ep)
|
||||
{
|
||||
int temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
|
||||
int temp = __raw_readl(imx_ep->imx_usb->base
|
||||
+ USB_EP_INTR(EP_NO(imx_ep)));
|
||||
|
||||
dev_dbg(imx_ep->imx_usb->dev,
|
||||
"<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, EP_NO(imx_ep),
|
||||
"<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n",
|
||||
label, EP_NO(imx_ep),
|
||||
(temp & EPINTR_FIFO_FULL) ? " full" : "",
|
||||
(temp & EPINTR_FIFO_EMPTY) ? " fempty" : "",
|
||||
(temp & EPINTR_FIFO_ERROR) ? " ferr" : "",
|
||||
|
@ -275,18 +282,22 @@ struct imx_udc_struct {
|
|||
(temp & EPINTR_DEVREQ) ? " devreq" : "",
|
||||
(temp & EPINTR_EOT) ? " eot" : "");
|
||||
|
||||
temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
|
||||
temp = __raw_readl(imx_ep->imx_usb->base
|
||||
+ USB_EP_STAT(EP_NO(imx_ep)));
|
||||
|
||||
dev_dbg(imx_ep->imx_usb->dev,
|
||||
"<%s> EP%d_STAT=[%s%s bcount=%d]\n", label, EP_NO(imx_ep),
|
||||
"<%s> EP%d_STAT=[%s%s bcount=%d]\n",
|
||||
label, EP_NO(imx_ep),
|
||||
(temp & EPSTAT_SIP) ? " sip" : "",
|
||||
(temp & EPSTAT_STALL) ? " stall" : "",
|
||||
(temp & EPSTAT_BCOUNT) >> 16);
|
||||
|
||||
temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)));
|
||||
temp = __raw_readl(imx_ep->imx_usb->base
|
||||
+ USB_EP_FSTAT(EP_NO(imx_ep)));
|
||||
|
||||
dev_dbg(imx_ep->imx_usb->dev,
|
||||
"<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n", label, EP_NO(imx_ep),
|
||||
"<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n",
|
||||
label, EP_NO(imx_ep),
|
||||
(temp & FSTAT_ERR) ? " ferr" : "",
|
||||
(temp & FSTAT_UF) ? " funder" : "",
|
||||
(temp & FSTAT_OF) ? " fover" : "",
|
||||
|
@ -296,19 +307,23 @@ struct imx_udc_struct {
|
|||
(temp & FSTAT_EMPTY) ? " fempty" : "");
|
||||
}
|
||||
|
||||
static void dump_req(const char *label, struct imx_ep_struct *imx_ep, struct usb_request *req)
|
||||
static void dump_req(const char *label, struct imx_ep_struct *imx_ep,
|
||||
struct usb_request *req)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!req || !req->buf) {
|
||||
dev_dbg(imx_ep->imx_usb->dev, "<%s> req or req buf is free\n", label);
|
||||
dev_dbg(imx_ep->imx_usb->dev,
|
||||
"<%s> req or req buf is free\n", label);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state == EP0_IN_DATA_PHASE)
|
||||
if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
|
||||
== EP0_IN_DATA_PHASE)
|
||||
|| (EP_NO(imx_ep) && EP_DIR(imx_ep))) {
|
||||
|
||||
dev_dbg(imx_ep->imx_usb->dev, "<%s> request dump <", label);
|
||||
dev_dbg(imx_ep->imx_usb->dev,
|
||||
"<%s> request dump <", label);
|
||||
for (i = 0; i < req->length; i++)
|
||||
printk("%02x-", *((u8 *)req->buf + i));
|
||||
printk(">\n");
|
||||
|
|
|
@ -1334,7 +1334,7 @@ static void make_qualifier (struct dev_data *dev)
|
|||
|
||||
qual.bLength = sizeof qual;
|
||||
qual.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
|
||||
qual.bcdUSB = __constant_cpu_to_le16 (0x0200);
|
||||
qual.bcdUSB = cpu_to_le16 (0x0200);
|
||||
|
||||
desc = dev->dev;
|
||||
qual.bDeviceClass = desc->bDeviceClass;
|
||||
|
@ -1908,7 +1908,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
|||
|| dev->dev->bNumConfigurations != 1)
|
||||
goto fail;
|
||||
dev->dev->bNumConfigurations = 1;
|
||||
dev->dev->bcdUSB = __constant_cpu_to_le16 (0x0200);
|
||||
dev->dev->bcdUSB = cpu_to_le16 (0x0200);
|
||||
|
||||
/* triggers gadgetfs_bind(); then we can enumerate. */
|
||||
spin_unlock_irq (&dev->lock);
|
||||
|
|
|
@ -432,8 +432,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
device_add(&dev->gadget.dev);
|
||||
retval = driver->bind(&dev->gadget);
|
||||
if (retval) {
|
||||
printk("%s: bind to driver %s --> error %d\n", dev->gadget.name,
|
||||
driver->driver.name, retval);
|
||||
printk(KERN_WARNING "%s: bind to driver %s --> error %d\n",
|
||||
dev->gadget.name, driver->driver.name, retval);
|
||||
device_del(&dev->gadget.dev);
|
||||
|
||||
dev->driver = 0;
|
||||
|
@ -445,8 +445,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
* for set_configuration as well as eventual disconnect.
|
||||
* NOTE: this shouldn't power up until later.
|
||||
*/
|
||||
printk("%s: registered gadget driver '%s'\n", dev->gadget.name,
|
||||
driver->driver.name);
|
||||
printk(KERN_WARNING "%s: registered gadget driver '%s'\n",
|
||||
dev->gadget.name, driver->driver.name);
|
||||
|
||||
udc_enable(dev);
|
||||
|
||||
|
@ -581,7 +581,8 @@ static int read_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
|
|||
* discard the extra data.
|
||||
*/
|
||||
if (req->req.status != -EOVERFLOW)
|
||||
printk("%s overflow %d\n", ep->ep.name, count);
|
||||
printk(KERN_WARNING "%s overflow %d\n",
|
||||
ep->ep.name, count);
|
||||
req->req.status = -EOVERFLOW;
|
||||
} else {
|
||||
*buf++ = byte;
|
||||
|
@ -831,7 +832,8 @@ static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
|
|||
queue);
|
||||
|
||||
if (!req) {
|
||||
printk("%s: NULL REQ %d\n",
|
||||
printk(KERN_WARNING
|
||||
"%s: NULL REQ %d\n",
|
||||
__func__, ep_idx);
|
||||
flush(ep);
|
||||
break;
|
||||
|
@ -844,7 +846,7 @@ static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
|
|||
|
||||
} else {
|
||||
/* Throw packet away.. */
|
||||
printk("%s: No descriptor?!?\n", __func__);
|
||||
printk(KERN_WARNING "%s: No descriptor?!?\n", __func__);
|
||||
flush(ep);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,8 +142,8 @@ static char *type_string (u8 bmAttributes)
|
|||
|
||||
#include "net2280.h"
|
||||
|
||||
#define valid_bit __constant_cpu_to_le32 (1 << VALID_BIT)
|
||||
#define dma_done_ie __constant_cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
|
||||
#define valid_bit cpu_to_le32 (1 << VALID_BIT)
|
||||
#define dma_done_ie cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -425,7 +425,7 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
|
|||
return NULL;
|
||||
}
|
||||
td->dmacount = 0; /* not VALID */
|
||||
td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
|
||||
td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
|
||||
td->dmadesc = td->dmaaddr;
|
||||
req->td = td;
|
||||
}
|
||||
|
@ -775,7 +775,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
|
|||
fill_dma_desc (ep, req, 1);
|
||||
|
||||
if (!use_dma_chaining)
|
||||
req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
|
||||
req->td->dmacount |= cpu_to_le32 (1 << END_OF_CHAIN);
|
||||
|
||||
start_queue (ep, tmp, req->td_dma);
|
||||
}
|
||||
|
@ -2407,9 +2407,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
|
||||
if (readl (&e->regs->ep_rsp)
|
||||
& (1 << SET_ENDPOINT_HALT))
|
||||
status = __constant_cpu_to_le32 (1);
|
||||
status = cpu_to_le32 (1);
|
||||
else
|
||||
status = __constant_cpu_to_le32 (0);
|
||||
status = cpu_to_le32 (0);
|
||||
|
||||
/* don't bother with a request object! */
|
||||
writel (0, &dev->epregs [0].ep_irqenb);
|
||||
|
@ -2667,7 +2667,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
|
|||
req = list_entry (ep->queue.next,
|
||||
struct net2280_request, queue);
|
||||
dmacount = req->td->dmacount;
|
||||
dmacount &= __constant_cpu_to_le32 (
|
||||
dmacount &= cpu_to_le32 (
|
||||
(1 << VALID_BIT)
|
||||
| DMA_BYTE_COUNT_MASK);
|
||||
if (dmacount && (dmacount & valid_bit) == 0)
|
||||
|
@ -2881,7 +2881,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
goto done;
|
||||
}
|
||||
td->dmacount = 0; /* not VALID */
|
||||
td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
|
||||
td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
|
||||
td->dmadesc = td->dmaaddr;
|
||||
dev->ep [i].dummy = td;
|
||||
}
|
||||
|
|
|
@ -225,12 +225,12 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR);
|
|||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PER_INTERFACE,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.idVendor = __constant_cpu_to_le16(PRINTER_VENDOR_NUM),
|
||||
.idProduct = __constant_cpu_to_le16(PRINTER_PRODUCT_NUM),
|
||||
.idVendor = cpu_to_le16(PRINTER_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16(PRINTER_PRODUCT_NUM),
|
||||
.iManufacturer = STRING_MANUFACTURER,
|
||||
.iProduct = STRING_PRODUCT,
|
||||
.iSerialNumber = STRING_SERIALNUM,
|
||||
|
@ -299,20 +299,20 @@ static struct usb_endpoint_descriptor hs_ep_in_desc = {
|
|||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512)
|
||||
.wMaxPacketSize = cpu_to_le16(512)
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ep_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512)
|
||||
.wMaxPacketSize = cpu_to_le16(512)
|
||||
};
|
||||
|
||||
static struct usb_qualifier_descriptor dev_qualifier = {
|
||||
.bLength = sizeof dev_qualifier,
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PRINTER,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
@ -1406,16 +1406,16 @@ printer_bind(struct usb_gadget *gadget)
|
|||
gadget->name);
|
||||
/* unrecognized, but safe unless bulk is REALLY quirky */
|
||||
device_desc.bcdDevice =
|
||||
__constant_cpu_to_le16(0xFFFF);
|
||||
cpu_to_le16(0xFFFF);
|
||||
}
|
||||
snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
|
||||
init_utsname()->sysname, init_utsname()->release,
|
||||
gadget->name);
|
||||
|
||||
device_desc.idVendor =
|
||||
__constant_cpu_to_le16(PRINTER_VENDOR_NUM);
|
||||
cpu_to_le16(PRINTER_VENDOR_NUM);
|
||||
device_desc.idProduct =
|
||||
__constant_cpu_to_le16(PRINTER_PRODUCT_NUM);
|
||||
cpu_to_le16(PRINTER_PRODUCT_NUM);
|
||||
|
||||
/* support optional vendor/distro customization */
|
||||
if (idVendor) {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/proc_fs.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <mach/hardware.h>
|
||||
|
@ -278,7 +279,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc)
|
|||
goto err_queues;
|
||||
eps = debugfs_create_file("epstate", 0400, root, udc,
|
||||
&eps_dbg_fops);
|
||||
if (!queues)
|
||||
if (!eps)
|
||||
goto err_eps;
|
||||
|
||||
udc->debugfs_root = root;
|
||||
|
@ -747,13 +748,13 @@ static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
|
|||
}
|
||||
|
||||
/**
|
||||
* ep_end_out_req - Ends control endpoint in request
|
||||
* ep_end_out_req - Ends endpoint OUT request
|
||||
* @ep: physical endpoint
|
||||
* @req: pxa request
|
||||
*
|
||||
* Context: ep->lock held
|
||||
*
|
||||
* Ends endpoint in request (completes usb request).
|
||||
* Ends endpoint OUT request (completes usb request).
|
||||
*/
|
||||
static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
|
||||
{
|
||||
|
@ -762,13 +763,13 @@ static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
|
|||
}
|
||||
|
||||
/**
|
||||
* ep0_end_out_req - Ends control endpoint in request (ends data stage)
|
||||
* ep0_end_out_req - Ends control endpoint OUT request (ends data stage)
|
||||
* @ep: physical endpoint
|
||||
* @req: pxa request
|
||||
*
|
||||
* Context: ep->lock held
|
||||
*
|
||||
* Ends control endpoint in request (completes usb request), and puts
|
||||
* Ends control endpoint OUT request (completes usb request), and puts
|
||||
* control endpoint into idle state
|
||||
*/
|
||||
static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
|
||||
|
@ -779,13 +780,13 @@ static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
|
|||
}
|
||||
|
||||
/**
|
||||
* ep_end_in_req - Ends endpoint out request
|
||||
* ep_end_in_req - Ends endpoint IN request
|
||||
* @ep: physical endpoint
|
||||
* @req: pxa request
|
||||
*
|
||||
* Context: ep->lock held
|
||||
*
|
||||
* Ends endpoint out request (completes usb request).
|
||||
* Ends endpoint IN request (completes usb request).
|
||||
*/
|
||||
static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
|
||||
{
|
||||
|
@ -794,20 +795,18 @@ static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
|
|||
}
|
||||
|
||||
/**
|
||||
* ep0_end_in_req - Ends control endpoint out request (ends data stage)
|
||||
* ep0_end_in_req - Ends control endpoint IN request (ends data stage)
|
||||
* @ep: physical endpoint
|
||||
* @req: pxa request
|
||||
*
|
||||
* Context: ep->lock held
|
||||
*
|
||||
* Ends control endpoint out request (completes usb request), and puts
|
||||
* Ends control endpoint IN request (completes usb request), and puts
|
||||
* control endpoint into status state
|
||||
*/
|
||||
static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
|
||||
{
|
||||
struct pxa_udc *udc = ep->dev;
|
||||
|
||||
set_ep0state(udc, IN_STATUS_STAGE);
|
||||
set_ep0state(ep->dev, IN_STATUS_STAGE);
|
||||
ep_end_in_req(ep, req);
|
||||
}
|
||||
|
||||
|
@ -1167,7 +1166,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
|
|||
ep_end_in_req(ep, req);
|
||||
} else {
|
||||
ep_err(ep, "got a request of %d bytes while"
|
||||
"in state WATI_ACK_SET_CONF_INTERF\n",
|
||||
"in state WAIT_ACK_SET_CONF_INTERF\n",
|
||||
length);
|
||||
ep_del_request(ep, req);
|
||||
rc = -EL2HLT;
|
||||
|
@ -1213,30 +1212,26 @@ static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
|||
struct udc_usb_ep *udc_usb_ep;
|
||||
struct pxa27x_request *req;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
int rc = -EINVAL;
|
||||
|
||||
if (!_ep)
|
||||
return -EINVAL;
|
||||
return rc;
|
||||
udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
|
||||
ep = udc_usb_ep->pxa_ep;
|
||||
if (!ep || is_ep0(ep))
|
||||
return -EINVAL;
|
||||
return rc;
|
||||
|
||||
spin_lock_irqsave(&ep->lock, flags);
|
||||
|
||||
/* make sure it's actually queued on this endpoint */
|
||||
list_for_each_entry(req, &ep->queue, queue) {
|
||||
if (&req->req == _req)
|
||||
if (&req->req == _req) {
|
||||
req_done(ep, req, -ECONNRESET);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = -EINVAL;
|
||||
if (&req->req != _req)
|
||||
goto out;
|
||||
|
||||
rc = 0;
|
||||
req_done(ep, req, -ECONNRESET);
|
||||
out:
|
||||
spin_unlock_irqrestore(&ep->lock, flags);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1471,6 +1466,32 @@ static struct usb_ep_ops pxa_ep_ops = {
|
|||
.fifo_flush = pxa_ep_fifo_flush,
|
||||
};
|
||||
|
||||
/**
|
||||
* dplus_pullup - Connect or disconnect pullup resistor to D+ pin
|
||||
* @udc: udc device
|
||||
* @on: 0 if disconnect pullup resistor, 1 otherwise
|
||||
* Context: any
|
||||
*
|
||||
* Handle D+ pullup resistor, make the device visible to the usb bus, and
|
||||
* declare it as a full speed usb device
|
||||
*/
|
||||
static void dplus_pullup(struct pxa_udc *udc, int on)
|
||||
{
|
||||
if (on) {
|
||||
if (gpio_is_valid(udc->mach->gpio_pullup))
|
||||
gpio_set_value(udc->mach->gpio_pullup,
|
||||
!udc->mach->gpio_pullup_inverted);
|
||||
if (udc->mach->udc_command)
|
||||
udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
|
||||
} else {
|
||||
if (gpio_is_valid(udc->mach->gpio_pullup))
|
||||
gpio_set_value(udc->mach->gpio_pullup,
|
||||
udc->mach->gpio_pullup_inverted);
|
||||
if (udc->mach->udc_command)
|
||||
udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
|
||||
}
|
||||
udc->pullup_on = on;
|
||||
}
|
||||
|
||||
/**
|
||||
* pxa_udc_get_frame - Returns usb frame number
|
||||
|
@ -1500,21 +1521,145 @@ static int pxa_udc_wakeup(struct usb_gadget *_gadget)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void udc_enable(struct pxa_udc *udc);
|
||||
static void udc_disable(struct pxa_udc *udc);
|
||||
|
||||
/**
|
||||
* should_enable_udc - Tells if UDC should be enabled
|
||||
* @udc: udc device
|
||||
* Context: any
|
||||
*
|
||||
* The UDC should be enabled if :
|
||||
|
||||
* - the pullup resistor is connected
|
||||
* - and a gadget driver is bound
|
||||
* - and vbus is sensed (or no vbus sense is available)
|
||||
*
|
||||
* Returns 1 if UDC should be enabled, 0 otherwise
|
||||
*/
|
||||
static int should_enable_udc(struct pxa_udc *udc)
|
||||
{
|
||||
int put_on;
|
||||
|
||||
put_on = ((udc->pullup_on) && (udc->driver));
|
||||
put_on &= ((udc->vbus_sensed) || (!udc->transceiver));
|
||||
return put_on;
|
||||
}
|
||||
|
||||
/**
|
||||
* should_disable_udc - Tells if UDC should be disabled
|
||||
* @udc: udc device
|
||||
* Context: any
|
||||
*
|
||||
* The UDC should be disabled if :
|
||||
* - the pullup resistor is not connected
|
||||
* - or no gadget driver is bound
|
||||
* - or no vbus is sensed (when vbus sesing is available)
|
||||
*
|
||||
* Returns 1 if UDC should be disabled
|
||||
*/
|
||||
static int should_disable_udc(struct pxa_udc *udc)
|
||||
{
|
||||
int put_off;
|
||||
|
||||
put_off = ((!udc->pullup_on) || (!udc->driver));
|
||||
put_off |= ((!udc->vbus_sensed) && (udc->transceiver));
|
||||
return put_off;
|
||||
}
|
||||
|
||||
/**
|
||||
* pxa_udc_pullup - Offer manual D+ pullup control
|
||||
* @_gadget: usb gadget using the control
|
||||
* @is_active: 0 if disconnect, else connect D+ pullup resistor
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup
|
||||
*/
|
||||
static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active)
|
||||
{
|
||||
struct pxa_udc *udc = to_gadget_udc(_gadget);
|
||||
|
||||
if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
dplus_pullup(udc, is_active);
|
||||
|
||||
if (should_enable_udc(udc))
|
||||
udc_enable(udc);
|
||||
if (should_disable_udc(udc))
|
||||
udc_disable(udc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void udc_enable(struct pxa_udc *udc);
|
||||
static void udc_disable(struct pxa_udc *udc);
|
||||
|
||||
/**
|
||||
* pxa_udc_vbus_session - Called by external transceiver to enable/disable udc
|
||||
* @_gadget: usb gadget
|
||||
* @is_active: 0 if should disable the udc, 1 if should enable
|
||||
*
|
||||
* Enables the udc, and optionnaly activates D+ pullup resistor. Or disables the
|
||||
* udc, and deactivates D+ pullup resistor.
|
||||
*
|
||||
* Returns 0
|
||||
*/
|
||||
static int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
|
||||
{
|
||||
struct pxa_udc *udc = to_gadget_udc(_gadget);
|
||||
|
||||
udc->vbus_sensed = is_active;
|
||||
if (should_enable_udc(udc))
|
||||
udc_enable(udc);
|
||||
if (should_disable_udc(udc))
|
||||
udc_disable(udc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pxa_udc_vbus_draw - Called by gadget driver after SET_CONFIGURATION completed
|
||||
* @_gadget: usb gadget
|
||||
* @mA: current drawn
|
||||
*
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Called after a configuration was chosen by a USB host, to inform how much
|
||||
* current can be drawn by the device from VBus line.
|
||||
*
|
||||
* Returns 0 or -EOPNOTSUPP if no transceiver is handling the udc
|
||||
*/
|
||||
static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
{
|
||||
struct pxa_udc *udc;
|
||||
|
||||
udc = to_gadget_udc(_gadget);
|
||||
if (udc->transceiver)
|
||||
return otg_set_power(udc->transceiver, mA);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct usb_gadget_ops pxa_udc_ops = {
|
||||
.get_frame = pxa_udc_get_frame,
|
||||
.wakeup = pxa_udc_wakeup,
|
||||
/* current versions must always be self-powered */
|
||||
.pullup = pxa_udc_pullup,
|
||||
.vbus_session = pxa_udc_vbus_session,
|
||||
.vbus_draw = pxa_udc_vbus_draw,
|
||||
};
|
||||
|
||||
/**
|
||||
* udc_disable - disable udc device controller
|
||||
* @udc: udc device
|
||||
* Context: any
|
||||
*
|
||||
* Disables the udc device : disables clocks, udc interrupts, control endpoint
|
||||
* interrupts.
|
||||
*/
|
||||
static void udc_disable(struct pxa_udc *udc)
|
||||
{
|
||||
if (!udc->enabled)
|
||||
return;
|
||||
|
||||
udc_writel(udc, UDCICR0, 0);
|
||||
udc_writel(udc, UDCICR1, 0);
|
||||
|
||||
|
@ -1523,8 +1668,8 @@ static void udc_disable(struct pxa_udc *udc)
|
|||
|
||||
ep0_idle(udc);
|
||||
udc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
if (udc->mach->udc_command)
|
||||
udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
|
||||
|
||||
udc->enabled = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1555,10 +1700,9 @@ static __init void udc_init_data(struct pxa_udc *dev)
|
|||
}
|
||||
|
||||
/* USB endpoints init */
|
||||
for (i = 0; i < NR_USB_ENDPOINTS; i++)
|
||||
if (i != 0)
|
||||
list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
|
||||
&dev->gadget.ep_list);
|
||||
for (i = 1; i < NR_USB_ENDPOINTS; i++)
|
||||
list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
|
||||
&dev->gadget.ep_list);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1570,6 +1714,9 @@ static __init void udc_init_data(struct pxa_udc *dev)
|
|||
*/
|
||||
static void udc_enable(struct pxa_udc *udc)
|
||||
{
|
||||
if (udc->enabled)
|
||||
return;
|
||||
|
||||
udc_writel(udc, UDCICR0, 0);
|
||||
udc_writel(udc, UDCICR1, 0);
|
||||
udc_clear_mask_UDCCR(udc, UDCCR_UDE);
|
||||
|
@ -1598,9 +1745,7 @@ static void udc_enable(struct pxa_udc *udc)
|
|||
/* enable ep0 irqs */
|
||||
pio_irq_enable(&udc->pxa_ep[0]);
|
||||
|
||||
dev_info(udc->dev, "UDC connecting\n");
|
||||
if (udc->mach->udc_command)
|
||||
udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
|
||||
udc->enabled = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1612,6 +1757,9 @@ static void udc_enable(struct pxa_udc *udc)
|
|||
* usb traffic follows until a disconnect is reported. Then a host may connect
|
||||
* again, or the driver might get unbound.
|
||||
*
|
||||
* Note that the udc is not automatically enabled. Check function
|
||||
* should_enable_udc().
|
||||
*
|
||||
* Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
|
@ -1630,6 +1778,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
/* first hook up the driver ... */
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
dplus_pullup(udc, 1);
|
||||
|
||||
retval = device_add(&udc->gadget.dev);
|
||||
if (retval) {
|
||||
|
@ -1645,9 +1794,21 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
dev_dbg(udc->dev, "registered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
|
||||
udc_enable(udc);
|
||||
if (udc->transceiver) {
|
||||
retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
|
||||
if (retval) {
|
||||
dev_err(udc->dev, "can't bind to transceiver\n");
|
||||
goto transceiver_fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_enable_udc(udc))
|
||||
udc_enable(udc);
|
||||
return 0;
|
||||
|
||||
transceiver_fail:
|
||||
if (driver->unbind)
|
||||
driver->unbind(&udc->gadget);
|
||||
bind_fail:
|
||||
device_del(&udc->gadget.dev);
|
||||
add_fail:
|
||||
|
@ -1699,14 +1860,17 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
stop_activity(udc, driver);
|
||||
udc_disable(udc);
|
||||
dplus_pullup(udc, 0);
|
||||
|
||||
driver->unbind(&udc->gadget);
|
||||
udc->driver = NULL;
|
||||
|
||||
device_del(&udc->gadget.dev);
|
||||
|
||||
dev_info(udc->dev, "unregistered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
|
||||
if (udc->transceiver)
|
||||
return otg_set_peripheral(udc->transceiver, NULL);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
|
@ -1823,14 +1987,14 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
|
|||
struct pxa27x_request *req = NULL;
|
||||
int completed = 0;
|
||||
|
||||
if (!list_empty(&ep->queue))
|
||||
req = list_entry(ep->queue.next, struct pxa27x_request, queue);
|
||||
|
||||
udccsr0 = udc_ep_readl(ep, UDCCSR);
|
||||
ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n",
|
||||
EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR),
|
||||
(fifo_irq << 1 | opc_irq));
|
||||
|
||||
if (!list_empty(&ep->queue))
|
||||
req = list_entry(ep->queue.next, struct pxa27x_request, queue);
|
||||
|
||||
if (udccsr0 & UDCCSR0_SST) {
|
||||
ep_dbg(ep, "clearing stall status\n");
|
||||
nuke(ep, -EPIPE);
|
||||
|
@ -2212,7 +2376,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct resource *regs;
|
||||
struct pxa_udc *udc = &memory;
|
||||
int retval;
|
||||
int retval = 0, gpio;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs)
|
||||
|
@ -2223,6 +2387,20 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
|||
|
||||
udc->dev = &pdev->dev;
|
||||
udc->mach = pdev->dev.platform_data;
|
||||
udc->transceiver = otg_get_transceiver();
|
||||
|
||||
gpio = udc->mach->gpio_pullup;
|
||||
if (gpio_is_valid(gpio)) {
|
||||
retval = gpio_request(gpio, "USB D+ pullup");
|
||||
if (retval == 0)
|
||||
gpio_direction_output(gpio,
|
||||
udc->mach->gpio_pullup_inverted);
|
||||
}
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "Couldn't request gpio %d : %d\n",
|
||||
gpio, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
udc->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(udc->clk)) {
|
||||
|
@ -2240,6 +2418,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
|||
device_initialize(&udc->gadget.dev);
|
||||
udc->gadget.dev.parent = &pdev->dev;
|
||||
udc->gadget.dev.dma_mask = NULL;
|
||||
udc->vbus_sensed = 0;
|
||||
|
||||
the_controller = udc;
|
||||
platform_set_drvdata(pdev, udc);
|
||||
|
@ -2273,14 +2452,21 @@ err_clk:
|
|||
static int __exit pxa_udc_remove(struct platform_device *_dev)
|
||||
{
|
||||
struct pxa_udc *udc = platform_get_drvdata(_dev);
|
||||
int gpio = udc->mach->gpio_pullup;
|
||||
|
||||
usb_gadget_unregister_driver(udc->driver);
|
||||
free_irq(udc->irq, udc);
|
||||
pxa_cleanup_debugfs(udc);
|
||||
if (gpio_is_valid(gpio))
|
||||
gpio_free(gpio);
|
||||
|
||||
otg_put_transceiver(udc->transceiver);
|
||||
|
||||
udc->transceiver = NULL;
|
||||
platform_set_drvdata(_dev, NULL);
|
||||
the_controller = NULL;
|
||||
clk_put(udc->clk);
|
||||
iounmap(udc->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2319,6 +2505,8 @@ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
|
|||
}
|
||||
|
||||
udc_disable(udc);
|
||||
udc->pullup_resume = udc->pullup_on;
|
||||
dplus_pullup(udc, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2346,7 +2534,9 @@ static int pxa_udc_resume(struct platform_device *_dev)
|
|||
ep->udccsr_value, ep->udccr_value);
|
||||
}
|
||||
|
||||
udc_enable(udc);
|
||||
dplus_pullup(udc, udc->pullup_resume);
|
||||
if (should_enable_udc(udc))
|
||||
udc_enable(udc);
|
||||
/*
|
||||
* We do not handle OTG yet.
|
||||
*
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
/*
|
||||
* Register definitions
|
||||
|
@ -421,10 +422,14 @@ struct udc_stats {
|
|||
* @driver: bound gadget (zero, g_ether, g_file_storage, ...)
|
||||
* @dev: device
|
||||
* @mach: machine info, used to activate specific GPIO
|
||||
* @transceiver: external transceiver to handle vbus sense and D+ pullup
|
||||
* @ep0state: control endpoint state machine state
|
||||
* @stats: statistics on udc usage
|
||||
* @udc_usb_ep: array of usb endpoints offered by the gadget
|
||||
* @pxa_ep: array of pxa available endpoints
|
||||
* @enabled: UDC was enabled by a previous udc_enable()
|
||||
* @pullup_on: if pullup resistor connected to D+ pin
|
||||
* @pullup_resume: if pullup resistor should be connected to D+ pin on resume
|
||||
* @config: UDC active configuration
|
||||
* @last_interface: UDC interface of the last SET_INTERFACE host request
|
||||
* @last_alternate: UDC altsetting of the last SET_INTERFACE host request
|
||||
|
@ -443,6 +448,7 @@ struct pxa_udc {
|
|||
struct usb_gadget_driver *driver;
|
||||
struct device *dev;
|
||||
struct pxa2xx_udc_mach_info *mach;
|
||||
struct otg_transceiver *transceiver;
|
||||
|
||||
enum ep0_state ep0state;
|
||||
struct udc_stats stats;
|
||||
|
@ -450,6 +456,10 @@ struct pxa_udc {
|
|||
struct udc_usb_ep udc_usb_ep[NR_USB_ENDPOINTS];
|
||||
struct pxa_ep pxa_ep[NR_PXA_ENDPOINTS];
|
||||
|
||||
unsigned enabled:1;
|
||||
unsigned pullup_on:1;
|
||||
unsigned pullup_resume:1;
|
||||
unsigned vbus_sensed:1;
|
||||
unsigned config:2;
|
||||
unsigned last_interface:3;
|
||||
unsigned last_alternate:3;
|
||||
|
|
|
@ -87,12 +87,12 @@ static struct usb_gadget_strings *dev_strings[] = {
|
|||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
/* .bDeviceClass = f(use_acm) */
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
/* .bMaxPacketSize0 = f(hardware) */
|
||||
.idVendor = __constant_cpu_to_le16(GS_VENDOR_ID),
|
||||
.idVendor = cpu_to_le16(GS_VENDOR_ID),
|
||||
/* .idProduct = f(use_acm) */
|
||||
/* .bcdDevice = f(hardware) */
|
||||
/* .iManufacturer = DYNAMIC */
|
||||
|
@ -216,7 +216,7 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
|
|||
pr_warning("gs_bind: controller '%s' not recognized\n",
|
||||
gadget->name);
|
||||
device_desc.bcdDevice =
|
||||
__constant_cpu_to_le16(GS_VERSION_NUM | 0x0099);
|
||||
cpu_to_le16(GS_VERSION_NUM | 0x0099);
|
||||
}
|
||||
|
||||
if (gadget_is_otg(cdev->gadget)) {
|
||||
|
@ -255,19 +255,19 @@ static int __init init(void)
|
|||
serial_config_driver.bConfigurationValue = 2;
|
||||
device_desc.bDeviceClass = USB_CLASS_COMM;
|
||||
device_desc.idProduct =
|
||||
__constant_cpu_to_le16(GS_CDC_PRODUCT_ID);
|
||||
cpu_to_le16(GS_CDC_PRODUCT_ID);
|
||||
} else if (use_obex) {
|
||||
serial_config_driver.label = "CDC OBEX config";
|
||||
serial_config_driver.bConfigurationValue = 3;
|
||||
device_desc.bDeviceClass = USB_CLASS_COMM;
|
||||
device_desc.idProduct =
|
||||
__constant_cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
|
||||
cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
|
||||
} else {
|
||||
serial_config_driver.label = "Generic Serial config";
|
||||
serial_config_driver.bConfigurationValue = 1;
|
||||
device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
|
||||
device_desc.idProduct =
|
||||
__constant_cpu_to_le16(GS_PRODUCT_ID);
|
||||
cpu_to_le16(GS_PRODUCT_ID);
|
||||
}
|
||||
strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
|
||||
|
||||
|
|
|
@ -1092,7 +1092,7 @@ int __init gserial_setup(struct usb_gadget *g, unsigned count)
|
|||
gs_tty_driver->init_termios.c_ispeed = 9600;
|
||||
gs_tty_driver->init_termios.c_ospeed = 9600;
|
||||
|
||||
coding.dwDTERate = __constant_cpu_to_le32(9600);
|
||||
coding.dwDTERate = cpu_to_le32(9600);
|
||||
coding.bCharFormat = 8;
|
||||
coding.bParityType = USB_CDC_NO_PARITY;
|
||||
coding.bDataBits = USB_CDC_1_STOP_BITS;
|
||||
|
|
|
@ -102,22 +102,32 @@ module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
|
|||
#ifndef CONFIG_USB_ZERO_HNPTEST
|
||||
#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
|
||||
#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
|
||||
#define DEFAULT_AUTORESUME 0
|
||||
#else
|
||||
#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
|
||||
#define DRIVER_PRODUCT_NUM 0xbadd
|
||||
#define DEFAULT_AUTORESUME 5
|
||||
#endif
|
||||
|
||||
/* If the optional "autoresume" mode is enabled, it provides good
|
||||
* functional coverage for the "USBCV" test harness from USB-IF.
|
||||
* It's always set if OTG mode is enabled.
|
||||
*/
|
||||
unsigned autoresume = DEFAULT_AUTORESUME;
|
||||
module_param(autoresume, uint, S_IRUGO);
|
||||
MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_device_descriptor device_desc = {
|
||||
.bLength = sizeof device_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
|
||||
.bcdUSB = __constant_cpu_to_le16(0x0200),
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
|
||||
|
||||
.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
|
||||
.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
|
||||
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
|
||||
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
|
||||
.bNumConfigurations = 2,
|
||||
};
|
||||
|
||||
|
@ -212,6 +222,47 @@ void disable_endpoints(struct usb_composite_dev *cdev,
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct timer_list autoresume_timer;
|
||||
|
||||
static void zero_autoresume(unsigned long _c)
|
||||
{
|
||||
struct usb_composite_dev *cdev = (void *)_c;
|
||||
struct usb_gadget *g = cdev->gadget;
|
||||
|
||||
/* unconfigured devices can't issue wakeups */
|
||||
if (!cdev->config)
|
||||
return;
|
||||
|
||||
/* Normally the host would be woken up for something
|
||||
* more significant than just a timer firing; likely
|
||||
* because of some direct user request.
|
||||
*/
|
||||
if (g->speed != USB_SPEED_UNKNOWN) {
|
||||
int status = usb_gadget_wakeup(g);
|
||||
INFO(cdev, "%s --> %d\n", __func__, status);
|
||||
}
|
||||
}
|
||||
|
||||
static void zero_suspend(struct usb_composite_dev *cdev)
|
||||
{
|
||||
if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
|
||||
return;
|
||||
|
||||
if (autoresume) {
|
||||
mod_timer(&autoresume_timer, jiffies + (HZ * autoresume));
|
||||
DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume);
|
||||
} else
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static void zero_resume(struct usb_composite_dev *cdev)
|
||||
{
|
||||
DBG(cdev, "%s\n", __func__);
|
||||
del_timer(&autoresume_timer);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init zero_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
|
@ -239,17 +290,19 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
|
|||
strings_dev[STRING_SERIAL_IDX].id = id;
|
||||
device_desc.iSerialNumber = id;
|
||||
|
||||
setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
|
||||
|
||||
/* Register primary, then secondary configuration. Note that
|
||||
* SH3 only allows one config...
|
||||
*/
|
||||
if (loopdefault) {
|
||||
loopback_add(cdev);
|
||||
loopback_add(cdev, autoresume != 0);
|
||||
if (!gadget_is_sh(gadget))
|
||||
sourcesink_add(cdev);
|
||||
sourcesink_add(cdev, autoresume != 0);
|
||||
} else {
|
||||
sourcesink_add(cdev);
|
||||
sourcesink_add(cdev, autoresume != 0);
|
||||
if (!gadget_is_sh(gadget))
|
||||
loopback_add(cdev);
|
||||
loopback_add(cdev, autoresume != 0);
|
||||
}
|
||||
|
||||
gcnum = usb_gadget_controller_number(gadget);
|
||||
|
@ -265,7 +318,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
|
|||
*/
|
||||
pr_warning("%s: controller '%s' not recognized\n",
|
||||
longname, gadget->name);
|
||||
device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
|
||||
device_desc.bcdDevice = cpu_to_le16(0x9999);
|
||||
}
|
||||
|
||||
|
||||
|
@ -278,11 +331,20 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int zero_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
del_timer_sync(&autoresume_timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_composite_driver zero_driver = {
|
||||
.name = "zero",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = zero_bind,
|
||||
.unbind = zero_unbind,
|
||||
.suspend = zero_suspend,
|
||||
.resume = zero_resume,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
|
|
@ -24,10 +24,7 @@ config USB_EHCI_HCD
|
|||
The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
|
||||
"high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
|
||||
If your USB host controller supports USB 2.0, you will likely want to
|
||||
configure this Host Controller Driver. At the time of this writing,
|
||||
the primary implementation of EHCI is a chip from NEC, widely available
|
||||
in add-on PCI cards, but implementations are in the works from other
|
||||
vendors including Intel and Philips. Motherboard support is appearing.
|
||||
configure this Host Controller Driver.
|
||||
|
||||
EHCI controllers are packaged with "companion" host controllers (OHCI
|
||||
or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports
|
||||
|
@ -123,7 +120,7 @@ config USB_ISP116X_HCD
|
|||
|
||||
config USB_ISP1760_HCD
|
||||
tristate "ISP 1760 HCD support"
|
||||
depends on USB && EXPERIMENTAL && (PCI || PPC_OF)
|
||||
depends on USB && EXPERIMENTAL
|
||||
---help---
|
||||
The ISP1760 chip is a USB 2.0 host controller.
|
||||
|
||||
|
|
|
@ -110,6 +110,42 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||
{
|
||||
/* Don't override timeouts which shrink or (later) disable
|
||||
* the async ring; just the I/O watchdog. Note that if a
|
||||
* SHRINK were pending, OFF would never be requested.
|
||||
*/
|
||||
if (timer_pending(&ehci->watchdog)
|
||||
&& ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
|
||||
& ehci->actions))
|
||||
return;
|
||||
|
||||
if (!test_and_set_bit(action, &ehci->actions)) {
|
||||
unsigned long t;
|
||||
|
||||
switch (action) {
|
||||
case TIMER_IO_WATCHDOG:
|
||||
t = EHCI_IO_JIFFIES;
|
||||
break;
|
||||
case TIMER_ASYNC_OFF:
|
||||
t = EHCI_ASYNC_JIFFIES;
|
||||
break;
|
||||
/* case TIMER_ASYNC_SHRINK: */
|
||||
default:
|
||||
/* add a jiffie since we synch against the
|
||||
* 8 KHz uframe counter.
|
||||
*/
|
||||
t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
|
||||
break;
|
||||
}
|
||||
mod_timer(&ehci->watchdog, t + jiffies);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* handshake - spin reading hc until handshake completes or fails
|
||||
* @ptr: address of hc register to be read
|
||||
|
|
|
@ -333,12 +333,40 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
token = hc32_to_cpu(ehci, qtd->hw_token);
|
||||
|
||||
/* always clean up qtds the hc de-activated */
|
||||
retry_xacterr:
|
||||
if ((token & QTD_STS_ACTIVE) == 0) {
|
||||
|
||||
/* on STALL, error, and short reads this urb must
|
||||
* complete and all its qtds must be recycled.
|
||||
*/
|
||||
if ((token & QTD_STS_HALT) != 0) {
|
||||
|
||||
/* retry transaction errors until we
|
||||
* reach the software xacterr limit
|
||||
*/
|
||||
if ((token & QTD_STS_XACT) &&
|
||||
QTD_CERR(token) == 0 &&
|
||||
--qh->xacterrs > 0 &&
|
||||
!urb->unlinked) {
|
||||
ehci_dbg(ehci,
|
||||
"detected XactErr len %zu/%zu retry %d\n",
|
||||
qtd->length - QTD_LENGTH(token), qtd->length,
|
||||
QH_XACTERR_MAX - qh->xacterrs);
|
||||
|
||||
/* reset the token in the qtd and the
|
||||
* qh overlay (which still contains
|
||||
* the qtd) so that we pick up from
|
||||
* where we left off
|
||||
*/
|
||||
token &= ~QTD_STS_HALT;
|
||||
token |= QTD_STS_ACTIVE |
|
||||
(EHCI_TUNE_CERR << 10);
|
||||
qtd->hw_token = cpu_to_hc32(ehci,
|
||||
token);
|
||||
wmb();
|
||||
qh->hw_token = cpu_to_hc32(ehci, token);
|
||||
goto retry_xacterr;
|
||||
}
|
||||
stopped = 1;
|
||||
|
||||
/* magic dummy for some short reads; qh won't advance.
|
||||
|
@ -421,6 +449,9 @@ halt:
|
|||
/* remove qtd; it's recycled after possible urb completion */
|
||||
list_del (&qtd->qtd_list);
|
||||
last = qtd;
|
||||
|
||||
/* reinit the xacterr counter for the next qtd */
|
||||
qh->xacterrs = QH_XACTERR_MAX;
|
||||
}
|
||||
|
||||
/* last urb's completion might still need calling */
|
||||
|
@ -862,6 +893,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
head->qh_next.qh = qh;
|
||||
head->hw_next = dma;
|
||||
|
||||
qh->xacterrs = QH_XACTERR_MAX;
|
||||
qh->qh_state = QH_STATE_LINKED;
|
||||
/* qtd completions reported later by interrupt */
|
||||
}
|
||||
|
|
|
@ -563,7 +563,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
// and this qh is active in the current uframe
|
||||
// (and overlay token SplitXstate is false?)
|
||||
// THEN
|
||||
// qh->hw_info1 |= __constant_cpu_to_hc32(1 << 7 /* "ignore" */);
|
||||
// qh->hw_info1 |= cpu_to_hc32(1 << 7 /* "ignore" */);
|
||||
|
||||
/* high bandwidth, or otherwise part of every microframe */
|
||||
if ((period = qh->period) == 0)
|
||||
|
|
|
@ -190,40 +190,6 @@ timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
|
|||
clear_bit (action, &ehci->actions);
|
||||
}
|
||||
|
||||
static inline void
|
||||
timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||
{
|
||||
/* Don't override timeouts which shrink or (later) disable
|
||||
* the async ring; just the I/O watchdog. Note that if a
|
||||
* SHRINK were pending, OFF would never be requested.
|
||||
*/
|
||||
if (timer_pending(&ehci->watchdog)
|
||||
&& ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
|
||||
& ehci->actions))
|
||||
return;
|
||||
|
||||
if (!test_and_set_bit (action, &ehci->actions)) {
|
||||
unsigned long t;
|
||||
|
||||
switch (action) {
|
||||
case TIMER_IO_WATCHDOG:
|
||||
t = EHCI_IO_JIFFIES;
|
||||
break;
|
||||
case TIMER_ASYNC_OFF:
|
||||
t = EHCI_ASYNC_JIFFIES;
|
||||
break;
|
||||
// case TIMER_ASYNC_SHRINK:
|
||||
default:
|
||||
/* add a jiffie since we synch against the
|
||||
* 8 KHz uframe counter.
|
||||
*/
|
||||
t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
|
||||
break;
|
||||
}
|
||||
mod_timer(&ehci->watchdog, t + jiffies);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_cached_itd_list(struct ehci_hcd *ehci);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -287,7 +253,7 @@ struct ehci_qtd {
|
|||
|
||||
/*
|
||||
* Now the following defines are not converted using the
|
||||
* __constant_cpu_to_le32() macro anymore, since we have to support
|
||||
* cpu_to_le32() macro anymore, since we have to support
|
||||
* "dynamic" switching between be and le support, so that the driver
|
||||
* can be used on one system with SoC EHCI controller using big-endian
|
||||
* descriptors as well as a normal little-endian PCI EHCI controller.
|
||||
|
@ -376,6 +342,9 @@ struct ehci_qh {
|
|||
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
|
||||
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
|
||||
|
||||
u8 xacterrs; /* XactErr retry counter */
|
||||
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
|
||||
|
||||
/* periodic schedule info */
|
||||
u8 usecs; /* intr bandwidth */
|
||||
u8 gap_uf; /* uframes split/csplit gap */
|
||||
|
|
|
@ -464,8 +464,7 @@ static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
|
|||
port_idx << 8 | iface_no,
|
||||
keyd, keyd_len, 1000 /* FIXME: arbitrary */);
|
||||
|
||||
memset(keyd, 0, sizeof(*keyd)); /* clear keys etc. */
|
||||
kfree(keyd);
|
||||
kzfree(keyd); /* clear keys etc. */
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -772,7 +772,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
|
|||
break;
|
||||
case PIPE_INTERRUPT:
|
||||
urb->interval = ep->period;
|
||||
ep->length = min((int)ep->maxpacket,
|
||||
ep->length = min_t(u32, ep->maxpacket,
|
||||
urb->transfer_buffer_length);
|
||||
|
||||
/* urb submitted for already existing endpoint */
|
||||
|
|
|
@ -563,7 +563,7 @@ static void urb_dbg(struct urb *urb, char *msg)
|
|||
*/
|
||||
static inline void dump_ptd(struct ptd *ptd)
|
||||
{
|
||||
printk("td: %x %d%c%d %d,%d,%d %x %x%x%x\n",
|
||||
printk(KERN_WARNING "td: %x %d%c%d %d,%d,%d %x %x%x%x\n",
|
||||
PTD_GET_CC(ptd), PTD_GET_FA(ptd),
|
||||
PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
|
||||
PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
|
||||
|
@ -576,7 +576,7 @@ static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf)
|
|||
int k;
|
||||
|
||||
if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) {
|
||||
printk("-> ");
|
||||
printk(KERN_WARNING "-> ");
|
||||
for (k = 0; k < PTD_GET_LEN(ptd); ++k)
|
||||
printk("%02x ", ((u8 *) buf)[k]);
|
||||
printk("\n");
|
||||
|
@ -588,13 +588,13 @@ static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf)
|
|||
int k;
|
||||
|
||||
if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) {
|
||||
printk("<- ");
|
||||
printk(KERN_WARNING "<- ");
|
||||
for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
|
||||
printk("%02x ", ((u8 *) buf)[k]);
|
||||
printk("\n");
|
||||
}
|
||||
if (PTD_GET_LAST(ptd))
|
||||
printk("-\n");
|
||||
printk(KERN_WARNING "-\n");
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -644,7 +644,7 @@ static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
|
|||
|
||||
if (urb->dev->speed != USB_SPEED_HIGH) {
|
||||
/* split */
|
||||
ptd->dw5 = __constant_cpu_to_le32(0x1c);
|
||||
ptd->dw5 = cpu_to_le32(0x1c);
|
||||
|
||||
if (qh->period >= 32)
|
||||
period = qh->period / 2;
|
||||
|
@ -819,6 +819,13 @@ static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
|||
u32 atl_regs, payload;
|
||||
u32 buffstatus;
|
||||
|
||||
/*
|
||||
* When this function is called from the interrupt handler to enqueue
|
||||
* a follow-up packet, the SKIP register gets written and read back
|
||||
* almost immediately. With ISP1761, this register requires a delay of
|
||||
* 195ns between a write and subsequent read (see section 15.1.1.3).
|
||||
*/
|
||||
ndelay(195);
|
||||
skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
|
||||
|
||||
BUG_ON(!skip_map);
|
||||
|
@ -853,6 +860,13 @@ static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
|||
u32 int_regs, payload;
|
||||
u32 buffstatus;
|
||||
|
||||
/*
|
||||
* When this function is called from the interrupt handler to enqueue
|
||||
* a follow-up packet, the SKIP register gets written and read back
|
||||
* almost immediately. With ISP1761, this register requires a delay of
|
||||
* 195ns between a write and subsequent read (see section 15.1.1.3).
|
||||
*/
|
||||
ndelay(195);
|
||||
skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
|
||||
|
||||
BUG_ON(!skip_map);
|
||||
|
@ -1054,7 +1068,7 @@ static void do_atl_int(struct usb_hcd *usb_hcd)
|
|||
priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
|
||||
atl_regs, sizeof(ptd));
|
||||
|
||||
ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID);
|
||||
ptd.dw0 |= cpu_to_le32(PTD_VALID);
|
||||
priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
|
||||
atl_regs, sizeof(ptd));
|
||||
|
||||
|
@ -2235,9 +2249,10 @@ void deinit_kmem_cache(void)
|
|||
kmem_cache_destroy(qh_cachep);
|
||||
}
|
||||
|
||||
struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
|
||||
u64 irqflags, struct device *dev, const char *busname,
|
||||
unsigned int devflags)
|
||||
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
int irq, unsigned long irqflags,
|
||||
struct device *dev, const char *busname,
|
||||
unsigned int devflags)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct isp1760_hcd *priv;
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
#define _ISP1760_HCD_H_
|
||||
|
||||
/* exports for if */
|
||||
struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
|
||||
u64 irqflags, struct device *dev, const char *busname,
|
||||
unsigned int devflags);
|
||||
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
int irq, unsigned long irqflags,
|
||||
struct device *dev, const char *busname,
|
||||
unsigned int devflags);
|
||||
int init_kmem_once(void);
|
||||
void deinit_kmem_cache(void);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "../core/hcd.h"
|
||||
#include "isp1760-hcd.h"
|
||||
|
@ -300,39 +301,101 @@ static struct pci_driver isp1761_pci_driver = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static int __devinit isp1760_plat_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *mem_res;
|
||||
struct resource *irq_res;
|
||||
resource_size_t mem_size;
|
||||
unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem_res) {
|
||||
pr_warning("isp1760: Memory resource not available\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
mem_size = resource_size(mem_res);
|
||||
if (!request_mem_region(mem_res->start, mem_size, "isp1760")) {
|
||||
pr_warning("isp1760: Cannot reserve the memory resource\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq_res) {
|
||||
pr_warning("isp1760: IRQ resource not available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
|
||||
|
||||
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
|
||||
irqflags, &pdev->dev, dev_name(&pdev->dev), 0);
|
||||
if (IS_ERR(hcd)) {
|
||||
pr_warning("isp1760: Failed to register the HCD device\n");
|
||||
ret = -ENODEV;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pr_info("ISP1760 USB device initialised\n");
|
||||
return ret;
|
||||
|
||||
cleanup:
|
||||
release_mem_region(mem_res->start, mem_size);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit isp1760_plat_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *mem_res;
|
||||
resource_size_t mem_size;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mem_size = resource_size(mem_res);
|
||||
release_mem_region(mem_res->start, mem_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver isp1760_plat_driver = {
|
||||
.probe = isp1760_plat_probe,
|
||||
.remove = isp1760_plat_remove,
|
||||
.driver = {
|
||||
.name = "isp1760",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init isp1760_init(void)
|
||||
{
|
||||
int ret;
|
||||
int ret, any_ret = -ENODEV;
|
||||
|
||||
init_kmem_once();
|
||||
|
||||
ret = platform_driver_register(&isp1760_plat_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#ifdef CONFIG_PPC_OF
|
||||
ret = of_register_platform_driver(&isp1760_of_driver);
|
||||
if (ret) {
|
||||
deinit_kmem_cache();
|
||||
return ret;
|
||||
}
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_PCI
|
||||
ret = pci_register_driver(&isp1761_pci_driver);
|
||||
if (ret)
|
||||
goto unreg_of;
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
unreg_of:
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_OF
|
||||
of_unregister_platform_driver(&isp1760_of_driver);
|
||||
#endif
|
||||
deinit_kmem_cache();
|
||||
return ret;
|
||||
if (any_ret)
|
||||
deinit_kmem_cache();
|
||||
return any_ret;
|
||||
}
|
||||
module_init(isp1760_init);
|
||||
|
||||
static void __exit isp1760_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&isp1760_plat_driver);
|
||||
#ifdef CONFIG_PPC_OF
|
||||
of_unregister_platform_driver(&isp1760_of_driver);
|
||||
#endif
|
||||
|
|
|
@ -997,7 +997,7 @@ MODULE_LICENSE ("GPL");
|
|||
#define SA1111_DRIVER ohci_hcd_sa1111_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_S3C2410
|
||||
#if defined(CONFIG_ARCH_S3C2410) || defined(CONFIG_ARCH_S3C64XX)
|
||||
#include "ohci-s3c2410.c"
|
||||
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
|
||||
#endif
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/usb-control.h>
|
||||
#include <plat/usb-control.h>
|
||||
|
||||
#define valid_port(idx) ((idx) == 1 || (idx) == 2)
|
||||
|
||||
|
@ -372,7 +370,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
|
|||
|
||||
usb_clk = clk_get(&dev->dev, "usb-bus-host");
|
||||
if (IS_ERR(usb_clk)) {
|
||||
dev_err(&dev->dev, "cannot get usb-host clock\n");
|
||||
dev_err(&dev->dev, "cannot get usb-bus-host clock\n");
|
||||
retval = -ENOENT;
|
||||
goto err_clk;
|
||||
}
|
||||
|
|
|
@ -845,14 +845,14 @@ static inline void qh_update(struct oxu_hcd *oxu,
|
|||
is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
|
||||
epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
|
||||
if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
|
||||
qh->hw_token &= ~__constant_cpu_to_le32(QTD_TOGGLE);
|
||||
qh->hw_token &= ~cpu_to_le32(QTD_TOGGLE);
|
||||
usb_settoggle(qh->dev, epnum, is_out, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
|
||||
wmb();
|
||||
qh->hw_token &= __constant_cpu_to_le32(QTD_TOGGLE | QTD_STS_PING);
|
||||
qh->hw_token &= cpu_to_le32(QTD_TOGGLE | QTD_STS_PING);
|
||||
}
|
||||
|
||||
/* If it weren't for a common silicon quirk (writing the dummy into the qh
|
||||
|
@ -937,7 +937,7 @@ __acquires(oxu->lock)
|
|||
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
|
||||
|
||||
/* S-mask in a QH means it's an interrupt urb */
|
||||
if ((qh->hw_info2 & __constant_cpu_to_le32(QH_SMASK)) != 0) {
|
||||
if ((qh->hw_info2 & cpu_to_le32(QH_SMASK)) != 0) {
|
||||
|
||||
/* ... update hc-wide periodic stats (for usbfs) */
|
||||
oxu_to_hcd(oxu)->self.bandwidth_int_reqs--;
|
||||
|
@ -981,7 +981,7 @@ static void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh);
|
|||
static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
|
||||
static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
|
||||
|
||||
#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
|
||||
#define HALT_BIT cpu_to_le32(QTD_STS_HALT)
|
||||
|
||||
/* Process and free completed qtds for a qh, returning URBs to drivers.
|
||||
* Chases up to qh->hw_current. Returns number of completions called,
|
||||
|
@ -1160,7 +1160,7 @@ halt:
|
|||
/* should be rare for periodic transfers,
|
||||
* except maybe high bandwidth ...
|
||||
*/
|
||||
if ((__constant_cpu_to_le32(QH_SMASK)
|
||||
if ((cpu_to_le32(QH_SMASK)
|
||||
& qh->hw_info2) != 0) {
|
||||
intr_deschedule(oxu, qh);
|
||||
(void) qh_schedule(oxu, qh);
|
||||
|
@ -1350,7 +1350,7 @@ static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu,
|
|||
}
|
||||
|
||||
/* by default, enable interrupt on urb completion */
|
||||
qtd->hw_token |= __constant_cpu_to_le32(QTD_IOC);
|
||||
qtd->hw_token |= cpu_to_le32(QTD_IOC);
|
||||
return head;
|
||||
|
||||
cleanup:
|
||||
|
@ -1539,7 +1539,7 @@ static void qh_link_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
|
|||
/* qtd completions reported later by interrupt */
|
||||
}
|
||||
|
||||
#define QH_ADDR_MASK __constant_cpu_to_le32(0x7f)
|
||||
#define QH_ADDR_MASK cpu_to_le32(0x7f)
|
||||
|
||||
/*
|
||||
* For control/bulk/interrupt, return QH with these TDs appended.
|
||||
|
@ -2012,7 +2012,7 @@ static void qh_unlink_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh)
|
|||
* and this qh is active in the current uframe
|
||||
* (and overlay token SplitXstate is false?)
|
||||
* THEN
|
||||
* qh->hw_info1 |= __constant_cpu_to_le32(1 << 7 "ignore");
|
||||
* qh->hw_info1 |= cpu_to_le32(1 << 7 "ignore");
|
||||
*/
|
||||
|
||||
/* high bandwidth, or otherwise part of every microframe */
|
||||
|
@ -2057,7 +2057,7 @@ static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
|
|||
* active high speed queues may need bigger delays...
|
||||
*/
|
||||
if (list_empty(&qh->qtd_list)
|
||||
|| (__constant_cpu_to_le32(QH_CMASK) & qh->hw_info2) != 0)
|
||||
|| (cpu_to_le32(QH_CMASK) & qh->hw_info2) != 0)
|
||||
wait = 2;
|
||||
else
|
||||
wait = 55; /* worst case: 3 * 1024 */
|
||||
|
@ -2183,10 +2183,10 @@ static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
|
|||
qh->start = frame;
|
||||
|
||||
/* reset S-frame and (maybe) C-frame masks */
|
||||
qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK));
|
||||
qh->hw_info2 &= cpu_to_le32(~(QH_CMASK | QH_SMASK));
|
||||
qh->hw_info2 |= qh->period
|
||||
? cpu_to_le32(1 << uframe)
|
||||
: __constant_cpu_to_le32(QH_SMASK);
|
||||
: cpu_to_le32(QH_SMASK);
|
||||
qh->hw_info2 |= c_mask;
|
||||
} else
|
||||
oxu_dbg(oxu, "reused qh %p schedule\n", qh);
|
||||
|
@ -2684,7 +2684,7 @@ static int oxu_reset(struct usb_hcd *hcd)
|
|||
oxu->urb_len = 0;
|
||||
|
||||
/* FIMXE */
|
||||
hcd->self.controller->dma_mask = 0UL;
|
||||
hcd->self.controller->dma_mask = NULL;
|
||||
|
||||
if (oxu->is_otg) {
|
||||
oxu->caps = hcd->regs + OXU_OTG_CAP_OFFSET;
|
||||
|
|
|
@ -235,21 +235,21 @@ struct ehci_qtd {
|
|||
} __attribute__ ((aligned(32)));
|
||||
|
||||
/* mask NakCnt+T in qh->hw_alt_next */
|
||||
#define QTD_MASK __constant_cpu_to_le32 (~0x1f)
|
||||
#define QTD_MASK cpu_to_le32 (~0x1f)
|
||||
|
||||
#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
|
||||
|
||||
/* Type tag from {qh, itd, sitd, fstn}->hw_next */
|
||||
#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
|
||||
#define Q_NEXT_TYPE(dma) ((dma) & cpu_to_le32 (3 << 1))
|
||||
|
||||
/* values for that type tag */
|
||||
#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
|
||||
#define Q_TYPE_QH cpu_to_le32 (1 << 1)
|
||||
|
||||
/* next async queue entry, or pointer to interrupt/periodic QH */
|
||||
#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
|
||||
|
||||
/* for periodic/async schedules and qtd lists, mark end of list */
|
||||
#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */
|
||||
#define EHCI_LIST_END cpu_to_le32(1) /* "null pointer" to hw */
|
||||
|
||||
/*
|
||||
* Entries in periodic shadow table are pointers to one of four kinds
|
||||
|
|
|
@ -234,7 +234,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
|
|||
*/
|
||||
hcc_params = readl(base + EHCI_HCC_PARAMS);
|
||||
offset = (hcc_params >> 8) & 0xff;
|
||||
while (offset && count--) {
|
||||
while (offset && --count) {
|
||||
u32 cap;
|
||||
int msec;
|
||||
|
||||
|
|
|
@ -660,9 +660,9 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
|
|||
u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
|
||||
|
||||
memset(array, 0, sizeof(array));
|
||||
switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
|
||||
switch (usb_endpoint_type(ep)) {
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
if (usb_endpoint_dir_in(ep))
|
||||
array[i++] = 4;
|
||||
else {
|
||||
array[i++] = 3;
|
||||
|
@ -670,7 +670,7 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
|
|||
}
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
|
||||
if (usb_endpoint_dir_in(ep)) {
|
||||
array[i++] = 6;
|
||||
array[i++] = 7;
|
||||
array[i++] = 8;
|
||||
|
@ -678,7 +678,7 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
|
|||
array[i++] = 9;
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
if (usb_endpoint_dir_in(ep))
|
||||
array[i++] = 2;
|
||||
else
|
||||
array[i++] = 1;
|
||||
|
@ -928,10 +928,9 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
|
|||
|
||||
info.pipenum = get_empty_pipenum(r8a66597, ep);
|
||||
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
|
||||
info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
|
||||
info.epnum = usb_endpoint_num(ep);
|
||||
info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
|
||||
info.type = get_r8a66597_type(ep->bmAttributes
|
||||
& USB_ENDPOINT_XFERTYPE_MASK);
|
||||
info.type = get_r8a66597_type(usb_endpoint_type(ep));
|
||||
info.bufnum = get_bufnum(info.pipenum);
|
||||
info.buf_bsize = get_buf_bsize(info.pipenum);
|
||||
if (info.type == R8A66597_BULK) {
|
||||
|
@ -941,7 +940,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
|
|||
info.interval = get_interval(urb, ep->bInterval);
|
||||
info.timer_interval = get_timer_interval(urb, ep->bInterval);
|
||||
}
|
||||
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
if (usb_endpoint_dir_in(ep))
|
||||
info.dir_in = 1;
|
||||
else
|
||||
info.dir_in = 0;
|
||||
|
@ -1014,6 +1013,9 @@ static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port,
|
|||
|
||||
r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
|
||||
r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
|
||||
|
||||
if (r8a66597->bus_suspended)
|
||||
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
|
||||
}
|
||||
|
||||
/* this function must be called with interrupt disabled */
|
||||
|
@ -1395,7 +1397,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
|
|||
(int)urb->iso_frame_desc[td->iso_cnt].length);
|
||||
} else {
|
||||
buf = (u16 *)(urb->transfer_buffer + urb->actual_length);
|
||||
size = min((int)bufsize,
|
||||
size = min_t(u32, bufsize,
|
||||
urb->transfer_buffer_length - urb->actual_length);
|
||||
}
|
||||
|
||||
|
@ -1615,6 +1617,11 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
|
|||
r8a66597_bclr(r8a66597, DTCHE, INTENB2);
|
||||
r8a66597_usb_disconnect(r8a66597, 1);
|
||||
}
|
||||
if (mask2 & BCHG) {
|
||||
r8a66597_write(r8a66597, ~BCHG, INTSTS2);
|
||||
r8a66597_bclr(r8a66597, BCHGE, INTENB2);
|
||||
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
|
||||
}
|
||||
}
|
||||
|
||||
if (mask1) {
|
||||
|
@ -1630,6 +1637,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
|
|||
r8a66597_bclr(r8a66597, DTCHE, INTENB1);
|
||||
r8a66597_usb_disconnect(r8a66597, 0);
|
||||
}
|
||||
if (mask1 & BCHG) {
|
||||
r8a66597_write(r8a66597, ~BCHG, INTSTS1);
|
||||
r8a66597_bclr(r8a66597, BCHGE, INTENB1);
|
||||
usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597));
|
||||
}
|
||||
|
||||
if (mask1 & SIGN) {
|
||||
r8a66597_write(r8a66597, ~SIGN, INTSTS1);
|
||||
status = get_urb_error(r8a66597, 0);
|
||||
|
@ -2141,7 +2154,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_ENABLE:
|
||||
rh->port &= (1 << USB_PORT_FEAT_POWER);
|
||||
rh->port &= ~(1 << USB_PORT_FEAT_POWER);
|
||||
break;
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
break;
|
||||
|
@ -2213,6 +2226,68 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int r8a66597_bus_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
|
||||
int port;
|
||||
|
||||
dbg("%s", __func__);
|
||||
|
||||
for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
|
||||
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
|
||||
unsigned long dvstctr_reg = get_dvstctr_reg(port);
|
||||
|
||||
if (!(rh->port & (1 << USB_PORT_FEAT_ENABLE)))
|
||||
continue;
|
||||
|
||||
dbg("suspend port = %d", port);
|
||||
r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */
|
||||
rh->port |= 1 << USB_PORT_FEAT_SUSPEND;
|
||||
|
||||
if (rh->dev->udev->do_remote_wakeup) {
|
||||
msleep(3); /* waiting last SOF */
|
||||
r8a66597_bset(r8a66597, RWUPE, dvstctr_reg);
|
||||
r8a66597_write(r8a66597, ~BCHG, get_intsts_reg(port));
|
||||
r8a66597_bset(r8a66597, BCHGE, get_intenb_reg(port));
|
||||
}
|
||||
}
|
||||
|
||||
r8a66597->bus_suspended = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r8a66597_bus_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
|
||||
int port;
|
||||
|
||||
dbg("%s", __func__);
|
||||
|
||||
for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
|
||||
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
|
||||
unsigned long dvstctr_reg = get_dvstctr_reg(port);
|
||||
|
||||
if (!(rh->port & (1 << USB_PORT_FEAT_SUSPEND)))
|
||||
continue;
|
||||
|
||||
dbg("resume port = %d", port);
|
||||
rh->port &= ~(1 << USB_PORT_FEAT_SUSPEND);
|
||||
rh->port |= 1 << USB_PORT_FEAT_C_SUSPEND;
|
||||
r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
|
||||
msleep(50);
|
||||
r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
#else
|
||||
#define r8a66597_bus_suspend NULL
|
||||
#define r8a66597_bus_resume NULL
|
||||
#endif
|
||||
|
||||
static struct hc_driver r8a66597_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.hcd_priv_size = sizeof(struct r8a66597),
|
||||
|
@ -2243,16 +2318,39 @@ static struct hc_driver r8a66597_hc_driver = {
|
|||
*/
|
||||
.hub_status_data = r8a66597_hub_status_data,
|
||||
.hub_control = r8a66597_hub_control,
|
||||
.bus_suspend = r8a66597_bus_suspend,
|
||||
.bus_resume = r8a66597_bus_resume,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
|
||||
int port;
|
||||
|
||||
dbg("%s", __func__);
|
||||
|
||||
disable_controller(r8a66597);
|
||||
|
||||
for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
|
||||
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
|
||||
|
||||
rh->port = 0x00000000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r8a66597_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
|
||||
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
|
||||
|
||||
dbg("%s", __func__);
|
||||
|
||||
enable_controller(r8a66597);
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* if defined(CONFIG_PM) */
|
||||
|
|
|
@ -504,6 +504,8 @@ struct r8a66597 {
|
|||
|
||||
struct list_head child_device;
|
||||
unsigned long child_connect_map[4];
|
||||
|
||||
unsigned bus_suspended:1;
|
||||
};
|
||||
|
||||
static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
|
||||
|
|
|
@ -230,7 +230,7 @@ static void in_packet(
|
|||
writeb(usb_pipedevice(urb->pipe), data_reg);
|
||||
|
||||
sl811_write(sl811, bank + SL11H_HOSTCTLREG, control);
|
||||
ep->length = min((int)len,
|
||||
ep->length = min_t(u32, len,
|
||||
urb->transfer_buffer_length - urb->actual_length);
|
||||
PACKET("IN%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "",
|
||||
!!usb_gettoggle(urb->dev, ep->epnum, 0), ep, len);
|
||||
|
@ -255,7 +255,7 @@ static void out_packet(
|
|||
buf = urb->transfer_buffer + urb->actual_length;
|
||||
prefetch(buf);
|
||||
|
||||
len = min((int)ep->maxpacket,
|
||||
len = min_t(u32, ep->maxpacket,
|
||||
urb->transfer_buffer_length - urb->actual_length);
|
||||
|
||||
if (!(control & SL11H_HCTLMASK_ISOCH)
|
||||
|
|
|
@ -118,7 +118,9 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
|
|||
}
|
||||
|
||||
out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
|
||||
out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
|
||||
out += sprintf(out, " Actlen=%d%s", urbp->urb->actual_length,
|
||||
(urbp->qh->type == USB_ENDPOINT_XFER_CONTROL ?
|
||||
"-8" : ""));
|
||||
|
||||
if (urbp->urb->unlinked)
|
||||
out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
|
||||
|
|
|
@ -73,11 +73,11 @@
|
|||
#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
|
||||
#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
|
||||
|
||||
#define UHCI_PTR_BITS __constant_cpu_to_le32(0x000F)
|
||||
#define UHCI_PTR_TERM __constant_cpu_to_le32(0x0001)
|
||||
#define UHCI_PTR_QH __constant_cpu_to_le32(0x0002)
|
||||
#define UHCI_PTR_DEPTH __constant_cpu_to_le32(0x0004)
|
||||
#define UHCI_PTR_BREADTH __constant_cpu_to_le32(0x0000)
|
||||
#define UHCI_PTR_BITS cpu_to_le32(0x000F)
|
||||
#define UHCI_PTR_TERM cpu_to_le32(0x0001)
|
||||
#define UHCI_PTR_QH cpu_to_le32(0x0002)
|
||||
#define UHCI_PTR_DEPTH cpu_to_le32(0x0004)
|
||||
#define UHCI_PTR_BREADTH cpu_to_le32(0x0000)
|
||||
|
||||
#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */
|
||||
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
|
||||
|
|
|
@ -402,7 +402,7 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
|
|||
/* Otherwise all the toggles in the URB have to be switched */
|
||||
} else {
|
||||
list_for_each_entry(td, &urbp->td_list, list) {
|
||||
td->token ^= __constant_cpu_to_le32(
|
||||
td->token ^= cpu_to_le32(
|
||||
TD_TOKEN_TOGGLE);
|
||||
toggle ^= 1;
|
||||
}
|
||||
|
@ -883,7 +883,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
|
||||
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
|
||||
wmb();
|
||||
qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
|
||||
qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE);
|
||||
qh->dummy_td = td;
|
||||
|
||||
/* Low-speed transfers get a different queue, and won't hog the bus.
|
||||
|
@ -899,8 +899,6 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
}
|
||||
if (qh->state != QH_STATE_ACTIVE)
|
||||
qh->skel = skel;
|
||||
|
||||
urb->actual_length = -8; /* Account for the SETUP packet */
|
||||
return 0;
|
||||
|
||||
nomem:
|
||||
|
@ -1003,7 +1001,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
* fast side but not enough to justify delaying an interrupt
|
||||
* more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
|
||||
* flag setting. */
|
||||
td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
|
||||
td->status |= cpu_to_le32(TD_CTRL_IOC);
|
||||
|
||||
/*
|
||||
* Build the new dummy TD and activate the old one
|
||||
|
@ -1015,7 +1013,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
|
||||
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
|
||||
wmb();
|
||||
qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
|
||||
qh->dummy_td->status |= cpu_to_le32(TD_CTRL_ACTIVE);
|
||||
qh->dummy_td = td;
|
||||
|
||||
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
|
||||
|
@ -1317,7 +1315,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
|
|||
}
|
||||
|
||||
/* Set the interrupt-on-completion flag on the last packet. */
|
||||
td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
|
||||
td->status |= cpu_to_le32(TD_CTRL_IOC);
|
||||
|
||||
/* Add the TDs to the frame list */
|
||||
frame = urb->start_frame;
|
||||
|
@ -1494,11 +1492,10 @@ __acquires(uhci->lock)
|
|||
|
||||
if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
|
||||
|
||||
/* urb->actual_length < 0 means the setup transaction didn't
|
||||
* complete successfully. Either it failed or the URB was
|
||||
* unlinked first. Regardless, don't confuse people with a
|
||||
* negative length. */
|
||||
urb->actual_length = max(urb->actual_length, 0);
|
||||
/* Subtract off the length of the SETUP packet from
|
||||
* urb->actual_length.
|
||||
*/
|
||||
urb->actual_length -= min_t(u32, 8, urb->actual_length);
|
||||
}
|
||||
|
||||
/* When giving back the first URB in an Isochronous queue,
|
||||
|
|
|
@ -188,7 +188,7 @@ static struct usb_endpoint_descriptor mdc800_ed [4] =
|
|||
.bDescriptorType = 0,
|
||||
.bEndpointAddress = 0x01,
|
||||
.bmAttributes = 0x02,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(8),
|
||||
.wMaxPacketSize = cpu_to_le16(8),
|
||||
.bInterval = 0,
|
||||
.bRefresh = 0,
|
||||
.bSynchAddress = 0,
|
||||
|
@ -198,7 +198,7 @@ static struct usb_endpoint_descriptor mdc800_ed [4] =
|
|||
.bDescriptorType = 0,
|
||||
.bEndpointAddress = 0x82,
|
||||
.bmAttributes = 0x03,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(8),
|
||||
.wMaxPacketSize = cpu_to_le16(8),
|
||||
.bInterval = 0,
|
||||
.bRefresh = 0,
|
||||
.bSynchAddress = 0,
|
||||
|
@ -208,7 +208,7 @@ static struct usb_endpoint_descriptor mdc800_ed [4] =
|
|||
.bDescriptorType = 0,
|
||||
.bEndpointAddress = 0x03,
|
||||
.bmAttributes = 0x02,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(64),
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
.bInterval = 0,
|
||||
.bRefresh = 0,
|
||||
.bSynchAddress = 0,
|
||||
|
@ -218,7 +218,7 @@ static struct usb_endpoint_descriptor mdc800_ed [4] =
|
|||
.bDescriptorType = 0,
|
||||
.bEndpointAddress = 0x84,
|
||||
.bmAttributes = 0x02,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(64),
|
||||
.wMaxPacketSize = cpu_to_le16(64),
|
||||
.bInterval = 0,
|
||||
.bRefresh = 0,
|
||||
.bSynchAddress = 0,
|
||||
|
|
|
@ -135,45 +135,6 @@ config USB_CYTHERM
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called cytherm.
|
||||
|
||||
config USB_PHIDGET
|
||||
tristate "USB Phidgets drivers"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here to enable the various drivers for devices from
|
||||
Phidgets inc.
|
||||
|
||||
config USB_PHIDGETKIT
|
||||
tristate "USB PhidgetInterfaceKit support"
|
||||
depends on USB_PHIDGET
|
||||
help
|
||||
Say Y here if you want to connect a PhidgetInterfaceKit USB device
|
||||
from Phidgets Inc.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called phidgetkit.
|
||||
|
||||
config USB_PHIDGETMOTORCONTROL
|
||||
tristate "USB PhidgetMotorControl support"
|
||||
depends on USB_PHIDGET
|
||||
help
|
||||
Say Y here if you want to connect a PhidgetMotorControl USB device
|
||||
from Phidgets Inc.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called phidgetmotorcontrol.
|
||||
|
||||
config USB_PHIDGETSERVO
|
||||
tristate "USB PhidgetServo support"
|
||||
depends on USB_PHIDGET
|
||||
help
|
||||
Say Y here if you want to connect an 1 or 4 Motor PhidgetServo
|
||||
servo controller version 2.0 or 3.0.
|
||||
|
||||
Phidgets Inc. has a web page at <http://www.phidgets.com/>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called phidgetservo.
|
||||
|
||||
config USB_IDMOUSE
|
||||
tristate "Siemens ID USB Mouse Fingerprint sensor support"
|
||||
depends on USB
|
||||
|
|
|
@ -18,10 +18,6 @@ obj-$(CONFIG_USB_LCD) += usblcd.o
|
|||
obj-$(CONFIG_USB_LD) += ldusb.o
|
||||
obj-$(CONFIG_USB_LED) += usbled.o
|
||||
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
|
||||
obj-$(CONFIG_USB_PHIDGET) += phidget.o
|
||||
obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o
|
||||
obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o
|
||||
obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
|
||||
obj-$(CONFIG_USB_RIO500) += rio500.o
|
||||
obj-$(CONFIG_USB_TEST) += usbtest.o
|
||||
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
|
||||
|
|
|
@ -1568,7 +1568,7 @@ static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
|
|||
struct u132_target *target = &ftdi->target[ed];
|
||||
struct u132_command *command = &ftdi->command[
|
||||
COMMAND_MASK & ftdi->command_next];
|
||||
int remaining_length = urb->transfer_buffer_length -
|
||||
u32 remaining_length = urb->transfer_buffer_length -
|
||||
urb->actual_length;
|
||||
command->header = 0x82 | (ed << 5);
|
||||
if (remaining_length == 0) {
|
||||
|
@ -1702,7 +1702,7 @@ static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
|
|||
| (address << 0);
|
||||
command->width = usb_maxpacket(urb->dev, urb->pipe,
|
||||
usb_pipeout(urb->pipe));
|
||||
command->follows = min(1024,
|
||||
command->follows = min_t(u32, 1024,
|
||||
urb->transfer_buffer_length -
|
||||
urb->actual_length);
|
||||
command->value = 0;
|
||||
|
@ -1766,7 +1766,7 @@ static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
|
|||
mutex_lock(&ftdi->u132_lock);
|
||||
command_size = ftdi->command_next - ftdi->command_head;
|
||||
if (command_size < COMMAND_SIZE) {
|
||||
int remaining_length = urb->transfer_buffer_length -
|
||||
u32 remaining_length = urb->transfer_buffer_length -
|
||||
urb->actual_length;
|
||||
struct u132_target *target = &ftdi->target[ed];
|
||||
struct u132_command *command = &ftdi->command[
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* USB Phidgets class
|
||||
*
|
||||
* Copyright (C) 2006 Sean Young <sean@mess.org>
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct class *phidget_class;
|
||||
|
||||
static int __init init_phidget(void)
|
||||
{
|
||||
phidget_class = class_create(THIS_MODULE, "phidget");
|
||||
|
||||
if (IS_ERR(phidget_class))
|
||||
return PTR_ERR(phidget_class);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cleanup_phidget(void)
|
||||
{
|
||||
class_destroy(phidget_class);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(phidget_class);
|
||||
|
||||
module_init(init_phidget);
|
||||
module_exit(cleanup_phidget);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Sean Young <sean@mess.org>");
|
||||
MODULE_DESCRIPTION("Container module for phidget class");
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* USB Phidgets class
|
||||
*
|
||||
* Copyright (C) 2006 Sean Young <sean@mess.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern struct class *phidget_class;
|
|
@ -1,740 +0,0 @@
|
|||
/*
|
||||
* USB PhidgetInterfaceKit driver 1.0
|
||||
*
|
||||
* Copyright (C) 2004, 2006 Sean Young <sean@mess.org>
|
||||
* Copyright (C) 2005 Daniel Saakes <daniel@saakes.net>
|
||||
* Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.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 is a driver for the USB PhidgetInterfaceKit.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "phidget.h"
|
||||
|
||||
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
|
||||
#define DRIVER_DESC "USB PhidgetInterfaceKit Driver"
|
||||
|
||||
#define USB_VENDOR_ID_GLAB 0x06c2
|
||||
#define USB_DEVICE_ID_INTERFACEKIT004 0x0040
|
||||
#define USB_DEVICE_ID_INTERFACEKIT01616 0x0044
|
||||
#define USB_DEVICE_ID_INTERFACEKIT888 0x0045
|
||||
#define USB_DEVICE_ID_INTERFACEKIT047 0x0051
|
||||
#define USB_DEVICE_ID_INTERFACEKIT088 0x0053
|
||||
|
||||
#define USB_VENDOR_ID_WISEGROUP 0x0925
|
||||
#define USB_DEVICE_ID_INTERFACEKIT884 0x8201
|
||||
|
||||
#define MAX_INTERFACES 16
|
||||
|
||||
#define URB_INT_SIZE 8
|
||||
|
||||
struct driver_interfacekit {
|
||||
int sensors;
|
||||
int inputs;
|
||||
int outputs;
|
||||
int has_lcd;
|
||||
int amnesiac;
|
||||
};
|
||||
|
||||
#define ifkit(_sensors, _inputs, _outputs, _lcd, _amnesiac) \
|
||||
{ \
|
||||
.sensors = _sensors, \
|
||||
.inputs = _inputs, \
|
||||
.outputs = _outputs, \
|
||||
.has_lcd = _lcd, \
|
||||
.amnesiac = _amnesiac \
|
||||
};
|
||||
|
||||
static const struct driver_interfacekit ph_004 = ifkit(0, 0, 4, 0, 0);
|
||||
static const struct driver_interfacekit ph_888n = ifkit(8, 8, 8, 0, 1);
|
||||
static const struct driver_interfacekit ph_888o = ifkit(8, 8, 8, 0, 0);
|
||||
static const struct driver_interfacekit ph_047 = ifkit(0, 4, 7, 1, 0);
|
||||
static const struct driver_interfacekit ph_884 = ifkit(8, 8, 4, 0, 0);
|
||||
static const struct driver_interfacekit ph_088 = ifkit(0, 8, 8, 1, 0);
|
||||
static const struct driver_interfacekit ph_01616 = ifkit(0, 16, 16, 0, 0);
|
||||
|
||||
static unsigned long device_no;
|
||||
|
||||
struct interfacekit {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct driver_interfacekit *ifkit;
|
||||
struct device *dev;
|
||||
unsigned long outputs;
|
||||
int dev_no;
|
||||
u8 inputs[MAX_INTERFACES];
|
||||
u16 sensors[MAX_INTERFACES];
|
||||
u8 lcd_files_on;
|
||||
|
||||
struct urb *irq;
|
||||
unsigned char *data;
|
||||
dma_addr_t data_dma;
|
||||
|
||||
struct delayed_work do_notify;
|
||||
struct delayed_work do_resubmit;
|
||||
unsigned long input_events;
|
||||
unsigned long sensor_events;
|
||||
};
|
||||
|
||||
static struct usb_device_id id_table[] = {
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004),
|
||||
.driver_info = (kernel_ulong_t)&ph_004},
|
||||
{USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0, 0x814),
|
||||
.driver_info = (kernel_ulong_t)&ph_888o},
|
||||
{USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0x0815, 0xffff),
|
||||
.driver_info = (kernel_ulong_t)&ph_888n},
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047),
|
||||
.driver_info = (kernel_ulong_t)&ph_047},
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088),
|
||||
.driver_info = (kernel_ulong_t)&ph_088},
|
||||
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT01616),
|
||||
.driver_info = (kernel_ulong_t)&ph_01616},
|
||||
{USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_INTERFACEKIT884),
|
||||
.driver_info = (kernel_ulong_t)&ph_884},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
static int set_outputs(struct interfacekit *kit)
|
||||
{
|
||||
u8 *buffer;
|
||||
int retval;
|
||||
|
||||
buffer = kzalloc(4, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&kit->udev->dev, "%s - out of memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
buffer[0] = (u8)kit->outputs;
|
||||
buffer[1] = (u8)(kit->outputs >> 8);
|
||||
|
||||
dev_dbg(&kit->udev->dev, "sending data: 0x%04x\n", (u16)kit->outputs);
|
||||
|
||||
retval = usb_control_msg(kit->udev,
|
||||
usb_sndctrlpipe(kit->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2000);
|
||||
|
||||
if (retval != 4)
|
||||
dev_err(&kit->udev->dev, "usb_control_msg returned %d\n",
|
||||
retval);
|
||||
kfree(buffer);
|
||||
|
||||
if (kit->ifkit->amnesiac)
|
||||
schedule_delayed_work(&kit->do_resubmit, HZ / 2);
|
||||
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static int change_string(struct interfacekit *kit, const char *display, unsigned char row)
|
||||
{
|
||||
unsigned char *buffer;
|
||||
unsigned char *form_buffer;
|
||||
int retval = -ENOMEM;
|
||||
int i,j, len, buf_ptr;
|
||||
|
||||
buffer = kmalloc(8, GFP_KERNEL);
|
||||
form_buffer = kmalloc(30, GFP_KERNEL);
|
||||
if ((!buffer) || (!form_buffer)) {
|
||||
dev_err(&kit->udev->dev, "%s - out of memory\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
len = strlen(display);
|
||||
if (len > 20)
|
||||
len = 20;
|
||||
|
||||
dev_dbg(&kit->udev->dev, "Setting LCD line %d to %s\n", row, display);
|
||||
|
||||
form_buffer[0] = row * 0x40 + 0x80;
|
||||
form_buffer[1] = 0x02;
|
||||
buf_ptr = 2;
|
||||
for (i = 0; i<len; i++)
|
||||
form_buffer[buf_ptr++] = display[i];
|
||||
|
||||
for (i = 0; i < (20 - len); i++)
|
||||
form_buffer[buf_ptr++] = 0x20;
|
||||
form_buffer[buf_ptr++] = 0x01;
|
||||
form_buffer[buf_ptr++] = row * 0x40 + 0x80 + strlen(display);
|
||||
|
||||
for (i = 0; i < buf_ptr; i += 7) {
|
||||
if ((buf_ptr - i) > 7)
|
||||
len = 7;
|
||||
else
|
||||
len = (buf_ptr - i);
|
||||
for (j = 0; j < len; j++)
|
||||
buffer[j] = form_buffer[i + j];
|
||||
buffer[7] = len;
|
||||
|
||||
retval = usb_control_msg(kit->udev,
|
||||
usb_sndctrlpipe(kit->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
exit:
|
||||
kfree(buffer);
|
||||
kfree(form_buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define set_lcd_line(number) \
|
||||
static ssize_t lcd_line_##number(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct interfacekit *kit = dev_get_drvdata(dev); \
|
||||
change_string(kit, buf, number - 1); \
|
||||
return count; \
|
||||
}
|
||||
|
||||
#define lcd_line_attr(number) \
|
||||
__ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number)
|
||||
|
||||
set_lcd_line(1);
|
||||
set_lcd_line(2);
|
||||
|
||||
static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct interfacekit *kit = dev_get_drvdata(dev);
|
||||
int enabled;
|
||||
unsigned char *buffer;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
buffer = kzalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&kit->udev->dev, "%s - out of memory\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%d", &enabled) < 1) {
|
||||
retval = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
if (enabled)
|
||||
buffer[0] = 0x01;
|
||||
buffer[7] = 0x11;
|
||||
|
||||
dev_dbg(&kit->udev->dev, "Setting backlight to %s\n", enabled ? "on" : "off");
|
||||
|
||||
retval = usb_control_msg(kit->udev,
|
||||
usb_sndctrlpipe(kit->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
retval = count;
|
||||
exit:
|
||||
kfree(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct device_attribute dev_lcd_line_attrs[] = {
|
||||
lcd_line_attr(1),
|
||||
lcd_line_attr(2),
|
||||
__ATTR(backlight, S_IWUGO, NULL, set_backlight)
|
||||
};
|
||||
|
||||
static void remove_lcd_files(struct interfacekit *kit)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (kit->lcd_files_on) {
|
||||
dev_dbg(&kit->udev->dev, "Removing lcd files\n");
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++)
|
||||
device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct interfacekit *kit = dev_get_drvdata(dev);
|
||||
int enable;
|
||||
int i, rc;
|
||||
|
||||
if (kit->ifkit->has_lcd == 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (sscanf(buf, "%d", &enable) < 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable) {
|
||||
if (!kit->lcd_files_on) {
|
||||
dev_dbg(&kit->udev->dev, "Adding lcd files\n");
|
||||
for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++) {
|
||||
rc = device_create_file(kit->dev,
|
||||
&dev_lcd_line_attrs[i]);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
kit->lcd_files_on = 1;
|
||||
}
|
||||
} else {
|
||||
if (kit->lcd_files_on) {
|
||||
remove_lcd_files(kit);
|
||||
kit->lcd_files_on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
out:
|
||||
while (i-- > 0)
|
||||
device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files);
|
||||
|
||||
static void interfacekit_irq(struct urb *urb)
|
||||
{
|
||||
struct interfacekit *kit = urb->context;
|
||||
unsigned char *buffer = kit->data;
|
||||
int i, level, sensor;
|
||||
int retval;
|
||||
int status = urb->status;
|
||||
|
||||
switch (status) {
|
||||
case 0: /* success */
|
||||
break;
|
||||
case -ECONNRESET: /* unlink */
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
/* -EPIPE: should clear the halt */
|
||||
default: /* error */
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
/* digital inputs */
|
||||
if (kit->ifkit->inputs == 16) {
|
||||
for (i=0; i < 8; i++) {
|
||||
level = (buffer[0] >> i) & 1;
|
||||
if (kit->inputs[i] != level) {
|
||||
kit->inputs[i] = level;
|
||||
set_bit(i, &kit->input_events);
|
||||
}
|
||||
level = (buffer[1] >> i) & 1;
|
||||
if (kit->inputs[8 + i] != level) {
|
||||
kit->inputs[8 + i] = level;
|
||||
set_bit(8 + i, &kit->input_events);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (kit->ifkit->inputs == 8) {
|
||||
for (i=0; i < 8; i++) {
|
||||
level = (buffer[1] >> i) & 1;
|
||||
if (kit->inputs[i] != level) {
|
||||
kit->inputs[i] = level;
|
||||
set_bit(i, &kit->input_events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* analog inputs */
|
||||
if (kit->ifkit->sensors) {
|
||||
sensor = (buffer[0] & 1) ? 4 : 0;
|
||||
|
||||
level = buffer[2] + (buffer[3] & 0x0f) * 256;
|
||||
if (level != kit->sensors[sensor]) {
|
||||
kit->sensors[sensor] = level;
|
||||
set_bit(sensor, &kit->sensor_events);
|
||||
}
|
||||
sensor++;
|
||||
level = buffer[4] + (buffer[3] & 0xf0) * 16;
|
||||
if (level != kit->sensors[sensor]) {
|
||||
kit->sensors[sensor] = level;
|
||||
set_bit(sensor, &kit->sensor_events);
|
||||
}
|
||||
sensor++;
|
||||
level = buffer[5] + (buffer[6] & 0x0f) * 256;
|
||||
if (level != kit->sensors[sensor]) {
|
||||
kit->sensors[sensor] = level;
|
||||
set_bit(sensor, &kit->sensor_events);
|
||||
}
|
||||
sensor++;
|
||||
level = buffer[7] + (buffer[6] & 0xf0) * 16;
|
||||
if (level != kit->sensors[sensor]) {
|
||||
kit->sensors[sensor] = level;
|
||||
set_bit(sensor, &kit->sensor_events);
|
||||
}
|
||||
}
|
||||
|
||||
if (kit->input_events || kit->sensor_events)
|
||||
schedule_delayed_work(&kit->do_notify, 0);
|
||||
|
||||
resubmit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
|
||||
kit->udev->bus->bus_name,
|
||||
kit->udev->devpath, retval);
|
||||
}
|
||||
|
||||
static void do_notify(struct work_struct *work)
|
||||
{
|
||||
struct interfacekit *kit =
|
||||
container_of(work, struct interfacekit, do_notify.work);
|
||||
int i;
|
||||
char sysfs_file[8];
|
||||
|
||||
for (i=0; i<kit->ifkit->inputs; i++) {
|
||||
if (test_and_clear_bit(i, &kit->input_events)) {
|
||||
sprintf(sysfs_file, "input%d", i + 1);
|
||||
sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<kit->ifkit->sensors; i++) {
|
||||
if (test_and_clear_bit(i, &kit->sensor_events)) {
|
||||
sprintf(sysfs_file, "sensor%d", i + 1);
|
||||
sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_resubmit(struct work_struct *work)
|
||||
{
|
||||
struct interfacekit *kit =
|
||||
container_of(work, struct interfacekit, do_resubmit.work);
|
||||
set_outputs(kit);
|
||||
}
|
||||
|
||||
#define show_set_output(value) \
|
||||
static ssize_t set_output##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct interfacekit *kit = dev_get_drvdata(dev); \
|
||||
int enable; \
|
||||
int retval; \
|
||||
\
|
||||
if (sscanf(buf, "%d", &enable) < 1) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (enable) \
|
||||
set_bit(value - 1, &kit->outputs); \
|
||||
else \
|
||||
clear_bit(value - 1, &kit->outputs); \
|
||||
\
|
||||
retval = set_outputs(kit); \
|
||||
\
|
||||
return retval ? retval : count; \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_output##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct interfacekit *kit = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", !!test_bit(value - 1, &kit->outputs));\
|
||||
}
|
||||
|
||||
#define output_attr(value) \
|
||||
__ATTR(output##value, S_IWUGO | S_IRUGO, \
|
||||
show_output##value, set_output##value)
|
||||
|
||||
show_set_output(1);
|
||||
show_set_output(2);
|
||||
show_set_output(3);
|
||||
show_set_output(4);
|
||||
show_set_output(5);
|
||||
show_set_output(6);
|
||||
show_set_output(7);
|
||||
show_set_output(8);
|
||||
show_set_output(9);
|
||||
show_set_output(10);
|
||||
show_set_output(11);
|
||||
show_set_output(12);
|
||||
show_set_output(13);
|
||||
show_set_output(14);
|
||||
show_set_output(15);
|
||||
show_set_output(16);
|
||||
|
||||
static struct device_attribute dev_output_attrs[] = {
|
||||
output_attr(1), output_attr(2), output_attr(3), output_attr(4),
|
||||
output_attr(5), output_attr(6), output_attr(7), output_attr(8),
|
||||
output_attr(9), output_attr(10), output_attr(11), output_attr(12),
|
||||
output_attr(13), output_attr(14), output_attr(15), output_attr(16)
|
||||
};
|
||||
|
||||
#define show_input(value) \
|
||||
static ssize_t show_input##value(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct interfacekit *kit = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", (int)kit->inputs[value - 1]); \
|
||||
}
|
||||
|
||||
#define input_attr(value) \
|
||||
__ATTR(input##value, S_IRUGO, show_input##value, NULL)
|
||||
|
||||
show_input(1);
|
||||
show_input(2);
|
||||
show_input(3);
|
||||
show_input(4);
|
||||
show_input(5);
|
||||
show_input(6);
|
||||
show_input(7);
|
||||
show_input(8);
|
||||
show_input(9);
|
||||
show_input(10);
|
||||
show_input(11);
|
||||
show_input(12);
|
||||
show_input(13);
|
||||
show_input(14);
|
||||
show_input(15);
|
||||
show_input(16);
|
||||
|
||||
static struct device_attribute dev_input_attrs[] = {
|
||||
input_attr(1), input_attr(2), input_attr(3), input_attr(4),
|
||||
input_attr(5), input_attr(6), input_attr(7), input_attr(8),
|
||||
input_attr(9), input_attr(10), input_attr(11), input_attr(12),
|
||||
input_attr(13), input_attr(14), input_attr(15), input_attr(16)
|
||||
};
|
||||
|
||||
#define show_sensor(value) \
|
||||
static ssize_t show_sensor##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct interfacekit *kit = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", (int)kit->sensors[value - 1]); \
|
||||
}
|
||||
|
||||
#define sensor_attr(value) \
|
||||
__ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL)
|
||||
|
||||
show_sensor(1);
|
||||
show_sensor(2);
|
||||
show_sensor(3);
|
||||
show_sensor(4);
|
||||
show_sensor(5);
|
||||
show_sensor(6);
|
||||
show_sensor(7);
|
||||
show_sensor(8);
|
||||
|
||||
static struct device_attribute dev_sensor_attrs[] = {
|
||||
sensor_attr(1), sensor_attr(2), sensor_attr(3), sensor_attr(4),
|
||||
sensor_attr(5), sensor_attr(6), sensor_attr(7), sensor_attr(8)
|
||||
};
|
||||
|
||||
static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *interface;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct interfacekit *kit;
|
||||
struct driver_interfacekit *ifkit;
|
||||
int pipe, maxp, rc = -ENOMEM;
|
||||
int bit, value, i;
|
||||
|
||||
ifkit = (struct driver_interfacekit *)id->driver_info;
|
||||
if (!ifkit)
|
||||
return -ENODEV;
|
||||
|
||||
interface = intf->cur_altsetting;
|
||||
if (interface->desc.bNumEndpoints != 1)
|
||||
return -ENODEV;
|
||||
|
||||
endpoint = &interface->endpoint[0].desc;
|
||||
if (!usb_endpoint_dir_in(endpoint))
|
||||
return -ENODEV;
|
||||
/*
|
||||
* bmAttributes
|
||||
*/
|
||||
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
|
||||
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
|
||||
|
||||
kit = kzalloc(sizeof(*kit), GFP_KERNEL);
|
||||
if (!kit)
|
||||
goto out;
|
||||
|
||||
kit->dev_no = -1;
|
||||
kit->ifkit = ifkit;
|
||||
kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, GFP_ATOMIC, &kit->data_dma);
|
||||
if (!kit->data)
|
||||
goto out;
|
||||
|
||||
kit->irq = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!kit->irq)
|
||||
goto out;
|
||||
|
||||
kit->udev = usb_get_dev(dev);
|
||||
kit->intf = intf;
|
||||
INIT_DELAYED_WORK(&kit->do_notify, do_notify);
|
||||
INIT_DELAYED_WORK(&kit->do_resubmit, do_resubmit);
|
||||
usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data,
|
||||
maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
|
||||
interfacekit_irq, kit, endpoint->bInterval);
|
||||
kit->irq->transfer_dma = kit->data_dma;
|
||||
kit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
usb_set_intfdata(intf, kit);
|
||||
|
||||
do {
|
||||
bit = find_first_zero_bit(&device_no, sizeof(device_no));
|
||||
value = test_and_set_bit(bit, &device_no);
|
||||
} while(value);
|
||||
kit->dev_no = bit;
|
||||
|
||||
kit->dev = device_create(phidget_class, &kit->udev->dev, MKDEV(0, 0),
|
||||
kit, "interfacekit%d", kit->dev_no);
|
||||
if (IS_ERR(kit->dev)) {
|
||||
rc = PTR_ERR(kit->dev);
|
||||
kit->dev = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i=0; i<ifkit->outputs; i++ ) {
|
||||
rc = device_create_file(kit->dev, &dev_output_attrs[i]);
|
||||
if (rc)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
for (i=0; i<ifkit->inputs; i++ ) {
|
||||
rc = device_create_file(kit->dev, &dev_input_attrs[i]);
|
||||
if (rc)
|
||||
goto out3;
|
||||
}
|
||||
|
||||
for (i=0; i<ifkit->sensors; i++ ) {
|
||||
rc = device_create_file(kit->dev, &dev_sensor_attrs[i]);
|
||||
if (rc)
|
||||
goto out4;
|
||||
}
|
||||
|
||||
if (ifkit->has_lcd) {
|
||||
rc = device_create_file(kit->dev, &dev_attr_lcd);
|
||||
if (rc)
|
||||
goto out4;
|
||||
|
||||
}
|
||||
|
||||
dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
|
||||
ifkit->sensors, ifkit->inputs, ifkit->outputs);
|
||||
|
||||
return 0;
|
||||
|
||||
out4:
|
||||
while (i-- > 0)
|
||||
device_remove_file(kit->dev, &dev_sensor_attrs[i]);
|
||||
|
||||
i = ifkit->inputs;
|
||||
out3:
|
||||
while (i-- > 0)
|
||||
device_remove_file(kit->dev, &dev_input_attrs[i]);
|
||||
|
||||
i = ifkit->outputs;
|
||||
out2:
|
||||
while (i-- > 0)
|
||||
device_remove_file(kit->dev, &dev_output_attrs[i]);
|
||||
out:
|
||||
if (kit) {
|
||||
usb_free_urb(kit->irq);
|
||||
if (kit->data)
|
||||
usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma);
|
||||
if (kit->dev)
|
||||
device_unregister(kit->dev);
|
||||
if (kit->dev_no >= 0)
|
||||
clear_bit(kit->dev_no, &device_no);
|
||||
|
||||
kfree(kit);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void interfacekit_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct interfacekit *kit;
|
||||
int i;
|
||||
|
||||
kit = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
if (!kit)
|
||||
return;
|
||||
|
||||
usb_kill_urb(kit->irq);
|
||||
usb_free_urb(kit->irq);
|
||||
usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma);
|
||||
|
||||
cancel_delayed_work(&kit->do_notify);
|
||||
cancel_delayed_work(&kit->do_resubmit);
|
||||
|
||||
for (i=0; i<kit->ifkit->outputs; i++)
|
||||
device_remove_file(kit->dev, &dev_output_attrs[i]);
|
||||
|
||||
for (i=0; i<kit->ifkit->inputs; i++)
|
||||
device_remove_file(kit->dev, &dev_input_attrs[i]);
|
||||
|
||||
for (i=0; i<kit->ifkit->sensors; i++)
|
||||
device_remove_file(kit->dev, &dev_sensor_attrs[i]);
|
||||
|
||||
if (kit->ifkit->has_lcd) {
|
||||
device_remove_file(kit->dev, &dev_attr_lcd);
|
||||
remove_lcd_files(kit);
|
||||
}
|
||||
|
||||
device_unregister(kit->dev);
|
||||
|
||||
dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
|
||||
kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
|
||||
|
||||
usb_put_dev(kit->udev);
|
||||
clear_bit(kit->dev_no, &device_no);
|
||||
|
||||
kfree(kit);
|
||||
}
|
||||
|
||||
static struct usb_driver interfacekit_driver = {
|
||||
.name = "phidgetkit",
|
||||
.probe = interfacekit_probe,
|
||||
.disconnect = interfacekit_disconnect,
|
||||
.id_table = id_table
|
||||
};
|
||||
|
||||
static int __init interfacekit_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
retval = usb_register(&interfacekit_driver);
|
||||
if (retval)
|
||||
err("usb_register failed. Error number %d", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit interfacekit_exit(void)
|
||||
{
|
||||
usb_deregister(&interfacekit_driver);
|
||||
}
|
||||
|
||||
module_init(interfacekit_init);
|
||||
module_exit(interfacekit_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,465 +0,0 @@
|
|||
/*
|
||||
* USB Phidget MotorControl driver
|
||||
*
|
||||
* Copyright (C) 2006 Sean Young <sean@mess.org>
|
||||
*
|
||||
* 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/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "phidget.h"
|
||||
|
||||
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
|
||||
#define DRIVER_DESC "USB PhidgetMotorControl Driver"
|
||||
|
||||
#define USB_VENDOR_ID_GLAB 0x06c2
|
||||
#define USB_DEVICE_ID_MOTORCONTROL 0x0058
|
||||
|
||||
#define URB_INT_SIZE 8
|
||||
|
||||
static unsigned long device_no;
|
||||
|
||||
struct motorcontrol {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct device *dev;
|
||||
int dev_no;
|
||||
u8 inputs[4];
|
||||
s8 desired_speed[2];
|
||||
s8 speed[2];
|
||||
s16 _current[2];
|
||||
s8 acceleration[2];
|
||||
struct urb *irq;
|
||||
unsigned char *data;
|
||||
dma_addr_t data_dma;
|
||||
|
||||
struct delayed_work do_notify;
|
||||
unsigned long input_events;
|
||||
unsigned long speed_events;
|
||||
unsigned long exceed_events;
|
||||
};
|
||||
|
||||
static struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_MOTORCONTROL) },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
static int set_motor(struct motorcontrol *mc, int motor)
|
||||
{
|
||||
u8 *buffer;
|
||||
int speed, speed2, acceleration;
|
||||
int retval;
|
||||
|
||||
buffer = kzalloc(8, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&mc->intf->dev, "%s - out of memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
acceleration = mc->acceleration[motor] * 10;
|
||||
/* -127 <= speed <= 127 */
|
||||
speed = (mc->desired_speed[motor] * 127) / 100;
|
||||
/* -0x7300 <= speed2 <= 0x7300 */
|
||||
speed2 = (mc->desired_speed[motor] * 230 * 128) / 100;
|
||||
|
||||
buffer[0] = motor;
|
||||
buffer[1] = speed;
|
||||
buffer[2] = acceleration >> 8;
|
||||
buffer[3] = acceleration;
|
||||
buffer[4] = speed2 >> 8;
|
||||
buffer[5] = speed2;
|
||||
|
||||
retval = usb_control_msg(mc->udev,
|
||||
usb_sndctrlpipe(mc->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
|
||||
|
||||
if (retval != 8)
|
||||
dev_err(&mc->intf->dev, "usb_control_msg returned %d\n",
|
||||
retval);
|
||||
kfree(buffer);
|
||||
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static void motorcontrol_irq(struct urb *urb)
|
||||
{
|
||||
struct motorcontrol *mc = urb->context;
|
||||
unsigned char *buffer = mc->data;
|
||||
int i, level;
|
||||
int retval;
|
||||
int status = urb->status;;
|
||||
|
||||
switch (status) {
|
||||
case 0: /* success */
|
||||
break;
|
||||
case -ECONNRESET: /* unlink */
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
/* -EPIPE: should clear the halt */
|
||||
default: /* error */
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
/* digital inputs */
|
||||
for (i=0; i<4; i++) {
|
||||
level = (buffer[0] >> i) & 1;
|
||||
if (mc->inputs[i] != level) {
|
||||
mc->inputs[i] = level;
|
||||
set_bit(i, &mc->input_events);
|
||||
}
|
||||
}
|
||||
|
||||
/* motor speed */
|
||||
if (buffer[2] == 0) {
|
||||
for (i=0; i<2; i++) {
|
||||
level = ((s8)buffer[4+i]) * 100 / 127;
|
||||
if (mc->speed[i] != level) {
|
||||
mc->speed[i] = level;
|
||||
set_bit(i, &mc->speed_events);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int index = buffer[3] & 1;
|
||||
|
||||
level = ((s8)buffer[4] << 8) | buffer[5];
|
||||
level = level * 100 / 29440;
|
||||
if (mc->speed[index] != level) {
|
||||
mc->speed[index] = level;
|
||||
set_bit(index, &mc->speed_events);
|
||||
}
|
||||
|
||||
level = ((s8)buffer[6] << 8) | buffer[7];
|
||||
mc->_current[index] = level * 100 / 1572;
|
||||
}
|
||||
|
||||
if (buffer[1] & 1)
|
||||
set_bit(0, &mc->exceed_events);
|
||||
|
||||
if (buffer[1] & 2)
|
||||
set_bit(1, &mc->exceed_events);
|
||||
|
||||
if (mc->input_events || mc->exceed_events || mc->speed_events)
|
||||
schedule_delayed_work(&mc->do_notify, 0);
|
||||
|
||||
resubmit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
dev_err(&mc->intf->dev,
|
||||
"can't resubmit intr, %s-%s/motorcontrol0, retval %d\n",
|
||||
mc->udev->bus->bus_name,
|
||||
mc->udev->devpath, retval);
|
||||
}
|
||||
|
||||
static void do_notify(struct work_struct *work)
|
||||
{
|
||||
struct motorcontrol *mc =
|
||||
container_of(work, struct motorcontrol, do_notify.work);
|
||||
int i;
|
||||
char sysfs_file[8];
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
if (test_and_clear_bit(i, &mc->input_events)) {
|
||||
sprintf(sysfs_file, "input%d", i);
|
||||
sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
if (test_and_clear_bit(i, &mc->speed_events)) {
|
||||
sprintf(sysfs_file, "speed%d", i);
|
||||
sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
if (test_and_clear_bit(i, &mc->exceed_events))
|
||||
dev_warn(&mc->intf->dev,
|
||||
"motor #%d exceeds 1.5 Amp current limit\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
#define show_set_speed(value) \
|
||||
static ssize_t set_speed##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct motorcontrol *mc = dev_get_drvdata(dev); \
|
||||
int speed; \
|
||||
int retval; \
|
||||
\
|
||||
if (sscanf(buf, "%d", &speed) < 1) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (speed < -100 || speed > 100) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
mc->desired_speed[value] = speed; \
|
||||
\
|
||||
retval = set_motor(mc, value); \
|
||||
\
|
||||
return retval ? retval : count; \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_speed##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct motorcontrol *mc = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", mc->speed[value]); \
|
||||
}
|
||||
|
||||
#define speed_attr(value) \
|
||||
__ATTR(speed##value, S_IWUGO | S_IRUGO, \
|
||||
show_speed##value, set_speed##value)
|
||||
|
||||
show_set_speed(0);
|
||||
show_set_speed(1);
|
||||
|
||||
#define show_set_acceleration(value) \
|
||||
static ssize_t set_acceleration##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct motorcontrol *mc = dev_get_drvdata(dev); \
|
||||
int acceleration; \
|
||||
int retval; \
|
||||
\
|
||||
if (sscanf(buf, "%d", &acceleration) < 1) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (acceleration < 0 || acceleration > 100) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
mc->acceleration[value] = acceleration; \
|
||||
\
|
||||
retval = set_motor(mc, value); \
|
||||
\
|
||||
return retval ? retval : count; \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_acceleration##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct motorcontrol *mc = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", mc->acceleration[value]); \
|
||||
}
|
||||
|
||||
#define acceleration_attr(value) \
|
||||
__ATTR(acceleration##value, S_IWUGO | S_IRUGO, \
|
||||
show_acceleration##value, set_acceleration##value)
|
||||
|
||||
show_set_acceleration(0);
|
||||
show_set_acceleration(1);
|
||||
|
||||
#define show_current(value) \
|
||||
static ssize_t show_current##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct motorcontrol *mc = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%dmA\n", (int)mc->_current[value]); \
|
||||
}
|
||||
|
||||
#define current_attr(value) \
|
||||
__ATTR(current##value, S_IRUGO, show_current##value, NULL)
|
||||
|
||||
show_current(0);
|
||||
show_current(1);
|
||||
|
||||
#define show_input(value) \
|
||||
static ssize_t show_input##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct motorcontrol *mc = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", (int)mc->inputs[value]); \
|
||||
}
|
||||
|
||||
#define input_attr(value) \
|
||||
__ATTR(input##value, S_IRUGO, show_input##value, NULL)
|
||||
|
||||
show_input(0);
|
||||
show_input(1);
|
||||
show_input(2);
|
||||
show_input(3);
|
||||
|
||||
static struct device_attribute dev_attrs[] = {
|
||||
input_attr(0),
|
||||
input_attr(1),
|
||||
input_attr(2),
|
||||
input_attr(3),
|
||||
speed_attr(0),
|
||||
speed_attr(1),
|
||||
acceleration_attr(0),
|
||||
acceleration_attr(1),
|
||||
current_attr(0),
|
||||
current_attr(1)
|
||||
};
|
||||
|
||||
static int motorcontrol_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *interface;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct motorcontrol *mc;
|
||||
int pipe, maxp, rc = -ENOMEM;
|
||||
int bit, value, i;
|
||||
|
||||
interface = intf->cur_altsetting;
|
||||
if (interface->desc.bNumEndpoints != 1)
|
||||
return -ENODEV;
|
||||
|
||||
endpoint = &interface->endpoint[0].desc;
|
||||
if (!usb_endpoint_dir_in(endpoint))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* bmAttributes
|
||||
*/
|
||||
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
|
||||
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
|
||||
|
||||
mc = kzalloc(sizeof(*mc), GFP_KERNEL);
|
||||
if (!mc)
|
||||
goto out;
|
||||
|
||||
mc->dev_no = -1;
|
||||
mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, GFP_ATOMIC, &mc->data_dma);
|
||||
if (!mc->data)
|
||||
goto out;
|
||||
|
||||
mc->irq = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!mc->irq)
|
||||
goto out;
|
||||
|
||||
mc->udev = usb_get_dev(dev);
|
||||
mc->intf = intf;
|
||||
mc->acceleration[0] = mc->acceleration[1] = 10;
|
||||
INIT_DELAYED_WORK(&mc->do_notify, do_notify);
|
||||
usb_fill_int_urb(mc->irq, mc->udev, pipe, mc->data,
|
||||
maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
|
||||
motorcontrol_irq, mc, endpoint->bInterval);
|
||||
mc->irq->transfer_dma = mc->data_dma;
|
||||
mc->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
usb_set_intfdata(intf, mc);
|
||||
|
||||
do {
|
||||
bit = find_first_zero_bit(&device_no, sizeof(device_no));
|
||||
value = test_and_set_bit(bit, &device_no);
|
||||
} while(value);
|
||||
mc->dev_no = bit;
|
||||
|
||||
mc->dev = device_create(phidget_class, &mc->udev->dev, MKDEV(0, 0), mc,
|
||||
"motorcontrol%d", mc->dev_no);
|
||||
if (IS_ERR(mc->dev)) {
|
||||
rc = PTR_ERR(mc->dev);
|
||||
mc->dev = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (usb_submit_urb(mc->irq, GFP_KERNEL)) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(dev_attrs); i++) {
|
||||
rc = device_create_file(mc->dev, &dev_attrs[i]);
|
||||
if (rc)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
dev_info(&intf->dev, "USB PhidgetMotorControl attached\n");
|
||||
|
||||
return 0;
|
||||
out2:
|
||||
while (i-- > 0)
|
||||
device_remove_file(mc->dev, &dev_attrs[i]);
|
||||
out:
|
||||
if (mc) {
|
||||
usb_free_urb(mc->irq);
|
||||
if (mc->data)
|
||||
usb_buffer_free(dev, URB_INT_SIZE, mc->data, mc->data_dma);
|
||||
if (mc->dev)
|
||||
device_unregister(mc->dev);
|
||||
if (mc->dev_no >= 0)
|
||||
clear_bit(mc->dev_no, &device_no);
|
||||
|
||||
kfree(mc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void motorcontrol_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct motorcontrol *mc;
|
||||
int i;
|
||||
|
||||
mc = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
if (!mc)
|
||||
return;
|
||||
|
||||
usb_kill_urb(mc->irq);
|
||||
usb_free_urb(mc->irq);
|
||||
usb_buffer_free(mc->udev, URB_INT_SIZE, mc->data, mc->data_dma);
|
||||
|
||||
cancel_delayed_work(&mc->do_notify);
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(dev_attrs); i++)
|
||||
device_remove_file(mc->dev, &dev_attrs[i]);
|
||||
|
||||
device_unregister(mc->dev);
|
||||
|
||||
usb_put_dev(mc->udev);
|
||||
clear_bit(mc->dev_no, &device_no);
|
||||
kfree(mc);
|
||||
|
||||
dev_info(&interface->dev, "USB PhidgetMotorControl detached\n");
|
||||
}
|
||||
|
||||
static struct usb_driver motorcontrol_driver = {
|
||||
.name = "phidgetmotorcontrol",
|
||||
.probe = motorcontrol_probe,
|
||||
.disconnect = motorcontrol_disconnect,
|
||||
.id_table = id_table
|
||||
};
|
||||
|
||||
static int __init motorcontrol_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
retval = usb_register(&motorcontrol_driver);
|
||||
if (retval)
|
||||
err("usb_register failed. Error number %d", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit motorcontrol_exit(void)
|
||||
{
|
||||
usb_deregister(&motorcontrol_driver);
|
||||
}
|
||||
|
||||
module_init(motorcontrol_init);
|
||||
module_exit(motorcontrol_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,375 +0,0 @@
|
|||
/*
|
||||
* USB PhidgetServo driver 1.0
|
||||
*
|
||||
* Copyright (C) 2004, 2006 Sean Young <sean@mess.org>
|
||||
*
|
||||
* 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 is a driver for the USB PhidgetServo version 2.0 and 3.0 servo
|
||||
* controllers available at: http://www.phidgets.com/
|
||||
*
|
||||
* Note that the driver takes input as: degrees.minutes
|
||||
*
|
||||
* CAUTION: Generally you should use 0 < degrees < 180 as anything else
|
||||
* is probably beyond the range of your servo and may damage it.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "phidget.h"
|
||||
|
||||
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
|
||||
#define DRIVER_DESC "USB PhidgetServo Driver"
|
||||
|
||||
#define VENDOR_ID_GLAB 0x06c2
|
||||
#define DEVICE_ID_GLAB_PHIDGETSERVO_QUAD 0x0038
|
||||
#define DEVICE_ID_GLAB_PHIDGETSERVO_UNI 0x0039
|
||||
|
||||
#define VENDOR_ID_WISEGROUP 0x0925
|
||||
#define VENDOR_ID_WISEGROUP_PHIDGETSERVO_QUAD 0x8101
|
||||
#define VENDOR_ID_WISEGROUP_PHIDGETSERVO_UNI 0x8104
|
||||
|
||||
#define SERVO_VERSION_30 0x01
|
||||
#define SERVO_COUNT_QUAD 0x02
|
||||
|
||||
static struct usb_device_id id_table[] = {
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_GLAB_PHIDGETSERVO_QUAD),
|
||||
.driver_info = SERVO_VERSION_30 | SERVO_COUNT_QUAD
|
||||
},
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_GLAB_PHIDGETSERVO_UNI),
|
||||
.driver_info = SERVO_VERSION_30
|
||||
},
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_WISEGROUP,
|
||||
VENDOR_ID_WISEGROUP_PHIDGETSERVO_QUAD),
|
||||
.driver_info = SERVO_COUNT_QUAD
|
||||
},
|
||||
{
|
||||
USB_DEVICE(VENDOR_ID_WISEGROUP,
|
||||
VENDOR_ID_WISEGROUP_PHIDGETSERVO_UNI),
|
||||
.driver_info = 0
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
static int unsigned long device_no;
|
||||
|
||||
struct phidget_servo {
|
||||
struct usb_device *udev;
|
||||
struct device *dev;
|
||||
int dev_no;
|
||||
ulong type;
|
||||
int pulse[4];
|
||||
int degrees[4];
|
||||
int minutes[4];
|
||||
};
|
||||
|
||||
static int
|
||||
change_position_v30(struct phidget_servo *servo, int servo_no, int degrees,
|
||||
int minutes)
|
||||
{
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
if (degrees < -23 || degrees > 362)
|
||||
return -EINVAL;
|
||||
|
||||
buffer = kmalloc(6, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&servo->udev->dev, "%s - out of memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* pulse = 0 - 4095
|
||||
* angle = 0 - 180 degrees
|
||||
*
|
||||
* pulse = angle * 10.6 + 243.8
|
||||
*/
|
||||
servo->pulse[servo_no] = ((degrees*60 + minutes)*106 + 2438*60)/600;
|
||||
servo->degrees[servo_no]= degrees;
|
||||
servo->minutes[servo_no]= minutes;
|
||||
|
||||
/*
|
||||
* The PhidgetServo v3.0 is controlled by sending 6 bytes,
|
||||
* 4 * 12 bits for each servo.
|
||||
*
|
||||
* low = lower 8 bits pulse
|
||||
* high = higher 4 bits pulse
|
||||
*
|
||||
* offset bits
|
||||
* +---+-----------------+
|
||||
* | 0 | low 0 |
|
||||
* +---+--------+--------+
|
||||
* | 1 | high 1 | high 0 |
|
||||
* +---+--------+--------+
|
||||
* | 2 | low 1 |
|
||||
* +---+-----------------+
|
||||
* | 3 | low 2 |
|
||||
* +---+--------+--------+
|
||||
* | 4 | high 3 | high 2 |
|
||||
* +---+--------+--------+
|
||||
* | 5 | low 3 |
|
||||
* +---+-----------------+
|
||||
*/
|
||||
|
||||
buffer[0] = servo->pulse[0] & 0xff;
|
||||
buffer[1] = (servo->pulse[0] >> 8 & 0x0f)
|
||||
| (servo->pulse[1] >> 4 & 0xf0);
|
||||
buffer[2] = servo->pulse[1] & 0xff;
|
||||
buffer[3] = servo->pulse[2] & 0xff;
|
||||
buffer[4] = (servo->pulse[2] >> 8 & 0x0f)
|
||||
| (servo->pulse[3] >> 4 & 0xf0);
|
||||
buffer[5] = servo->pulse[3] & 0xff;
|
||||
|
||||
dev_dbg(&servo->udev->dev,
|
||||
"data: %02x %02x %02x %02x %02x %02x\n",
|
||||
buffer[0], buffer[1], buffer[2],
|
||||
buffer[3], buffer[4], buffer[5]);
|
||||
|
||||
retval = usb_control_msg(servo->udev,
|
||||
usb_sndctrlpipe(servo->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2000);
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,
|
||||
int minutes)
|
||||
{
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
|
||||
if (degrees < -23 || degrees > 278)
|
||||
return -EINVAL;
|
||||
|
||||
buffer = kmalloc(2, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
dev_err(&servo->udev->dev, "%s - out of memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* angle = 0 - 180 degrees
|
||||
* pulse = angle + 23
|
||||
*/
|
||||
servo->pulse[servo_no]= degrees + 23;
|
||||
servo->degrees[servo_no]= degrees;
|
||||
servo->minutes[servo_no]= 0;
|
||||
|
||||
/*
|
||||
* The PhidgetServo v2.0 is controlled by sending two bytes. The
|
||||
* first byte is the servo number xor'ed with 2:
|
||||
*
|
||||
* servo 0 = 2
|
||||
* servo 1 = 3
|
||||
* servo 2 = 0
|
||||
* servo 3 = 1
|
||||
*
|
||||
* The second byte is the position.
|
||||
*/
|
||||
|
||||
buffer[0] = servo_no ^ 2;
|
||||
buffer[1] = servo->pulse[servo_no];
|
||||
|
||||
dev_dbg(&servo->udev->dev, "data: %02x %02x\n", buffer[0], buffer[1]);
|
||||
|
||||
retval = usb_control_msg(servo->udev,
|
||||
usb_sndctrlpipe(servo->udev, 0),
|
||||
0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2000);
|
||||
|
||||
kfree(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define show_set(value) \
|
||||
static ssize_t set_servo##value (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
int degrees, minutes, retval; \
|
||||
struct phidget_servo *servo = dev_get_drvdata(dev); \
|
||||
\
|
||||
minutes = 0; \
|
||||
/* must at least convert degrees */ \
|
||||
if (sscanf(buf, "%d.%d", °rees, &minutes) < 1) { \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
\
|
||||
if (minutes < 0 || minutes > 59) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
if (servo->type & SERVO_VERSION_30) \
|
||||
retval = change_position_v30(servo, value, degrees, \
|
||||
minutes); \
|
||||
else \
|
||||
retval = change_position_v20(servo, value, degrees, \
|
||||
minutes); \
|
||||
\
|
||||
return retval < 0 ? retval : count; \
|
||||
} \
|
||||
\
|
||||
static ssize_t show_servo##value (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct phidget_servo *servo = dev_get_drvdata(dev); \
|
||||
\
|
||||
return sprintf(buf, "%d.%02d\n", servo->degrees[value], \
|
||||
servo->minutes[value]); \
|
||||
}
|
||||
|
||||
#define servo_attr(value) \
|
||||
__ATTR(servo##value, S_IWUGO | S_IRUGO, \
|
||||
show_servo##value, set_servo##value)
|
||||
show_set(0);
|
||||
show_set(1);
|
||||
show_set(2);
|
||||
show_set(3);
|
||||
|
||||
static struct device_attribute dev_attrs[] = {
|
||||
servo_attr(0), servo_attr(1), servo_attr(2), servo_attr(3)
|
||||
};
|
||||
|
||||
static int
|
||||
servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct phidget_servo *dev;
|
||||
int bit, value, rc;
|
||||
int servo_count, i;
|
||||
|
||||
dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
dev_err(&interface->dev, "%s - out of memory\n", __func__);
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->udev = usb_get_dev(udev);
|
||||
dev->type = id->driver_info;
|
||||
dev->dev_no = -1;
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
do {
|
||||
bit = find_first_zero_bit(&device_no, sizeof(device_no));
|
||||
value = test_and_set_bit(bit, &device_no);
|
||||
} while (value);
|
||||
dev->dev_no = bit;
|
||||
|
||||
dev->dev = device_create(phidget_class, &dev->udev->dev, MKDEV(0, 0),
|
||||
dev, "servo%d", dev->dev_no);
|
||||
if (IS_ERR(dev->dev)) {
|
||||
rc = PTR_ERR(dev->dev);
|
||||
dev->dev = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
|
||||
|
||||
for (i=0; i<servo_count; i++) {
|
||||
rc = device_create_file(dev->dev, &dev_attrs[i]);
|
||||
if (rc)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",
|
||||
servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
|
||||
|
||||
if (!(dev->type & SERVO_VERSION_30))
|
||||
dev_info(&interface->dev,
|
||||
"WARNING: v2.0 not tested! Please report if it works.\n");
|
||||
|
||||
return 0;
|
||||
out2:
|
||||
while (i-- > 0)
|
||||
device_remove_file(dev->dev, &dev_attrs[i]);
|
||||
out:
|
||||
if (dev) {
|
||||
if (dev->dev)
|
||||
device_unregister(dev->dev);
|
||||
if (dev->dev_no >= 0)
|
||||
clear_bit(dev->dev_no, &device_no);
|
||||
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
servo_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct phidget_servo *dev;
|
||||
int servo_count, i;
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
|
||||
|
||||
for (i=0; i<servo_count; i++)
|
||||
device_remove_file(dev->dev, &dev_attrs[i]);
|
||||
|
||||
device_unregister(dev->dev);
|
||||
usb_put_dev(dev->udev);
|
||||
|
||||
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",
|
||||
servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
|
||||
|
||||
clear_bit(dev->dev_no, &device_no);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct usb_driver servo_driver = {
|
||||
.name = "phidgetservo",
|
||||
.probe = servo_probe,
|
||||
.disconnect = servo_disconnect,
|
||||
.id_table = id_table
|
||||
};
|
||||
|
||||
static int __init
|
||||
phidget_servo_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = usb_register(&servo_driver);
|
||||
if (retval)
|
||||
err("usb_register failed. Error number %d", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
phidget_servo_exit(void)
|
||||
{
|
||||
usb_deregister(&servo_driver);
|
||||
}
|
||||
|
||||
module_init(phidget_servo_init);
|
||||
module_exit(phidget_servo_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -37,10 +37,13 @@
|
|||
#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
|
||||
#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
|
||||
#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
|
||||
/* #9 was MON_IOCT_SETAPI */
|
||||
#define MON_IOCX_GETX _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get)
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
|
||||
#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
|
||||
#define MON_IOCX_GETX32 _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get32)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -92,7 +95,29 @@ struct mon_bin_hdr {
|
|||
int status;
|
||||
unsigned int len_urb; /* Length of data (submitted or actual) */
|
||||
unsigned int len_cap; /* Delivered length */
|
||||
unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
|
||||
union {
|
||||
unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
|
||||
struct iso_rec {
|
||||
int error_count;
|
||||
int numdesc;
|
||||
} iso;
|
||||
} s;
|
||||
int interval;
|
||||
int start_frame;
|
||||
unsigned int xfer_flags;
|
||||
unsigned int ndesc; /* Actual number of ISO descriptors */
|
||||
};
|
||||
|
||||
/*
|
||||
* ISO vector, packed into the head of data stream.
|
||||
* This has to take 16 bytes to make sure that the end of buffer
|
||||
* wrap is not happening in the middle of a descriptor.
|
||||
*/
|
||||
struct mon_bin_isodesc {
|
||||
int iso_status;
|
||||
unsigned int iso_off;
|
||||
unsigned int iso_len;
|
||||
u32 _pad;
|
||||
};
|
||||
|
||||
/* per file statistic */
|
||||
|
@ -102,7 +127,7 @@ struct mon_bin_stats {
|
|||
};
|
||||
|
||||
struct mon_bin_get {
|
||||
struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */
|
||||
struct mon_bin_hdr __user *hdr; /* Can be 48 bytes or 64. */
|
||||
void __user *data;
|
||||
size_t alloc; /* Length of data (can be zero) */
|
||||
};
|
||||
|
@ -131,6 +156,11 @@ struct mon_bin_mfetch32 {
|
|||
#define PKT_ALIGN 64
|
||||
#define PKT_SIZE 64
|
||||
|
||||
#define PKT_SZ_API0 48 /* API 0 (2.6.20) size */
|
||||
#define PKT_SZ_API1 64 /* API 1 size: extra fields */
|
||||
|
||||
#define ISODESC_MAX 128 /* Same number as usbfs allows, 2048 bytes. */
|
||||
|
||||
/* max number of USB bus supported */
|
||||
#define MON_BIN_MAX_MINOR 128
|
||||
|
||||
|
@ -360,12 +390,8 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
|
|||
const struct urb *urb, char ev_type)
|
||||
{
|
||||
|
||||
if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
|
||||
return '-';
|
||||
|
||||
if (urb->setup_packet == NULL)
|
||||
return 'Z';
|
||||
|
||||
memcpy(setupb, urb->setup_packet, SETUP_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
@ -387,6 +413,26 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mon_bin_get_isodesc(const struct mon_reader_bin *rp,
|
||||
unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc)
|
||||
{
|
||||
struct mon_bin_isodesc *dp;
|
||||
struct usb_iso_packet_descriptor *fp;
|
||||
|
||||
fp = urb->iso_frame_desc;
|
||||
while (ndesc-- != 0) {
|
||||
dp = (struct mon_bin_isodesc *)
|
||||
(rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
|
||||
dp->iso_status = fp->status;
|
||||
dp->iso_off = fp->offset;
|
||||
dp->iso_len = (ev_type == 'S') ? fp->length : fp->actual_length;
|
||||
dp->_pad = 0;
|
||||
if ((offset += sizeof(struct mon_bin_isodesc)) >= rp->b_size)
|
||||
offset = 0;
|
||||
fp++;
|
||||
}
|
||||
}
|
||||
|
||||
static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
|
||||
char ev_type, int status)
|
||||
{
|
||||
|
@ -396,6 +442,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
|
|||
unsigned int urb_length;
|
||||
unsigned int offset;
|
||||
unsigned int length;
|
||||
unsigned int ndesc, lendesc;
|
||||
unsigned char dir;
|
||||
struct mon_bin_hdr *ep;
|
||||
char data_tag = 0;
|
||||
|
@ -407,6 +454,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
|
|||
/*
|
||||
* Find the maximum allowable length, then allocate space.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(epd)) {
|
||||
if (urb->number_of_packets < 0) {
|
||||
ndesc = 0;
|
||||
} else if (urb->number_of_packets >= ISODESC_MAX) {
|
||||
ndesc = ISODESC_MAX;
|
||||
} else {
|
||||
ndesc = urb->number_of_packets;
|
||||
}
|
||||
} else {
|
||||
ndesc = 0;
|
||||
}
|
||||
lendesc = ndesc*sizeof(struct mon_bin_isodesc);
|
||||
|
||||
urb_length = (ev_type == 'S') ?
|
||||
urb->transfer_buffer_length : urb->actual_length;
|
||||
length = urb_length;
|
||||
|
@ -429,10 +489,12 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
|
|||
dir = 0;
|
||||
}
|
||||
|
||||
if (rp->mmap_active)
|
||||
offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
|
||||
else
|
||||
offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
|
||||
if (rp->mmap_active) {
|
||||
offset = mon_buff_area_alloc_contiguous(rp,
|
||||
length + PKT_SIZE + lendesc);
|
||||
} else {
|
||||
offset = mon_buff_area_alloc(rp, length + PKT_SIZE + lendesc);
|
||||
}
|
||||
if (offset == ~0) {
|
||||
rp->cnt_lost++;
|
||||
spin_unlock_irqrestore(&rp->b_lock, flags);
|
||||
|
@ -456,9 +518,31 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
|
|||
ep->ts_usec = ts.tv_usec;
|
||||
ep->status = status;
|
||||
ep->len_urb = urb_length;
|
||||
ep->len_cap = length;
|
||||
ep->len_cap = length + lendesc;
|
||||
ep->xfer_flags = urb->transfer_flags;
|
||||
|
||||
if (usb_endpoint_xfer_int(epd)) {
|
||||
ep->interval = urb->interval;
|
||||
} else if (usb_endpoint_xfer_isoc(epd)) {
|
||||
ep->interval = urb->interval;
|
||||
ep->start_frame = urb->start_frame;
|
||||
ep->s.iso.error_count = urb->error_count;
|
||||
ep->s.iso.numdesc = urb->number_of_packets;
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_control(epd) && ev_type == 'S') {
|
||||
ep->flag_setup = mon_bin_get_setup(ep->s.setup, urb, ev_type);
|
||||
} else {
|
||||
ep->flag_setup = '-';
|
||||
}
|
||||
|
||||
if (ndesc != 0) {
|
||||
ep->ndesc = ndesc;
|
||||
mon_bin_get_isodesc(rp, offset, urb, ev_type, ndesc);
|
||||
if ((offset += lendesc) >= rp->b_size)
|
||||
offset -= rp->b_size;
|
||||
}
|
||||
|
||||
ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
|
||||
if (length != 0) {
|
||||
ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
|
||||
if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
|
||||
|
@ -592,7 +676,8 @@ err_alloc:
|
|||
* Returns zero or error.
|
||||
*/
|
||||
static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
|
||||
struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
|
||||
struct mon_bin_hdr __user *hdr, unsigned int hdrbytes,
|
||||
void __user *data, unsigned int nbytes)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct mon_bin_hdr *ep;
|
||||
|
@ -609,7 +694,7 @@ static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
|
|||
|
||||
ep = MON_OFF2HDR(rp, rp->b_out);
|
||||
|
||||
if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
|
||||
if (copy_to_user(hdr, ep, hdrbytes)) {
|
||||
mutex_unlock(&rp->fetch_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
@ -657,6 +742,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf,
|
|||
size_t nbytes, loff_t *ppos)
|
||||
{
|
||||
struct mon_reader_bin *rp = file->private_data;
|
||||
unsigned int hdrbytes = PKT_SZ_API0;
|
||||
unsigned long flags;
|
||||
struct mon_bin_hdr *ep;
|
||||
unsigned int offset;
|
||||
|
@ -674,8 +760,8 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf,
|
|||
|
||||
ep = MON_OFF2HDR(rp, rp->b_out);
|
||||
|
||||
if (rp->b_read < sizeof(struct mon_bin_hdr)) {
|
||||
step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
|
||||
if (rp->b_read < hdrbytes) {
|
||||
step_len = min(nbytes, (size_t)(hdrbytes - rp->b_read));
|
||||
ptr = ((char *)ep) + rp->b_read;
|
||||
if (step_len && copy_to_user(buf, ptr, step_len)) {
|
||||
mutex_unlock(&rp->fetch_lock);
|
||||
|
@ -687,13 +773,13 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf,
|
|||
done += step_len;
|
||||
}
|
||||
|
||||
if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
|
||||
if (rp->b_read >= hdrbytes) {
|
||||
step_len = ep->len_cap;
|
||||
step_len -= rp->b_read - sizeof(struct mon_bin_hdr);
|
||||
step_len -= rp->b_read - hdrbytes;
|
||||
if (step_len > nbytes)
|
||||
step_len = nbytes;
|
||||
offset = rp->b_out + PKT_SIZE;
|
||||
offset += rp->b_read - sizeof(struct mon_bin_hdr);
|
||||
offset += rp->b_read - hdrbytes;
|
||||
if (offset >= rp->b_size)
|
||||
offset -= rp->b_size;
|
||||
if (copy_from_buf(rp, offset, buf, step_len)) {
|
||||
|
@ -709,7 +795,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf,
|
|||
/*
|
||||
* Check if whole packet was read, and if so, jump to the next one.
|
||||
*/
|
||||
if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
|
||||
if (rp->b_read >= hdrbytes + ep->len_cap) {
|
||||
spin_lock_irqsave(&rp->b_lock, flags);
|
||||
mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
|
||||
spin_unlock_irqrestore(&rp->b_lock, flags);
|
||||
|
@ -908,6 +994,7 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file,
|
|||
break;
|
||||
|
||||
case MON_IOCX_GET:
|
||||
case MON_IOCX_GETX:
|
||||
{
|
||||
struct mon_bin_get getb;
|
||||
|
||||
|
@ -917,8 +1004,9 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file,
|
|||
|
||||
if (getb.alloc > 0x10000000) /* Want to cast to u32 */
|
||||
return -EINVAL;
|
||||
ret = mon_bin_get_event(file, rp,
|
||||
getb.hdr, getb.data, (unsigned int)getb.alloc);
|
||||
ret = mon_bin_get_event(file, rp, getb.hdr,
|
||||
(cmd == MON_IOCX_GET)? PKT_SZ_API0: PKT_SZ_API1,
|
||||
getb.data, (unsigned int)getb.alloc);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -984,16 +1072,18 @@ static long mon_bin_compat_ioctl(struct file *file,
|
|||
|
||||
switch (cmd) {
|
||||
|
||||
case MON_IOCX_GET32: {
|
||||
case MON_IOCX_GET32:
|
||||
case MON_IOCX_GETX32:
|
||||
{
|
||||
struct mon_bin_get32 getb;
|
||||
|
||||
if (copy_from_user(&getb, (void __user *)arg,
|
||||
sizeof(struct mon_bin_get32)))
|
||||
return -EFAULT;
|
||||
|
||||
ret = mon_bin_get_event(file, rp,
|
||||
compat_ptr(getb.hdr32), compat_ptr(getb.data32),
|
||||
getb.alloc32);
|
||||
ret = mon_bin_get_event(file, rp, compat_ptr(getb.hdr32),
|
||||
(cmd == MON_IOCX_GET32)? PKT_SZ_API0: PKT_SZ_API1,
|
||||
compat_ptr(getb.data32), getb.alloc32);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ config USB_MUSB_HDRC
|
|||
it's being used with, including the USB peripheral role,
|
||||
or the USB host role, or both.
|
||||
|
||||
Texas Instruments parts using this IP include DaVinci 644x,
|
||||
OMAP 243x, OMAP 343x, and TUSB 6010.
|
||||
Texas Instruments familiies using this IP include DaVinci
|
||||
(35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010.
|
||||
|
||||
Analog Devices parts using this IP include Blackfin BF54x,
|
||||
BF525 and BF527.
|
||||
|
@ -40,7 +40,7 @@ config USB_MUSB_SOC
|
|||
default y if (BF54x && !BF544)
|
||||
default y if (BF52x && !BF522 && !BF523)
|
||||
|
||||
comment "DaVinci 644x USB support"
|
||||
comment "DaVinci 35x and 644x USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_DAVINCI
|
||||
|
||||
comment "OMAP 243x high speed USB support"
|
||||
|
|
|
@ -48,6 +48,9 @@
|
|||
#include "cppi_dma.h"
|
||||
|
||||
|
||||
#define USB_PHY_CTRL IO_ADDRESS(USBPHY_CTL_PADDR)
|
||||
#define DM355_DEEPSLEEP IO_ADDRESS(DM355_DEEPSLEEP_PADDR)
|
||||
|
||||
/* REVISIT (PM) we should be able to keep the PHY in low power mode most
|
||||
* of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
|
||||
* and, when in host mode, autosuspending idle root ports... PHYPLLON
|
||||
|
@ -56,20 +59,26 @@
|
|||
|
||||
static inline void phy_on(void)
|
||||
{
|
||||
/* start the on-chip PHY and its PLL */
|
||||
__raw_writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON,
|
||||
(void __force __iomem *) IO_ADDRESS(USBPHY_CTL_PADDR));
|
||||
while ((__raw_readl((void __force __iomem *)
|
||||
IO_ADDRESS(USBPHY_CTL_PADDR))
|
||||
& USBPHY_PHYCLKGD) == 0)
|
||||
u32 phy_ctrl = __raw_readl(USB_PHY_CTRL);
|
||||
|
||||
/* power everything up; start the on-chip PHY and its PLL */
|
||||
phy_ctrl &= ~(USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN);
|
||||
phy_ctrl |= USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON;
|
||||
__raw_writel(phy_ctrl, USB_PHY_CTRL);
|
||||
|
||||
/* wait for PLL to lock before proceeding */
|
||||
while ((__raw_readl(USB_PHY_CTRL) & USBPHY_PHYCLKGD) == 0)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static inline void phy_off(void)
|
||||
{
|
||||
/* powerdown the on-chip PHY and its oscillator */
|
||||
__raw_writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, (void __force __iomem *)
|
||||
IO_ADDRESS(USBPHY_CTL_PADDR));
|
||||
u32 phy_ctrl = __raw_readl(USB_PHY_CTRL);
|
||||
|
||||
/* powerdown the on-chip PHY, its PLL, and the OTG block */
|
||||
phy_ctrl &= ~(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON);
|
||||
phy_ctrl |= USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN;
|
||||
__raw_writel(phy_ctrl, USB_PHY_CTRL);
|
||||
}
|
||||
|
||||
static int dma_off = 1;
|
||||
|
@ -126,10 +135,6 @@ void musb_platform_disable(struct musb *musb)
|
|||
}
|
||||
|
||||
|
||||
/* REVISIT it's not clear whether DaVinci can support full OTG. */
|
||||
|
||||
static int vbus_state = -1;
|
||||
|
||||
#ifdef CONFIG_USB_MUSB_HDRC_HCD
|
||||
#define portstate(stmt) stmt
|
||||
#else
|
||||
|
@ -137,10 +142,19 @@ static int vbus_state = -1;
|
|||
#endif
|
||||
|
||||
|
||||
/* VBUS SWITCHING IS BOARD-SPECIFIC */
|
||||
/*
|
||||
* VBUS SWITCHING IS BOARD-SPECIFIC ... at least for the DM6446 EVM,
|
||||
* which doesn't wire DRVVBUS to the FET that switches it. Unclear
|
||||
* if that's a problem with the DM6446 chip or just with that board.
|
||||
*
|
||||
* In either case, the DM355 EVM automates DRVVBUS the normal way,
|
||||
* when J10 is out, and TI documents it as handling OTG.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MACH_DAVINCI_EVM
|
||||
|
||||
static int vbus_state = -1;
|
||||
|
||||
/* I2C operations are always synchronous, and require a task context.
|
||||
* With unloaded systems, using the shared workqueue seems to suffice
|
||||
* to satisfy the 100msec A_WAIT_VRISE timeout...
|
||||
|
@ -150,12 +164,12 @@ static void evm_deferred_drvvbus(struct work_struct *ignored)
|
|||
gpio_set_value_cansleep(GPIO_nVBUS_DRV, vbus_state);
|
||||
vbus_state = !vbus_state;
|
||||
}
|
||||
static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
|
||||
|
||||
#endif /* EVM */
|
||||
|
||||
static void davinci_source_power(struct musb *musb, int is_on, int immediate)
|
||||
{
|
||||
#ifdef CONFIG_MACH_DAVINCI_EVM
|
||||
if (is_on)
|
||||
is_on = 1;
|
||||
|
||||
|
@ -163,16 +177,17 @@ static void davinci_source_power(struct musb *musb, int is_on, int immediate)
|
|||
return;
|
||||
vbus_state = !is_on; /* 0/1 vs "-1 == unknown/init" */
|
||||
|
||||
#ifdef CONFIG_MACH_DAVINCI_EVM
|
||||
if (machine_is_davinci_evm()) {
|
||||
static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus);
|
||||
|
||||
if (immediate)
|
||||
gpio_set_value_cansleep(GPIO_nVBUS_DRV, vbus_state);
|
||||
else
|
||||
schedule_work(&evm_vbus_work);
|
||||
}
|
||||
#endif
|
||||
if (immediate)
|
||||
vbus_state = is_on;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void davinci_set_vbus(struct musb *musb, int is_on)
|
||||
|
@ -391,6 +406,17 @@ int __init musb_platform_init(struct musb *musb)
|
|||
musb->board_set_vbus = davinci_set_vbus;
|
||||
davinci_source_power(musb, 0, 1);
|
||||
|
||||
/* dm355 EVM swaps D+/D- for signal integrity, and
|
||||
* is clocked from the main 24 MHz crystal.
|
||||
*/
|
||||
if (machine_is_davinci_dm355_evm()) {
|
||||
u32 phy_ctrl = __raw_readl(USB_PHY_CTRL);
|
||||
|
||||
phy_ctrl &= ~(3 << 9);
|
||||
phy_ctrl |= USBPHY_DATAPOL;
|
||||
__raw_writel(phy_ctrl, USB_PHY_CTRL);
|
||||
}
|
||||
|
||||
/* reset the controller */
|
||||
musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
|
||||
|
||||
|
@ -401,8 +427,7 @@ int __init musb_platform_init(struct musb *musb)
|
|||
|
||||
/* NOTE: irqs are in mixed mode, not bypass to pure-musb */
|
||||
pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
|
||||
revision, __raw_readl((void __force __iomem *)
|
||||
IO_ADDRESS(USBPHY_CTL_PADDR)),
|
||||
revision, __raw_readl(USB_PHY_CTRL),
|
||||
musb_readb(tibase, DAVINCI_USB_CTRL_REG));
|
||||
|
||||
musb->isr = davinci_interrupt;
|
||||
|
|
|
@ -15,14 +15,21 @@
|
|||
*/
|
||||
|
||||
/* Integrated highspeed/otg PHY */
|
||||
#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
|
||||
#define USBPHY_PHYCLKGD (1 << 8)
|
||||
#define USBPHY_SESNDEN (1 << 7) /* v(sess_end) comparator */
|
||||
#define USBPHY_VBDTCTEN (1 << 6) /* v(bus) comparator */
|
||||
#define USBPHY_PHYPLLON (1 << 4) /* override pll suspend */
|
||||
#define USBPHY_CLKO1SEL (1 << 3)
|
||||
#define USBPHY_OSCPDWN (1 << 2)
|
||||
#define USBPHY_PHYPDWN (1 << 0)
|
||||
#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
|
||||
#define USBPHY_DATAPOL BIT(11) /* (dm355) switch D+/D- */
|
||||
#define USBPHY_PHYCLKGD BIT(8)
|
||||
#define USBPHY_SESNDEN BIT(7) /* v(sess_end) comparator */
|
||||
#define USBPHY_VBDTCTEN BIT(6) /* v(bus) comparator */
|
||||
#define USBPHY_VBUSSENS BIT(5) /* (dm355,ro) is vbus > 0.5V */
|
||||
#define USBPHY_PHYPLLON BIT(4) /* override pll suspend */
|
||||
#define USBPHY_CLKO1SEL BIT(3)
|
||||
#define USBPHY_OSCPDWN BIT(2)
|
||||
#define USBPHY_OTGPDWN BIT(1)
|
||||
#define USBPHY_PHYPDWN BIT(0)
|
||||
|
||||
#define DM355_DEEPSLEEP_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x48)
|
||||
#define DRVVBUS_FORCE BIT(2)
|
||||
#define DRVVBUS_OVERRIDE BIT(1)
|
||||
|
||||
/* For now include usb OTG module registers here */
|
||||
#define DAVINCI_USB_VERSION_REG 0x00
|
||||
|
|
|
@ -769,7 +769,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
|
|||
case OTG_STATE_A_SUSPEND:
|
||||
usb_hcd_resume_root_hub(musb_to_hcd(musb));
|
||||
musb_root_disconnect(musb);
|
||||
if (musb->a_wait_bcon != 0)
|
||||
if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
|
||||
musb_platform_try_idle(musb, jiffies
|
||||
+ msecs_to_jiffies(musb->a_wait_bcon));
|
||||
break;
|
||||
|
|
|
@ -331,7 +331,6 @@ struct musb {
|
|||
struct list_head control; /* of musb_qh */
|
||||
struct list_head in_bulk; /* of musb_qh */
|
||||
struct list_head out_bulk; /* of musb_qh */
|
||||
struct musb_qh *periodic[32]; /* tree of interrupt+iso */
|
||||
#endif
|
||||
|
||||
/* called with IRQs blocked; ON/nonzero implies starting a session,
|
||||
|
@ -479,10 +478,11 @@ static inline void musb_configure_ep0(struct musb *musb)
|
|||
static inline int musb_read_fifosize(struct musb *musb,
|
||||
struct musb_hw_ep *hw_ep, u8 epnum)
|
||||
{
|
||||
void *mbase = musb->mregs;
|
||||
u8 reg = 0;
|
||||
|
||||
/* read from core using indexed model */
|
||||
reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE);
|
||||
reg = musb_readb(mbase, MUSB_EP_OFFSET(epnum, MUSB_FIFOSIZE));
|
||||
/* 0's returned when no more endpoints */
|
||||
if (!reg)
|
||||
return -ENODEV;
|
||||
|
@ -509,6 +509,7 @@ static inline void musb_configure_ep0(struct musb *musb)
|
|||
{
|
||||
musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
|
||||
musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
|
||||
musb->endpoints[0].is_shared_fifo = true;
|
||||
}
|
||||
#endif /* CONFIG_BLACKFIN */
|
||||
|
||||
|
|
|
@ -64,11 +64,8 @@
|
|||
*
|
||||
* - DMA (Mentor/OMAP) ...has at least toggle update problems
|
||||
*
|
||||
* - Still no traffic scheduling code to make NAKing for bulk or control
|
||||
* transfers unable to starve other requests; or to make efficient use
|
||||
* of hardware with periodic transfers. (Note that network drivers
|
||||
* commonly post bulk reads that stay pending for a long time; these
|
||||
* would make very visible trouble.)
|
||||
* - [23-feb-2009] minimal traffic scheduling to avoid bulk RX packet
|
||||
* starvation ... nothing yet for TX, interrupt, or bulk.
|
||||
*
|
||||
* - Not tested with HNP, but some SRP paths seem to behave.
|
||||
*
|
||||
|
@ -88,11 +85,8 @@
|
|||
*
|
||||
* CONTROL transfers all go through ep0. BULK ones go through dedicated IN
|
||||
* and OUT endpoints ... hardware is dedicated for those "async" queue(s).
|
||||
*
|
||||
* (Yes, bulk _could_ use more of the endpoints than that, and would even
|
||||
* benefit from it ... one remote device may easily be NAKing while others
|
||||
* need to perform transfers in that same direction. The same thing could
|
||||
* be done in software though, assuming dma cooperates.)
|
||||
* benefit from it.)
|
||||
*
|
||||
* INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints.
|
||||
* So far that scheduling is both dumb and optimistic: the endpoint will be
|
||||
|
@ -201,8 +195,9 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
|
|||
len = urb->iso_frame_desc[0].length;
|
||||
break;
|
||||
default: /* bulk, interrupt */
|
||||
buf = urb->transfer_buffer;
|
||||
len = urb->transfer_buffer_length;
|
||||
/* actual_length may be nonzero on retry paths */
|
||||
buf = urb->transfer_buffer + urb->actual_length;
|
||||
len = urb->transfer_buffer_length - urb->actual_length;
|
||||
}
|
||||
|
||||
DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
|
||||
|
@ -395,7 +390,6 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
|
|||
* de-allocated if it's tracked and allocated;
|
||||
* and where we'd update the schedule tree...
|
||||
*/
|
||||
musb->periodic[ep->epnum] = NULL;
|
||||
kfree(qh);
|
||||
qh = NULL;
|
||||
break;
|
||||
|
@ -1045,7 +1039,8 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
|
|||
|
||||
/* NOTE: this code path would be a good place to PAUSE a
|
||||
* control transfer, if another one is queued, so that
|
||||
* ep0 is more likely to stay busy.
|
||||
* ep0 is more likely to stay busy. That's already done
|
||||
* for bulk RX transfers.
|
||||
*
|
||||
* if (qh->ring.next != &musb->control), then
|
||||
* we have a candidate... NAKing is *NOT* an error
|
||||
|
@ -1197,6 +1192,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
|
|||
/* NOTE: this code path would be a good place to PAUSE a
|
||||
* transfer, if there's some other (nonperiodic) tx urb
|
||||
* that could use this fifo. (dma complicates it...)
|
||||
* That's already done for bulk RX transfers.
|
||||
*
|
||||
* if (bulk && qh->ring.next != &musb->out_bulk), then
|
||||
* we have a candidate... NAKing is *NOT* an error
|
||||
|
@ -1358,6 +1354,50 @@ finish:
|
|||
|
||||
#endif
|
||||
|
||||
/* Schedule next QH from musb->in_bulk and move the current qh to
|
||||
* the end; avoids starvation for other endpoints.
|
||||
*/
|
||||
static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
|
||||
{
|
||||
struct dma_channel *dma;
|
||||
struct urb *urb;
|
||||
void __iomem *mbase = musb->mregs;
|
||||
void __iomem *epio = ep->regs;
|
||||
struct musb_qh *cur_qh, *next_qh;
|
||||
u16 rx_csr;
|
||||
|
||||
musb_ep_select(mbase, ep->epnum);
|
||||
dma = is_dma_capable() ? ep->rx_channel : NULL;
|
||||
|
||||
/* clear nak timeout bit */
|
||||
rx_csr = musb_readw(epio, MUSB_RXCSR);
|
||||
rx_csr |= MUSB_RXCSR_H_WZC_BITS;
|
||||
rx_csr &= ~MUSB_RXCSR_DATAERROR;
|
||||
musb_writew(epio, MUSB_RXCSR, rx_csr);
|
||||
|
||||
cur_qh = first_qh(&musb->in_bulk);
|
||||
if (cur_qh) {
|
||||
urb = next_urb(cur_qh);
|
||||
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
|
||||
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
|
||||
musb->dma_controller->channel_abort(dma);
|
||||
urb->actual_length += dma->actual_len;
|
||||
dma->actual_len = 0L;
|
||||
}
|
||||
musb_save_toggle(ep, 1, urb);
|
||||
|
||||
/* move cur_qh to end of queue */
|
||||
list_move_tail(&cur_qh->ring, &musb->in_bulk);
|
||||
|
||||
/* get the next qh from musb->in_bulk */
|
||||
next_qh = first_qh(&musb->in_bulk);
|
||||
|
||||
/* set rx_reinit and schedule the next qh */
|
||||
ep->rx_reinit = 1;
|
||||
musb_start_urb(musb, 1, next_qh);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
|
||||
* and high-bandwidth IN transfer cases.
|
||||
|
@ -1421,18 +1461,26 @@ void musb_host_rx(struct musb *musb, u8 epnum)
|
|||
} else if (rx_csr & MUSB_RXCSR_DATAERROR) {
|
||||
|
||||
if (USB_ENDPOINT_XFER_ISOC != qh->type) {
|
||||
/* NOTE this code path would be a good place to PAUSE a
|
||||
* transfer, if there's some other (nonperiodic) rx urb
|
||||
* that could use this fifo. (dma complicates it...)
|
||||
*
|
||||
* if (bulk && qh->ring.next != &musb->in_bulk), then
|
||||
* we have a candidate... NAKing is *NOT* an error
|
||||
*/
|
||||
DBG(6, "RX end %d NAK timeout\n", epnum);
|
||||
|
||||
/* NOTE: NAKing is *NOT* an error, so we want to
|
||||
* continue. Except ... if there's a request for
|
||||
* another QH, use that instead of starving it.
|
||||
*
|
||||
* Devices like Ethernet and serial adapters keep
|
||||
* reads posted at all times, which will starve
|
||||
* other devices without this logic.
|
||||
*/
|
||||
if (usb_pipebulk(urb->pipe)
|
||||
&& qh->mux == 1
|
||||
&& !list_is_singular(&musb->in_bulk)) {
|
||||
musb_bulk_rx_nak_timeout(musb, hw_ep);
|
||||
return;
|
||||
}
|
||||
musb_ep_select(mbase, epnum);
|
||||
musb_writew(epio, MUSB_RXCSR,
|
||||
MUSB_RXCSR_H_WZC_BITS
|
||||
| MUSB_RXCSR_H_REQPKT);
|
||||
rx_csr |= MUSB_RXCSR_H_WZC_BITS;
|
||||
rx_csr &= ~MUSB_RXCSR_DATAERROR;
|
||||
musb_writew(epio, MUSB_RXCSR, rx_csr);
|
||||
|
||||
goto finish;
|
||||
} else {
|
||||
|
@ -1711,31 +1759,27 @@ static int musb_schedule(
|
|||
|
||||
/* else, periodic transfers get muxed to other endpoints */
|
||||
|
||||
/* FIXME this doesn't consider direction, so it can only
|
||||
* work for one half of the endpoint hardware, and assumes
|
||||
* the previous cases handled all non-shared endpoints...
|
||||
*/
|
||||
|
||||
/* we know this qh hasn't been scheduled, so all we need to do
|
||||
/*
|
||||
* We know this qh hasn't been scheduled, so all we need to do
|
||||
* is choose which hardware endpoint to put it on ...
|
||||
*
|
||||
* REVISIT what we really want here is a regular schedule tree
|
||||
* like e.g. OHCI uses, but for now musb->periodic is just an
|
||||
* array of the _single_ logical endpoint associated with a
|
||||
* given physical one (identity mapping logical->physical).
|
||||
*
|
||||
* that simplistic approach makes TT scheduling a lot simpler;
|
||||
* there is none, and thus none of its complexity...
|
||||
* like e.g. OHCI uses.
|
||||
*/
|
||||
best_diff = 4096;
|
||||
best_end = -1;
|
||||
|
||||
for (epnum = 1; epnum < musb->nr_endpoints; epnum++) {
|
||||
for (epnum = 1, hw_ep = musb->endpoints + 1;
|
||||
epnum < musb->nr_endpoints;
|
||||
epnum++, hw_ep++) {
|
||||
int diff;
|
||||
|
||||
if (musb->periodic[epnum])
|
||||
if (is_in || hw_ep->is_shared_fifo) {
|
||||
if (hw_ep->in_qh != NULL)
|
||||
continue;
|
||||
} else if (hw_ep->out_qh != NULL)
|
||||
continue;
|
||||
hw_ep = &musb->endpoints[epnum];
|
||||
|
||||
if (hw_ep == musb->bulk_ep)
|
||||
continue;
|
||||
|
||||
|
@ -1756,6 +1800,17 @@ static int musb_schedule(
|
|||
head = &musb->in_bulk;
|
||||
else
|
||||
head = &musb->out_bulk;
|
||||
|
||||
/* Enable bulk RX NAK timeout scheme when bulk requests are
|
||||
* multiplexed. This scheme doen't work in high speed to full
|
||||
* speed scenario as NAK interrupts are not coming from a
|
||||
* full speed device connected to a high speed device.
|
||||
* NAK timeout interval is 8 (128 uframe or 16ms) for HS and
|
||||
* 4 (8 frame or 8ms) for FS device.
|
||||
*/
|
||||
if (is_in && qh->dev)
|
||||
qh->intv_reg =
|
||||
(USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
|
||||
goto success;
|
||||
} else if (best_end < 0) {
|
||||
return -ENOSPC;
|
||||
|
@ -1764,7 +1819,6 @@ static int musb_schedule(
|
|||
idle = 1;
|
||||
qh->mux = 0;
|
||||
hw_ep = musb->endpoints + best_end;
|
||||
musb->periodic[best_end] = qh;
|
||||
DBG(4, "qh %p periodic slot %d\n", qh, best_end);
|
||||
success:
|
||||
if (head) {
|
||||
|
@ -1888,13 +1942,11 @@ static int musb_urb_enqueue(
|
|||
*
|
||||
* The downside of disabling this is that transfer scheduling
|
||||
* gets VERY unfair for nonperiodic transfers; a misbehaving
|
||||
* peripheral could make that hurt. Or for reads, one that's
|
||||
* perfectly normal: network and other drivers keep reads
|
||||
* posted at all times, having one pending for a week should
|
||||
* be perfectly safe.
|
||||
* peripheral could make that hurt. That's perfectly normal
|
||||
* for reads from network or serial adapters ... so we have
|
||||
* partial NAKlimit support for bulk RX.
|
||||
*
|
||||
* The upside of disabling it is avoidng transfer scheduling
|
||||
* code to put this aside for while.
|
||||
* The upside of disabling it is simpler transfer scheduling.
|
||||
*/
|
||||
interval = 0;
|
||||
}
|
||||
|
|
|
@ -285,7 +285,7 @@ int musb_hub_control(
|
|||
desc->bDescLength = 9;
|
||||
desc->bDescriptorType = 0x29;
|
||||
desc->bNbrPorts = 1;
|
||||
desc->wHubCharacteristics = __constant_cpu_to_le16(
|
||||
desc->wHubCharacteristics = cpu_to_le16(
|
||||
0x0001 /* per-port power switching */
|
||||
| 0x0010 /* no overcurrent reporting */
|
||||
);
|
||||
|
|
|
@ -43,7 +43,7 @@ config ISP1301_OMAP
|
|||
|
||||
config TWL4030_USB
|
||||
tristate "TWL4030 USB Transceiver Driver"
|
||||
depends on TWL4030_CORE
|
||||
depends on TWL4030_CORE && REGULATOR_TWL4030
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
Enable this to support the USB OTG transceiver on TWL4030
|
||||
|
@ -51,4 +51,12 @@ config TWL4030_USB
|
|||
This transceiver supports high and full speed devices plus,
|
||||
in host mode, low speed.
|
||||
|
||||
config NOP_USB_XCEIV
|
||||
tristate "NOP USB Transceiver Driver"
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
this driver is to be used by all the usb transceiver which are either
|
||||
built-in with usb ip or which are autonomous and doesn't require any
|
||||
phy programming such as ISP1x04 etc.
|
||||
|
||||
endif # USB || OTG
|
||||
|
|
|
@ -9,6 +9,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o
|
|||
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
|
||||
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
|
||||
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
|
||||
obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
|
||||
|
||||
ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
|
||||
ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
|
@ -34,6 +35,7 @@ struct gpio_vbus_data {
|
|||
struct regulator *vbus_draw;
|
||||
int vbus_draw_enabled;
|
||||
unsigned mA;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,24 +78,26 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
|
|||
gpio_vbus->mA = mA;
|
||||
}
|
||||
|
||||
/* VBUS change IRQ handler */
|
||||
static irqreturn_t gpio_vbus_irq(int irq, void *data)
|
||||
static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
|
||||
{
|
||||
struct platform_device *pdev = data;
|
||||
struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
|
||||
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
|
||||
int gpio, vbus;
|
||||
int vbus;
|
||||
|
||||
vbus = gpio_get_value(pdata->gpio_vbus);
|
||||
if (pdata->gpio_vbus_inverted)
|
||||
vbus = !vbus;
|
||||
|
||||
dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
|
||||
vbus ? "supplied" : "inactive",
|
||||
gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
|
||||
return vbus;
|
||||
}
|
||||
|
||||
static void gpio_vbus_work(struct work_struct *work)
|
||||
{
|
||||
struct gpio_vbus_data *gpio_vbus =
|
||||
container_of(work, struct gpio_vbus_data, work);
|
||||
struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
|
||||
int gpio;
|
||||
|
||||
if (!gpio_vbus->otg.gadget)
|
||||
return IRQ_HANDLED;
|
||||
return;
|
||||
|
||||
/* Peripheral controllers which manage the pullup themselves won't have
|
||||
* gpio_pullup configured here. If it's configured here, we'll do what
|
||||
|
@ -101,7 +105,7 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data)
|
|||
* that may complicate usb_gadget_{,dis}connect() support.
|
||||
*/
|
||||
gpio = pdata->gpio_pullup;
|
||||
if (vbus) {
|
||||
if (is_vbus_powered(pdata)) {
|
||||
gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL;
|
||||
usb_gadget_vbus_connect(gpio_vbus->otg.gadget);
|
||||
|
||||
|
@ -121,6 +125,21 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data)
|
|||
usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget);
|
||||
gpio_vbus->otg.state = OTG_STATE_B_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* VBUS change IRQ handler */
|
||||
static irqreturn_t gpio_vbus_irq(int irq, void *data)
|
||||
{
|
||||
struct platform_device *pdev = data;
|
||||
struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
|
||||
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
|
||||
|
||||
dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
|
||||
is_vbus_powered(pdata) ? "supplied" : "inactive",
|
||||
gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
|
||||
|
||||
if (gpio_vbus->otg.gadget)
|
||||
schedule_work(&gpio_vbus->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -257,6 +276,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
|
|||
irq, err);
|
||||
goto err_irq;
|
||||
}
|
||||
INIT_WORK(&gpio_vbus->work, gpio_vbus_work);
|
||||
|
||||
/* only active when a gadget is registered */
|
||||
err = otg_set_transceiver(&gpio_vbus->otg);
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* drivers/usb/otg/nop-usb-xceiv.c
|
||||
*
|
||||
* NOP USB transceiver for all USB transceiver which are either built-in
|
||||
* into USB IP or which are mostly autonomous.
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Inc
|
||||
* Author: Ajay Kumar Gupta <ajay.gupta@ti.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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Current status:
|
||||
* this is to add "nop" transceiver for all those phy which is
|
||||
* autonomous such as isp1504 etc.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
struct nop_usb_xceiv {
|
||||
struct otg_transceiver otg;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static u64 nop_xceiv_dmamask = DMA_32BIT_MASK;
|
||||
|
||||
static struct platform_device nop_xceiv_device = {
|
||||
.name = "nop_usb_xceiv",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &nop_xceiv_dmamask,
|
||||
.coherent_dma_mask = DMA_32BIT_MASK,
|
||||
.platform_data = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
void usb_nop_xceiv_register(void)
|
||||
{
|
||||
if (platform_device_register(&nop_xceiv_device) < 0) {
|
||||
printk(KERN_ERR "Unable to register usb nop transceiver\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_nop_xceiv_unregister(void)
|
||||
{
|
||||
platform_device_unregister(&nop_xceiv_device);
|
||||
}
|
||||
|
||||
static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
|
||||
{
|
||||
return container_of(x, struct nop_usb_xceiv, otg);
|
||||
}
|
||||
|
||||
static int nop_set_suspend(struct otg_transceiver *x, int suspend)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nop_set_peripheral(struct otg_transceiver *x,
|
||||
struct usb_gadget *gadget)
|
||||
{
|
||||
struct nop_usb_xceiv *nop;
|
||||
|
||||
if (!x)
|
||||
return -ENODEV;
|
||||
|
||||
nop = xceiv_to_nop(x);
|
||||
|
||||
if (!gadget) {
|
||||
nop->otg.gadget = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
nop->otg.gadget = gadget;
|
||||
nop->otg.state = OTG_STATE_B_IDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nop_set_host(struct otg_transceiver *x, struct usb_bus *host)
|
||||
{
|
||||
struct nop_usb_xceiv *nop;
|
||||
|
||||
if (!x)
|
||||
return -ENODEV;
|
||||
|
||||
nop = xceiv_to_nop(x);
|
||||
|
||||
if (!host) {
|
||||
nop->otg.host = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
nop->otg.host = host;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nop_usb_xceiv *nop;
|
||||
int err;
|
||||
|
||||
nop = kzalloc(sizeof *nop, GFP_KERNEL);
|
||||
if (!nop)
|
||||
return -ENOMEM;
|
||||
|
||||
nop->dev = &pdev->dev;
|
||||
nop->otg.dev = nop->dev;
|
||||
nop->otg.label = "nop-xceiv";
|
||||
nop->otg.state = OTG_STATE_UNDEFINED;
|
||||
nop->otg.set_host = nop_set_host;
|
||||
nop->otg.set_peripheral = nop_set_peripheral;
|
||||
nop->otg.set_suspend = nop_set_suspend;
|
||||
|
||||
err = otg_set_transceiver(&nop->otg);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
|
||||
err);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, nop);
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
kfree(nop);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
|
||||
|
||||
otg_set_transceiver(NULL);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(nop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver nop_usb_xceiv_driver = {
|
||||
.probe = nop_usb_xceiv_probe,
|
||||
.remove = __devexit_p(nop_usb_xceiv_remove),
|
||||
.driver = {
|
||||
.name = "nop_usb_xceiv",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init nop_usb_xceiv_init(void)
|
||||
{
|
||||
return platform_driver_register(&nop_usb_xceiv_driver);
|
||||
}
|
||||
subsys_initcall(nop_usb_xceiv_init);
|
||||
|
||||
static void __exit nop_usb_xceiv_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&nop_usb_xceiv_driver);
|
||||
}
|
||||
module_exit(nop_usb_xceiv_exit);
|
||||
|
||||
MODULE_ALIAS("platform:nop_usb_xceiv");
|
||||
MODULE_AUTHOR("Texas Instruments Inc");
|
||||
MODULE_DESCRIPTION("NOP USB Transceiver driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -34,6 +34,8 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/i2c/twl4030.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
|
||||
/* Register defines */
|
||||
|
@ -246,6 +248,11 @@ struct twl4030_usb {
|
|||
struct otg_transceiver otg;
|
||||
struct device *dev;
|
||||
|
||||
/* TWL4030 internal USB regulator supplies */
|
||||
struct regulator *usb1v5;
|
||||
struct regulator *usb1v8;
|
||||
struct regulator *usb3v1;
|
||||
|
||||
/* for vbus reporting with irqs disabled */
|
||||
spinlock_t lock;
|
||||
|
||||
|
@ -434,6 +441,18 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
|
|||
|
||||
pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
|
||||
if (on) {
|
||||
regulator_enable(twl->usb3v1);
|
||||
regulator_enable(twl->usb1v8);
|
||||
/*
|
||||
* Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
|
||||
* in twl4030) resets the VUSB_DEDICATED2 register. This reset
|
||||
* enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to
|
||||
* SLEEP. We work around this by clearing the bit after usv3v1
|
||||
* is re-activated. This ensures that VUSB3V1 is really active.
|
||||
*/
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
|
||||
VUSB_DEDICATED2);
|
||||
regulator_enable(twl->usb1v5);
|
||||
pwr &= ~PHY_PWR_PHYPWD;
|
||||
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
|
||||
twl4030_usb_write(twl, PHY_CLK_CTRL,
|
||||
|
@ -443,6 +462,9 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
|
|||
} else {
|
||||
pwr |= PHY_PWR_PHYPWD;
|
||||
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
|
||||
regulator_disable(twl->usb1v5);
|
||||
regulator_disable(twl->usb1v8);
|
||||
regulator_disable(twl->usb3v1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,7 +490,7 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
|
|||
twl->asleep = 0;
|
||||
}
|
||||
|
||||
static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
|
||||
static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
|
||||
{
|
||||
/* Enable writing to power configuration registers */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
|
||||
|
@ -480,20 +502,45 @@ static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
|
|||
/* input to VUSB3V1 LDO is from VBAT, not VBUS */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
|
||||
|
||||
/* turn on 3.1V regulator */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
|
||||
/* Initialize 3.1V regulator */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
|
||||
|
||||
twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
|
||||
if (IS_ERR(twl->usb3v1))
|
||||
return -ENODEV;
|
||||
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
|
||||
|
||||
/* turn on 1.5V regulator */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
|
||||
/* Initialize 1.5V regulator */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
|
||||
|
||||
twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
|
||||
if (IS_ERR(twl->usb1v5))
|
||||
goto fail1;
|
||||
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
|
||||
|
||||
/* turn on 1.8V regulator */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
|
||||
/* Initialize 1.8V regulator */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
|
||||
|
||||
twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
|
||||
if (IS_ERR(twl->usb1v8))
|
||||
goto fail2;
|
||||
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
|
||||
|
||||
/* disable access to power configuration registers */
|
||||
twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
|
||||
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
regulator_put(twl->usb1v5);
|
||||
twl->usb1v5 = NULL;
|
||||
fail1:
|
||||
regulator_put(twl->usb3v1);
|
||||
twl->usb3v1 = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static ssize_t twl4030_usb_vbus_show(struct device *dev,
|
||||
|
@ -598,7 +645,7 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct twl4030_usb_data *pdata = pdev->dev.platform_data;
|
||||
struct twl4030_usb *twl;
|
||||
int status;
|
||||
int status, err;
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(&pdev->dev, "platform_data not available\n");
|
||||
|
@ -622,7 +669,12 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
|
|||
/* init spinlock for workqueue */
|
||||
spin_lock_init(&twl->lock);
|
||||
|
||||
twl4030_usb_ldo_init(twl);
|
||||
err = twl4030_usb_ldo_init(twl);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "ldo init failed\n");
|
||||
kfree(twl);
|
||||
return err;
|
||||
}
|
||||
otg_set_transceiver(&twl->otg);
|
||||
|
||||
platform_set_drvdata(pdev, twl);
|
||||
|
@ -688,6 +740,9 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
|
|||
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
|
||||
|
||||
twl4030_phy_power(twl, 0);
|
||||
regulator_put(twl->usb1v5);
|
||||
regulator_put(twl->usb1v8);
|
||||
regulator_put(twl->usb3v1);
|
||||
|
||||
kfree(twl);
|
||||
|
||||
|
|
|
@ -116,14 +116,14 @@ config USB_SERIAL_DIGI_ACCELEPORT
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called digi_acceleport.
|
||||
|
||||
config USB_SERIAL_CP2101
|
||||
tristate "USB CP2101 UART Bridge Controller"
|
||||
config USB_SERIAL_CP210X
|
||||
tristate "USB CP210x family of UART Bridge Controllers"
|
||||
help
|
||||
Say Y here if you want to use a CP2101/CP2102 based USB to RS232
|
||||
converter.
|
||||
Say Y here if you want to use a CP2101/CP2102/CP2103 based USB
|
||||
to RS232 converters.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cp2101.
|
||||
module will be called cp210x.
|
||||
|
||||
config USB_SERIAL_CYPRESS_M8
|
||||
tristate "USB Cypress M8 USB Serial Driver"
|
||||
|
@ -472,6 +472,15 @@ config USB_SERIAL_OTI6858
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called oti6858.
|
||||
|
||||
config USB_SERIAL_QUALCOMM
|
||||
tristate "USB Qualcomm Serial modem"
|
||||
help
|
||||
Say Y here if you have a Qualcomm USB modem device. These are
|
||||
usually wireless cellular modems.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called qcserial.
|
||||
|
||||
config USB_SERIAL_SPCP8X5
|
||||
tristate "USB SPCP8x5 USB To Serial Driver"
|
||||
help
|
||||
|
@ -515,6 +524,15 @@ config USB_SERIAL_SIERRAWIRELESS
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called sierra.
|
||||
|
||||
config USB_SERIAL_SYMBOL
|
||||
tristate "USB Symbol Barcode driver (serial mode)"
|
||||
help
|
||||
Say Y here if you want to use a Symbol USB Barcode device
|
||||
in serial emulation mode.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called symbolserial.
|
||||
|
||||
config USB_SERIAL_TI
|
||||
tristate "USB TI 3410/5052 Serial Driver"
|
||||
help
|
||||
|
|
|
@ -15,7 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
|
|||
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
|
||||
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
|
||||
obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
|
||||
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
|
||||
obj-$(CONFIG_USB_SERIAL_CP210X) += cp210x.o
|
||||
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
|
||||
obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
|
||||
obj-$(CONFIG_USB_SERIAL_DEBUG) += usb_debug.o
|
||||
|
@ -45,10 +45,12 @@ obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
|
|||
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
|
||||
obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o
|
||||
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
|
||||
obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o
|
||||
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
|
||||
obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
|
||||
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
|
||||
obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o
|
||||
obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o
|
||||
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
|
||||
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
|
||||
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
|
||||
* Copyright 2007, Werner Cornelius <werner@cornelius-consult.de>
|
||||
* Copyright 2009, Boris Hajduk <boris@hajduk.org>
|
||||
*
|
||||
* ch341.c implements a serial port driver for the Winchiphead CH341.
|
||||
*
|
||||
|
@ -21,9 +23,39 @@
|
|||
#include <linux/usb/serial.h>
|
||||
#include <linux/serial.h>
|
||||
|
||||
#define DEFAULT_BAUD_RATE 2400
|
||||
#define DEFAULT_BAUD_RATE 9600
|
||||
#define DEFAULT_TIMEOUT 1000
|
||||
|
||||
/* flags for IO-Bits */
|
||||
#define CH341_BIT_RTS (1 << 6)
|
||||
#define CH341_BIT_DTR (1 << 5)
|
||||
|
||||
/******************************/
|
||||
/* interrupt pipe definitions */
|
||||
/******************************/
|
||||
/* always 4 interrupt bytes */
|
||||
/* first irq byte normally 0x08 */
|
||||
/* second irq byte base 0x7d + below */
|
||||
/* third irq byte base 0x94 + below */
|
||||
/* fourth irq byte normally 0xee */
|
||||
|
||||
/* second interrupt byte */
|
||||
#define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */
|
||||
|
||||
/* status returned in third interrupt answer byte, inverted in data
|
||||
from irq */
|
||||
#define CH341_BIT_CTS 0x01
|
||||
#define CH341_BIT_DSR 0x02
|
||||
#define CH341_BIT_RI 0x04
|
||||
#define CH341_BIT_DCD 0x08
|
||||
#define CH341_BITS_MODEM_STAT 0x0f /* all bits */
|
||||
|
||||
/*******************************/
|
||||
/* baudrate calculation factor */
|
||||
/*******************************/
|
||||
#define CH341_BAUDBASE_FACTOR 1532620800
|
||||
#define CH341_BAUDBASE_DIVMAX 3
|
||||
|
||||
static int debug;
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
|
@ -34,9 +66,12 @@ static struct usb_device_id id_table [] = {
|
|||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
struct ch341_private {
|
||||
unsigned baud_rate;
|
||||
u8 dtr;
|
||||
u8 rts;
|
||||
spinlock_t lock; /* access lock */
|
||||
wait_queue_head_t delta_msr_wait; /* wait queue for modem status */
|
||||
unsigned baud_rate; /* set baud rate */
|
||||
u8 line_control; /* set line control value RTS/DTR */
|
||||
u8 line_status; /* active status of modem control inputs */
|
||||
u8 multi_status_change; /* status changed multiple since last call */
|
||||
};
|
||||
|
||||
static int ch341_control_out(struct usb_device *dev, u8 request,
|
||||
|
@ -72,37 +107,28 @@ static int ch341_set_baudrate(struct usb_device *dev,
|
|||
{
|
||||
short a, b;
|
||||
int r;
|
||||
unsigned long factor;
|
||||
short divisor;
|
||||
|
||||
dbg("ch341_set_baudrate(%d)", priv->baud_rate);
|
||||
switch (priv->baud_rate) {
|
||||
case 2400:
|
||||
a = 0xd901;
|
||||
b = 0x0038;
|
||||
break;
|
||||
case 4800:
|
||||
a = 0x6402;
|
||||
b = 0x001f;
|
||||
break;
|
||||
case 9600:
|
||||
a = 0xb202;
|
||||
b = 0x0013;
|
||||
break;
|
||||
case 19200:
|
||||
a = 0xd902;
|
||||
b = 0x000d;
|
||||
break;
|
||||
case 38400:
|
||||
a = 0x6403;
|
||||
b = 0x000a;
|
||||
break;
|
||||
case 115200:
|
||||
a = 0xcc03;
|
||||
b = 0x0008;
|
||||
break;
|
||||
default:
|
||||
|
||||
if (!priv->baud_rate)
|
||||
return -EINVAL;
|
||||
factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate);
|
||||
divisor = CH341_BAUDBASE_DIVMAX;
|
||||
|
||||
while ((factor > 0xfff0) && divisor) {
|
||||
factor >>= 3;
|
||||
divisor--;
|
||||
}
|
||||
|
||||
if (factor > 0xfff0)
|
||||
return -EINVAL;
|
||||
|
||||
factor = 0x10000 - factor;
|
||||
a = (factor & 0xff00) | divisor;
|
||||
b = factor & 0xff;
|
||||
|
||||
r = ch341_control_out(dev, 0x9a, 0x1312, a);
|
||||
if (!r)
|
||||
r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
|
||||
|
@ -110,19 +136,18 @@ static int ch341_set_baudrate(struct usb_device *dev,
|
|||
return r;
|
||||
}
|
||||
|
||||
static int ch341_set_handshake(struct usb_device *dev,
|
||||
struct ch341_private *priv)
|
||||
static int ch341_set_handshake(struct usb_device *dev, u8 control)
|
||||
{
|
||||
dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
|
||||
return ch341_control_out(dev, 0xa4,
|
||||
~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
|
||||
dbg("ch341_set_handshake(0x%02x)", control);
|
||||
return ch341_control_out(dev, 0xa4, ~control, 0);
|
||||
}
|
||||
|
||||
static int ch341_get_status(struct usb_device *dev)
|
||||
static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
|
||||
{
|
||||
char *buffer;
|
||||
int r;
|
||||
const unsigned size = 8;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("ch341_get_status()");
|
||||
|
||||
|
@ -134,10 +159,15 @@ static int ch341_get_status(struct usb_device *dev)
|
|||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* Not having the datasheet for the CH341, we ignore the bytes returned
|
||||
* from the device. Return error if the device did not respond in time.
|
||||
*/
|
||||
r = 0;
|
||||
/* setup the private status if available */
|
||||
if (r == 2) {
|
||||
r = 0;
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
|
||||
priv->multi_status_change = 0;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
} else
|
||||
r = -EPROTO;
|
||||
|
||||
out: kfree(buffer);
|
||||
return r;
|
||||
|
@ -180,7 +210,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
|
|||
goto out;
|
||||
|
||||
/* expect 0xff 0xee */
|
||||
r = ch341_get_status(dev);
|
||||
r = ch341_get_status(dev, priv);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -192,12 +222,12 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
|
|||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = ch341_set_handshake(dev, priv);
|
||||
r = ch341_set_handshake(dev, priv->line_control);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
/* expect 0x9f 0xee */
|
||||
r = ch341_get_status(dev);
|
||||
r = ch341_get_status(dev, priv);
|
||||
|
||||
out: kfree(buffer);
|
||||
return r;
|
||||
|
@ -216,9 +246,10 @@ static int ch341_attach(struct usb_serial *serial)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
init_waitqueue_head(&priv->delta_msr_wait);
|
||||
priv->baud_rate = DEFAULT_BAUD_RATE;
|
||||
priv->dtr = 1;
|
||||
priv->rts = 1;
|
||||
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
|
||||
|
||||
r = ch341_configure(serial->dev, priv);
|
||||
if (r < 0)
|
||||
|
@ -231,6 +262,35 @@ error: kfree(priv);
|
|||
return r;
|
||||
}
|
||||
|
||||
static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
struct file *filp)
|
||||
{
|
||||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
unsigned int c_cflag;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
/* shutdown our urbs */
|
||||
dbg("%s - shutting down urbs", __func__);
|
||||
usb_kill_urb(port->write_urb);
|
||||
usb_kill_urb(port->read_urb);
|
||||
usb_kill_urb(port->interrupt_in_urb);
|
||||
|
||||
if (tty) {
|
||||
c_cflag = tty->termios->c_cflag;
|
||||
if (c_cflag & HUPCL) {
|
||||
/* drop DTR and RTS */
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_control = 0;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
ch341_set_handshake(port->serial->dev, 0);
|
||||
}
|
||||
}
|
||||
wake_up_interruptible(&priv->delta_msr_wait);
|
||||
}
|
||||
|
||||
|
||||
/* open this device, set default parameters */
|
||||
static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
struct file *filp)
|
||||
|
@ -242,14 +302,13 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
dbg("ch341_open()");
|
||||
|
||||
priv->baud_rate = DEFAULT_BAUD_RATE;
|
||||
priv->dtr = 1;
|
||||
priv->rts = 1;
|
||||
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
|
||||
|
||||
r = ch341_configure(serial->dev, priv);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
r = ch341_set_handshake(serial->dev, priv);
|
||||
r = ch341_set_handshake(serial->dev, priv->line_control);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
|
@ -257,6 +316,16 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
if (r)
|
||||
goto out;
|
||||
|
||||
dbg("%s - submitting interrupt urb", __func__);
|
||||
port->interrupt_in_urb->dev = serial->dev;
|
||||
r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||||
if (r) {
|
||||
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
|
||||
" error %d\n", __func__, r);
|
||||
ch341_close(tty, port, NULL);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
r = usb_serial_generic_open(tty, port, filp);
|
||||
|
||||
out: return r;
|
||||
|
@ -270,46 +339,224 @@ static void ch341_set_termios(struct tty_struct *tty,
|
|||
{
|
||||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned baud_rate;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("ch341_set_termios()");
|
||||
|
||||
if (!tty || !tty->termios)
|
||||
return;
|
||||
|
||||
baud_rate = tty_get_baud_rate(tty);
|
||||
|
||||
switch (baud_rate) {
|
||||
case 2400:
|
||||
case 4800:
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 115200:
|
||||
priv->baud_rate = baud_rate;
|
||||
break;
|
||||
default:
|
||||
dbg("Rate %d not supported, using %d",
|
||||
baud_rate, DEFAULT_BAUD_RATE);
|
||||
priv->baud_rate = DEFAULT_BAUD_RATE;
|
||||
priv->baud_rate = baud_rate;
|
||||
|
||||
if (baud_rate) {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
ch341_set_baudrate(port->serial->dev, priv);
|
||||
} else {
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
ch341_set_baudrate(port->serial->dev, priv);
|
||||
ch341_set_handshake(port->serial->dev, priv->line_control);
|
||||
|
||||
/* Unimplemented:
|
||||
* (cflag & CSIZE) : data bits [5, 8]
|
||||
* (cflag & PARENB) : parity {NONE, EVEN, ODD}
|
||||
* (cflag & CSTOPB) : stop bits [1, 2]
|
||||
*/
|
||||
}
|
||||
|
||||
/* Copy back the old hardware settings */
|
||||
tty_termios_copy_hw(tty->termios, old_termios);
|
||||
/* And re-encode with the new baud */
|
||||
tty_encode_baud_rate(tty, baud_rate, baud_rate);
|
||||
static int ch341_tiocmset(struct tty_struct *tty, struct file *file,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
u8 control;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
if (set & TIOCM_RTS)
|
||||
priv->line_control |= CH341_BIT_RTS;
|
||||
if (set & TIOCM_DTR)
|
||||
priv->line_control |= CH341_BIT_DTR;
|
||||
if (clear & TIOCM_RTS)
|
||||
priv->line_control &= ~CH341_BIT_RTS;
|
||||
if (clear & TIOCM_DTR)
|
||||
priv->line_control &= ~CH341_BIT_DTR;
|
||||
control = priv->line_control;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return ch341_set_handshake(port->serial->dev, control);
|
||||
}
|
||||
|
||||
static void ch341_read_int_callback(struct urb *urb)
|
||||
{
|
||||
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
unsigned int actual_length = urb->actual_length;
|
||||
int status;
|
||||
|
||||
dbg("%s (%d)", __func__, port->number);
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d", __func__,
|
||||
urb->status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d", __func__,
|
||||
urb->status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
usb_serial_debug_data(debug, &port->dev, __func__,
|
||||
urb->actual_length, urb->transfer_buffer);
|
||||
|
||||
if (actual_length >= 4) {
|
||||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT;
|
||||
if ((data[1] & CH341_MULT_STAT))
|
||||
priv->multi_status_change = 1;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
wake_up_interruptible(&priv->delta_msr_wait);
|
||||
}
|
||||
|
||||
exit:
|
||||
status = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (status)
|
||||
dev_err(&urb->dev->dev,
|
||||
"%s - usb_submit_urb failed with result %d\n",
|
||||
__func__, status);
|
||||
}
|
||||
|
||||
static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
|
||||
{
|
||||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
u8 prevstatus;
|
||||
u8 status;
|
||||
u8 changed;
|
||||
u8 multi_change = 0;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
prevstatus = priv->line_status;
|
||||
priv->multi_status_change = 0;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
while (!multi_change) {
|
||||
interruptible_sleep_on(&priv->delta_msr_wait);
|
||||
/* see if a signal did it */
|
||||
if (signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
status = priv->line_status;
|
||||
multi_change = priv->multi_status_change;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
changed = prevstatus ^ status;
|
||||
|
||||
if (((arg & TIOCM_RNG) && (changed & CH341_BIT_RI)) ||
|
||||
((arg & TIOCM_DSR) && (changed & CH341_BIT_DSR)) ||
|
||||
((arg & TIOCM_CD) && (changed & CH341_BIT_DCD)) ||
|
||||
((arg & TIOCM_CTS) && (changed & CH341_BIT_CTS))) {
|
||||
return 0;
|
||||
}
|
||||
prevstatus = status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*static int ch341_ioctl(struct usb_serial_port *port, struct file *file,*/
|
||||
static int ch341_ioctl(struct tty_struct *tty, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCMIWAIT:
|
||||
dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
|
||||
return wait_modem_info(port, arg);
|
||||
|
||||
default:
|
||||
dbg("%s not supported = 0x%04x", __func__, cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static int ch341_tiocmget(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct ch341_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
u8 mcr;
|
||||
u8 status;
|
||||
unsigned int result;
|
||||
|
||||
dbg("%s (%d)", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
mcr = priv->line_control;
|
||||
status = priv->line_status;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
result = ((mcr & CH341_BIT_DTR) ? TIOCM_DTR : 0)
|
||||
| ((mcr & CH341_BIT_RTS) ? TIOCM_RTS : 0)
|
||||
| ((status & CH341_BIT_CTS) ? TIOCM_CTS : 0)
|
||||
| ((status & CH341_BIT_DSR) ? TIOCM_DSR : 0)
|
||||
| ((status & CH341_BIT_RI) ? TIOCM_RI : 0)
|
||||
| ((status & CH341_BIT_DCD) ? TIOCM_CD : 0);
|
||||
|
||||
dbg("%s - result = %x", __func__, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int ch341_reset_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct usb_serial *serial = NULL;
|
||||
struct ch341_private *priv;
|
||||
|
||||
serial = usb_get_intfdata(intf);
|
||||
priv = usb_get_serial_port_data(serial->port[0]);
|
||||
|
||||
/*reconfigure ch341 serial port after bus-reset*/
|
||||
ch341_configure(dev, priv);
|
||||
|
||||
usb_serial_resume(intf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_driver ch341_driver = {
|
||||
.name = "ch341",
|
||||
.probe = usb_serial_probe,
|
||||
.disconnect = usb_serial_disconnect,
|
||||
.suspend = usb_serial_suspend,
|
||||
.resume = usb_serial_resume,
|
||||
.reset_resume = ch341_reset_resume,
|
||||
.id_table = id_table,
|
||||
.no_dynamic_id = 1,
|
||||
.supports_autosuspend = 1,
|
||||
};
|
||||
|
||||
static struct usb_serial_driver ch341_device = {
|
||||
|
@ -317,12 +564,17 @@ static struct usb_serial_driver ch341_device = {
|
|||
.owner = THIS_MODULE,
|
||||
.name = "ch341-uart",
|
||||
},
|
||||
.id_table = id_table,
|
||||
.usb_driver = &ch341_driver,
|
||||
.num_ports = 1,
|
||||
.open = ch341_open,
|
||||
.set_termios = ch341_set_termios,
|
||||
.attach = ch341_attach,
|
||||
.id_table = id_table,
|
||||
.usb_driver = &ch341_driver,
|
||||
.num_ports = 1,
|
||||
.open = ch341_open,
|
||||
.close = ch341_close,
|
||||
.ioctl = ch341_ioctl,
|
||||
.set_termios = ch341_set_termios,
|
||||
.tiocmget = ch341_tiocmget,
|
||||
.tiocmset = ch341_tiocmset,
|
||||
.read_int_callback = ch341_read_int_callback,
|
||||
.attach = ch341_attach,
|
||||
};
|
||||
|
||||
static int __init ch341_init(void)
|
||||
|
|
|
@ -11,10 +11,6 @@
|
|||
* thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
|
||||
* control thanks to Munir Nassar nassarmu@real-time.com
|
||||
*
|
||||
* Outstanding Issues:
|
||||
* Buffers are not flushed when the port is opened.
|
||||
* Multiple calls to write() may fail with "Resource temporarily unavailable"
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -31,7 +27,7 @@
|
|||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.07"
|
||||
#define DRIVER_VERSION "v0.08"
|
||||
#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
|
||||
|
||||
/*
|
||||
|
@ -42,17 +38,21 @@ static int cp2101_open(struct tty_struct *, struct usb_serial_port *,
|
|||
static void cp2101_cleanup(struct usb_serial_port *);
|
||||
static void cp2101_close(struct tty_struct *, struct usb_serial_port *,
|
||||
struct file*);
|
||||
static void cp2101_get_termios(struct tty_struct *);
|
||||
static void cp2101_get_termios(struct tty_struct *,
|
||||
struct usb_serial_port *port);
|
||||
static void cp2101_get_termios_port(struct usb_serial_port *port,
|
||||
unsigned int *cflagp, unsigned int *baudp);
|
||||
static void cp2101_set_termios(struct tty_struct *, struct usb_serial_port *,
|
||||
struct ktermios*);
|
||||
static int cp2101_tiocmget(struct tty_struct *, struct file *);
|
||||
static int cp2101_tiocmset(struct tty_struct *, struct file *,
|
||||
unsigned int, unsigned int);
|
||||
static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *,
|
||||
unsigned int, unsigned int);
|
||||
static void cp2101_break_ctl(struct tty_struct *, int);
|
||||
static int cp2101_startup(struct usb_serial *);
|
||||
static void cp2101_shutdown(struct usb_serial *);
|
||||
|
||||
|
||||
static int debug;
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
|
@ -91,6 +91,7 @@ static struct usb_device_id id_table [] = {
|
|||
{ USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
|
||||
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
|
||||
{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
|
||||
{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
|
||||
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
|
||||
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
|
||||
{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
|
||||
|
@ -225,7 +226,7 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request,
|
|||
kfree(buf);
|
||||
|
||||
if (result != size) {
|
||||
dev_err(&port->dev, "%s - Unable to send config request, "
|
||||
dbg("%s - Unable to send config request, "
|
||||
"request=0x%x size=%d result=%d\n",
|
||||
__func__, request, size, result);
|
||||
return -EPROTO;
|
||||
|
@ -276,7 +277,7 @@ static int cp2101_set_config(struct usb_serial_port *port, u8 request,
|
|||
kfree(buf);
|
||||
|
||||
if ((size > 2 && result != size) || result < 0) {
|
||||
dev_err(&port->dev, "%s - Unable to send request, "
|
||||
dbg("%s - Unable to send request, "
|
||||
"request=0x%x size=%d result=%d\n",
|
||||
__func__, request, size, result);
|
||||
return -EPROTO;
|
||||
|
@ -301,6 +302,47 @@ static inline int cp2101_set_config_single(struct usb_serial_port *port,
|
|||
return cp2101_set_config(port, request, &data, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* cp2101_quantise_baudrate
|
||||
* Quantises the baud rate as per AN205 Table 1
|
||||
*/
|
||||
static unsigned int cp2101_quantise_baudrate(unsigned int baud) {
|
||||
if (baud <= 56) baud = 0;
|
||||
else if (baud <= 300) baud = 300;
|
||||
else if (baud <= 600) baud = 600;
|
||||
else if (baud <= 1200) baud = 1200;
|
||||
else if (baud <= 1800) baud = 1800;
|
||||
else if (baud <= 2400) baud = 2400;
|
||||
else if (baud <= 4000) baud = 4000;
|
||||
else if (baud <= 4803) baud = 4800;
|
||||
else if (baud <= 7207) baud = 7200;
|
||||
else if (baud <= 9612) baud = 9600;
|
||||
else if (baud <= 14428) baud = 14400;
|
||||
else if (baud <= 16062) baud = 16000;
|
||||
else if (baud <= 19250) baud = 19200;
|
||||
else if (baud <= 28912) baud = 28800;
|
||||
else if (baud <= 38601) baud = 38400;
|
||||
else if (baud <= 51558) baud = 51200;
|
||||
else if (baud <= 56280) baud = 56000;
|
||||
else if (baud <= 58053) baud = 57600;
|
||||
else if (baud <= 64111) baud = 64000;
|
||||
else if (baud <= 77608) baud = 76800;
|
||||
else if (baud <= 117028) baud = 115200;
|
||||
else if (baud <= 129347) baud = 128000;
|
||||
else if (baud <= 156868) baud = 153600;
|
||||
else if (baud <= 237832) baud = 230400;
|
||||
else if (baud <= 254234) baud = 250000;
|
||||
else if (baud <= 273066) baud = 256000;
|
||||
else if (baud <= 491520) baud = 460800;
|
||||
else if (baud <= 567138) baud = 500000;
|
||||
else if (baud <= 670254) baud = 576000;
|
||||
else if (baud <= 1053257) baud = 921600;
|
||||
else if (baud <= 1474560) baud = 1228800;
|
||||
else if (baud <= 2457600) baud = 1843200;
|
||||
else baud = 3686400;
|
||||
return baud;
|
||||
}
|
||||
|
||||
static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
struct file *filp)
|
||||
{
|
||||
|
@ -331,10 +373,12 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
}
|
||||
|
||||
/* Configure the termios structure */
|
||||
cp2101_get_termios(tty);
|
||||
cp2101_get_termios(tty, port);
|
||||
|
||||
/* Set the DTR and RTS pins low */
|
||||
cp2101_tiocmset(tty, NULL, TIOCM_DTR | TIOCM_RTS, 0);
|
||||
cp2101_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
|
||||
: port,
|
||||
NULL, TIOCM_DTR | TIOCM_RTS, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -376,9 +420,31 @@ static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
* from the device, corrects any unsupported values, and configures the
|
||||
* termios structure to reflect the state of the device
|
||||
*/
|
||||
static void cp2101_get_termios (struct tty_struct *tty)
|
||||
static void cp2101_get_termios(struct tty_struct *tty,
|
||||
struct usb_serial_port *port)
|
||||
{
|
||||
unsigned int baud;
|
||||
|
||||
if (tty) {
|
||||
cp2101_get_termios_port(tty->driver_data,
|
||||
&tty->termios->c_cflag, &baud);
|
||||
tty_encode_baud_rate(tty, baud, baud);
|
||||
}
|
||||
|
||||
else {
|
||||
unsigned int cflag;
|
||||
cflag = 0;
|
||||
cp2101_get_termios_port(port, &cflag, &baud);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cp2101_get_termios_port
|
||||
* This is the heart of cp2101_get_termios which always uses a &usb_serial_port.
|
||||
*/
|
||||
static void cp2101_get_termios_port(struct usb_serial_port *port,
|
||||
unsigned int *cflagp, unsigned int *baudp)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
unsigned int cflag, modem_ctl[4];
|
||||
unsigned int baud;
|
||||
unsigned int bits;
|
||||
|
@ -388,12 +454,12 @@ static void cp2101_get_termios (struct tty_struct *tty)
|
|||
cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
|
||||
/* Convert to baudrate */
|
||||
if (baud)
|
||||
baud = BAUD_RATE_GEN_FREQ / baud;
|
||||
baud = cp2101_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
|
||||
|
||||
dbg("%s - baud rate = %d", __func__, baud);
|
||||
*baudp = baud;
|
||||
|
||||
tty_encode_baud_rate(tty, baud, baud);
|
||||
cflag = tty->termios->c_cflag;
|
||||
cflag = *cflagp;
|
||||
|
||||
cp2101_get_config(port, CP2101_BITS, &bits, 2);
|
||||
cflag &= ~CSIZE;
|
||||
|
@ -499,7 +565,7 @@ static void cp2101_get_termios (struct tty_struct *tty)
|
|||
cflag &= ~CRTSCTS;
|
||||
}
|
||||
|
||||
tty->termios->c_cflag = cflag;
|
||||
*cflagp = cflag;
|
||||
}
|
||||
|
||||
static void cp2101_set_termios(struct tty_struct *tty,
|
||||
|
@ -517,46 +583,16 @@ static void cp2101_set_termios(struct tty_struct *tty,
|
|||
tty->termios->c_cflag &= ~CMSPAR;
|
||||
cflag = tty->termios->c_cflag;
|
||||
old_cflag = old_termios->c_cflag;
|
||||
baud = tty_get_baud_rate(tty);
|
||||
baud = cp2101_quantise_baudrate(tty_get_baud_rate(tty));
|
||||
|
||||
/* If the baud rate is to be updated*/
|
||||
if (baud != tty_termios_baud_rate(old_termios)) {
|
||||
switch (baud) {
|
||||
case 0:
|
||||
case 600:
|
||||
case 1200:
|
||||
case 1800:
|
||||
case 2400:
|
||||
case 4800:
|
||||
case 7200:
|
||||
case 9600:
|
||||
case 14400:
|
||||
case 19200:
|
||||
case 28800:
|
||||
case 38400:
|
||||
case 55854:
|
||||
case 57600:
|
||||
case 115200:
|
||||
case 127117:
|
||||
case 230400:
|
||||
case 460800:
|
||||
case 921600:
|
||||
case 3686400:
|
||||
break;
|
||||
default:
|
||||
baud = 9600;
|
||||
break;
|
||||
}
|
||||
|
||||
if (baud) {
|
||||
dbg("%s - Setting baud rate to %d baud", __func__,
|
||||
baud);
|
||||
if (cp2101_set_config_single(port, CP2101_BAUDRATE,
|
||||
(BAUD_RATE_GEN_FREQ / baud))) {
|
||||
dev_err(&port->dev, "Baud rate requested not "
|
||||
"supported by device\n");
|
||||
baud = tty_termios_baud_rate(old_termios);
|
||||
}
|
||||
if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
|
||||
dbg("%s - Setting baud rate to %d baud", __func__,
|
||||
baud);
|
||||
if (cp2101_set_config_single(port, CP2101_BAUDRATE,
|
||||
((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
|
||||
dbg("Baud rate requested not supported by device\n");
|
||||
baud = tty_termios_baud_rate(old_termios);
|
||||
}
|
||||
}
|
||||
/* Report back the resulting baud rate */
|
||||
|
@ -588,14 +624,14 @@ static void cp2101_set_termios(struct tty_struct *tty,
|
|||
dbg("%s - data bits = 9", __func__);
|
||||
break;*/
|
||||
default:
|
||||
dev_err(&port->dev, "cp2101 driver does not "
|
||||
dbg("cp2101 driver does not "
|
||||
"support the number of bits requested,"
|
||||
" using 8 bit mode\n");
|
||||
bits |= BITS_DATA_8;
|
||||
break;
|
||||
}
|
||||
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
|
||||
dev_err(&port->dev, "Number of data bits requested "
|
||||
dbg("Number of data bits requested "
|
||||
"not supported by device\n");
|
||||
}
|
||||
|
||||
|
@ -612,7 +648,7 @@ static void cp2101_set_termios(struct tty_struct *tty,
|
|||
}
|
||||
}
|
||||
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
|
||||
dev_err(&port->dev, "Parity mode not supported "
|
||||
dbg("Parity mode not supported "
|
||||
"by device\n");
|
||||
}
|
||||
|
||||
|
@ -627,7 +663,7 @@ static void cp2101_set_termios(struct tty_struct *tty,
|
|||
dbg("%s - stop bits = 1", __func__);
|
||||
}
|
||||
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
|
||||
dev_err(&port->dev, "Number of stop bits requested "
|
||||
dbg("Number of stop bits requested "
|
||||
"not supported by device\n");
|
||||
}
|
||||
|
||||
|
@ -661,6 +697,12 @@ static int cp2101_tiocmset (struct tty_struct *tty, struct file *file,
|
|||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
return cp2101_tiocmset_port(port, file, set, clear);
|
||||
}
|
||||
|
||||
static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
unsigned int control = 0;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
@ -685,7 +727,6 @@ static int cp2101_tiocmset (struct tty_struct *tty, struct file *file,
|
|||
dbg("%s - control = 0x%.4x", __func__, control);
|
||||
|
||||
return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
|
||||
|
||||
}
|
||||
|
||||
static int cp2101_tiocmget (struct tty_struct *tty, struct file *file)
|
|
@ -1938,18 +1938,16 @@ static void ftdi_process_read(struct work_struct *work)
|
|||
/* Compare new line status to the old one, signal if different/
|
||||
N.B. packet may be processed more than once, but differences
|
||||
are only processed once. */
|
||||
if (priv != NULL) {
|
||||
char new_status = data[packet_offset + 0] &
|
||||
FTDI_STATUS_B0_MASK;
|
||||
if (new_status != priv->prev_status) {
|
||||
priv->diff_status |=
|
||||
new_status ^ priv->prev_status;
|
||||
wake_up_interruptible(&priv->delta_msr_wait);
|
||||
priv->prev_status = new_status;
|
||||
}
|
||||
char new_status = data[packet_offset + 0] &
|
||||
FTDI_STATUS_B0_MASK;
|
||||
if (new_status != priv->prev_status) {
|
||||
priv->diff_status |=
|
||||
new_status ^ priv->prev_status;
|
||||
wake_up_interruptible(&priv->delta_msr_wait);
|
||||
priv->prev_status = new_status;
|
||||
}
|
||||
|
||||
length = min(PKTSZ, urb->actual_length-packet_offset)-2;
|
||||
length = min_t(u32, PKTSZ, urb->actual_length-packet_offset)-2;
|
||||
if (length < 0) {
|
||||
dev_err(&port->dev, "%s - bad packet length: %d\n",
|
||||
__func__, length+2);
|
||||
|
@ -2294,11 +2292,8 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
|
|||
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
|
||||
0, 0,
|
||||
buf, 1, WDR_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dbg("%s Could not get modem status of device - err: %d", __func__,
|
||||
ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case FT8U232AM:
|
||||
case FT232BM:
|
||||
|
@ -2313,15 +2308,11 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
|
|||
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
|
||||
0, priv->interface,
|
||||
buf, 2, WDR_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dbg("%s Could not get modem status of device - err: %d", __func__,
|
||||
ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
|
||||
|
|
|
@ -177,14 +177,6 @@ int usb_serial_generic_resume(struct usb_serial *serial)
|
|||
struct usb_serial_port *port;
|
||||
int i, c = 0, r;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* If this is an autoresume, don't submit URBs.
|
||||
* They will be submitted in the open function instead.
|
||||
*/
|
||||
if (serial->dev->auto_pm)
|
||||
return 0;
|
||||
#endif
|
||||
for (i = 0; i < serial->num_ports; i++) {
|
||||
port = serial->port[i];
|
||||
if (port->port.count && port->read_urb) {
|
||||
|
@ -196,6 +188,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
|
|||
|
||||
return c ? -EIO : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
|
||||
|
||||
void usb_serial_generic_close(struct tty_struct *tty,
|
||||
struct usb_serial_port *port, struct file *filp)
|
||||
|
|
|
@ -78,6 +78,7 @@ static int ipaq_open(struct tty_struct *tty,
|
|||
struct usb_serial_port *port, struct file *filp);
|
||||
static void ipaq_close(struct tty_struct *tty,
|
||||
struct usb_serial_port *port, struct file *filp);
|
||||
static int ipaq_calc_num_ports(struct usb_serial *serial);
|
||||
static int ipaq_startup(struct usb_serial *serial);
|
||||
static void ipaq_shutdown(struct usb_serial *serial);
|
||||
static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
|
@ -572,15 +573,10 @@ static struct usb_serial_driver ipaq_device = {
|
|||
.description = "PocketPC PDA",
|
||||
.usb_driver = &ipaq_driver,
|
||||
.id_table = ipaq_id_table,
|
||||
/*
|
||||
* some devices have an extra endpoint, which
|
||||
* must be ignored as it would make the core
|
||||
* create a second port which oopses when used
|
||||
*/
|
||||
.num_ports = 1,
|
||||
.open = ipaq_open,
|
||||
.close = ipaq_close,
|
||||
.attach = ipaq_startup,
|
||||
.calc_num_ports = ipaq_calc_num_ports,
|
||||
.shutdown = ipaq_shutdown,
|
||||
.write = ipaq_write,
|
||||
.write_room = ipaq_write_room,
|
||||
|
@ -956,14 +952,49 @@ static void ipaq_destroy_lists(struct usb_serial_port *port)
|
|||
}
|
||||
|
||||
|
||||
static int ipaq_calc_num_ports(struct usb_serial *serial)
|
||||
{
|
||||
/*
|
||||
* some devices have 3 endpoints, the 3rd of which
|
||||
* must be ignored as it would make the core
|
||||
* create a second port which oopses when used
|
||||
*/
|
||||
int ipaq_num_ports = 1;
|
||||
|
||||
dbg("%s - numberofendpoints: %d", __FUNCTION__,
|
||||
(int)serial->interface->cur_altsetting->desc.bNumEndpoints);
|
||||
|
||||
/*
|
||||
* a few devices have 4 endpoints, seemingly Yakuma devices,
|
||||
* and we need the second pair, so let them have 2 ports
|
||||
*
|
||||
* TODO: can we drop port 1 ?
|
||||
*/
|
||||
if (serial->interface->cur_altsetting->desc.bNumEndpoints > 3) {
|
||||
ipaq_num_ports = 2;
|
||||
}
|
||||
|
||||
return ipaq_num_ports;
|
||||
}
|
||||
|
||||
|
||||
static int ipaq_startup(struct usb_serial *serial)
|
||||
{
|
||||
dbg("%s", __func__);
|
||||
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
|
||||
/*
|
||||
* FIXME: HP iPaq rx3715, possibly others, have 1 config that
|
||||
* is labeled as 2
|
||||
*/
|
||||
|
||||
dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
|
||||
serial->dev->actconfig->desc.bConfigurationValue);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dbg("%s - iPAQ module configured for %d ports",
|
||||
__FUNCTION__, serial->num_ports);
|
||||
|
||||
return usb_reset_configuration(serial->dev);
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче