Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (34 commits) USB Storage: remove duplicate Nokia entry in unusual_devs.h [PATCH] bluetooth: add support for another Kensington dongle [PATCH] usb serial: add support for Novatel S720/U720 CDMA/EV-DO modems [PATCH] USB: Nokia E70 is an unusual device USB: fix to usbfs_snoop logging of user defined control urbs USB: at91_udc: Additional checks USB: at91_udc: Cleanup variables after failure in usb_gadget_register_driver() USB: at91_udc: allow drivers that support high speed USB: u132-hcd/ftdi-elan: add support for Option GT 3G Quad card USB: at91_udc, misc fixes USB: at91 udc, support at91sam926x addresses USB: OHCI support for PNX8550 USB: ohci handles hardware faults during root port resets USB: ohci at91 warning fix USB: ohci whitespace/comment fixups USB: MAINTAINERS update, EHCI and OHCI USB: gadget driver unbind() is optional; section fixes; misc UHCI: module parameter to ignore overcurrent changes USB: Nokia E70 is an unusual device USB AUERSWALD: replace kmalloc+memset with kzalloc ...
This commit is contained in:
commit
fb34d203d0
@ -1714,6 +1714,14 @@ and is between 256 and 4096 characters. It is defined in the file
|
||||
uart6850= [HW,OSS]
|
||||
Format: <io>,<irq>
|
||||
|
||||
uhci-hcd.ignore_oc=
|
||||
[USB] Ignore overcurrent events (default N).
|
||||
Some badly-designed motherboards generate lots of
|
||||
bogus events, for ports that aren't wired to
|
||||
anything. Set this parameter to avoid log spamming.
|
||||
Note that genuine overcurrent events won't be
|
||||
reported either.
|
||||
|
||||
usbhid.mousepoll=
|
||||
[USBHID] The interval which mice are to be polled at.
|
||||
|
||||
|
@ -3130,7 +3130,7 @@ USB EHCI DRIVER
|
||||
P: David Brownell
|
||||
M: dbrownell@users.sourceforge.net
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
S: Maintained
|
||||
S: Odd Fixes
|
||||
|
||||
USB ET61X[12]51 DRIVER
|
||||
P: Luca Risolia
|
||||
@ -3183,11 +3183,11 @@ S: Maintained
|
||||
W: http://www.one-eyed-alien.net/~mdharm/linux-usb/
|
||||
|
||||
USB OHCI DRIVER
|
||||
P: Roman Weissgaerber
|
||||
M: weissg@vienna.at
|
||||
P: David Brownell
|
||||
M: dbrownell@users.sourceforge.net
|
||||
L: linux-usb-users@lists.sourceforge.net
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
S: Maintained
|
||||
S: Odd Fixes
|
||||
|
||||
USB OPTION-CARD DRIVER
|
||||
P: Matthias Urlichs
|
||||
|
@ -126,6 +126,7 @@ static struct usb_device_id blacklist_ids[] = {
|
||||
|
||||
/* Kensington Bluetooth USB adapter */
|
||||
{ USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET },
|
||||
{ USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_WRONG_SCO_MTU },
|
||||
|
||||
/* ISSC Bluetooth Adapter v3.1 */
|
||||
{ USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
|
||||
|
@ -130,7 +130,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
|
||||
|
||||
struct usblp {
|
||||
struct usb_device *dev; /* USB device */
|
||||
struct semaphore sem; /* locks this struct, especially "dev" */
|
||||
struct mutex mut; /* locks this struct, especially "dev" */
|
||||
char *writebuf; /* write transfer_buffer */
|
||||
char *readbuf; /* read transfer_buffer */
|
||||
char *statusbuf; /* status transfer_buffer */
|
||||
@ -465,7 +465,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
int twoints[2];
|
||||
int retval = 0;
|
||||
|
||||
down (&usblp->sem);
|
||||
mutex_lock (&usblp->mut);
|
||||
if (!usblp->present) {
|
||||
retval = -ENODEV;
|
||||
goto done;
|
||||
@ -644,14 +644,14 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
|
||||
done:
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usblp *usblp = file->private_data;
|
||||
int timeout, rv, err = 0, transfer_length = 0;
|
||||
int timeout, intr, rv, err = 0, transfer_length = 0;
|
||||
size_t writecount = 0;
|
||||
|
||||
while (writecount < count) {
|
||||
@ -668,14 +668,16 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
|
||||
if (rv < 0)
|
||||
return writecount ? writecount : -EINTR;
|
||||
}
|
||||
down (&usblp->sem);
|
||||
intr = mutex_lock_interruptible (&usblp->mut);
|
||||
if (intr)
|
||||
return writecount ? writecount : -EINTR;
|
||||
if (!usblp->present) {
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (usblp->sleeping) {
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
return writecount ? writecount : -ENODEV;
|
||||
}
|
||||
|
||||
@ -687,10 +689,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
|
||||
err = usblp->writeurb->status;
|
||||
} else
|
||||
err = usblp_check_status(usblp, err);
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
|
||||
/* if the fault was due to disconnect, let khubd's
|
||||
* call to usblp_disconnect() grab usblp->sem ...
|
||||
* call to usblp_disconnect() grab usblp->mut ...
|
||||
*/
|
||||
schedule ();
|
||||
continue;
|
||||
@ -702,7 +704,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
|
||||
*/
|
||||
writecount += transfer_length;
|
||||
if (writecount == count) {
|
||||
up(&usblp->sem);
|
||||
mutex_unlock(&usblp->mut);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -714,7 +716,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
|
||||
|
||||
if (copy_from_user(usblp->writeurb->transfer_buffer,
|
||||
buffer + writecount, transfer_length)) {
|
||||
up(&usblp->sem);
|
||||
mutex_unlock(&usblp->mut);
|
||||
return writecount ? writecount : -EFAULT;
|
||||
}
|
||||
|
||||
@ -727,10 +729,10 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
|
||||
count = -EIO;
|
||||
else
|
||||
count = writecount ? writecount : -ENOMEM;
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
break;
|
||||
}
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
}
|
||||
|
||||
return count;
|
||||
@ -739,12 +741,14 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
|
||||
static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usblp *usblp = file->private_data;
|
||||
int rv;
|
||||
int rv, intr;
|
||||
|
||||
if (!usblp->bidir)
|
||||
return -EINVAL;
|
||||
|
||||
down (&usblp->sem);
|
||||
intr = mutex_lock_interruptible (&usblp->mut);
|
||||
if (intr)
|
||||
return -EINTR;
|
||||
if (!usblp->present) {
|
||||
count = -ENODEV;
|
||||
goto done;
|
||||
@ -757,9 +761,9 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
|
||||
count = -EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
up(&usblp->sem);
|
||||
mutex_unlock(&usblp->mut);
|
||||
rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
|
||||
down(&usblp->sem);
|
||||
mutex_lock(&usblp->mut);
|
||||
if (rv < 0) {
|
||||
count = -EINTR;
|
||||
goto done;
|
||||
@ -807,7 +811,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
|
||||
}
|
||||
|
||||
done:
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -886,7 +890,7 @@ static int usblp_probe(struct usb_interface *intf,
|
||||
goto abort;
|
||||
}
|
||||
usblp->dev = dev;
|
||||
init_MUTEX (&usblp->sem);
|
||||
mutex_init (&usblp->mut);
|
||||
init_waitqueue_head(&usblp->wait);
|
||||
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
|
||||
usblp->intf = intf;
|
||||
@ -1178,7 +1182,7 @@ static void usblp_disconnect(struct usb_interface *intf)
|
||||
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
|
||||
|
||||
mutex_lock (&usblp_mutex);
|
||||
down (&usblp->sem);
|
||||
mutex_lock (&usblp->mut);
|
||||
usblp->present = 0;
|
||||
usb_set_intfdata (intf, NULL);
|
||||
|
||||
@ -1187,7 +1191,7 @@ static void usblp_disconnect(struct usb_interface *intf)
|
||||
usblp->writebuf, usblp->writeurb->transfer_dma);
|
||||
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
|
||||
usblp->readbuf, usblp->readurb->transfer_dma);
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
|
||||
if (!usblp->used)
|
||||
usblp_cleanup (usblp);
|
||||
@ -1200,11 +1204,11 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
|
||||
|
||||
/* this races against normal access and open */
|
||||
mutex_lock (&usblp_mutex);
|
||||
down (&usblp->sem);
|
||||
mutex_lock (&usblp->mut);
|
||||
/* we take no more IO */
|
||||
usblp->sleeping = 1;
|
||||
usblp_unlink_urbs(usblp);
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
mutex_unlock (&usblp_mutex);
|
||||
|
||||
return 0;
|
||||
@ -1216,12 +1220,12 @@ static int usblp_resume (struct usb_interface *intf)
|
||||
int r;
|
||||
|
||||
mutex_lock (&usblp_mutex);
|
||||
down (&usblp->sem);
|
||||
mutex_lock (&usblp->mut);
|
||||
|
||||
usblp->sleeping = 0;
|
||||
r = handle_bidir (usblp);
|
||||
|
||||
up (&usblp->sem);
|
||||
mutex_unlock (&usblp->mut);
|
||||
mutex_unlock (&usblp_mutex);
|
||||
|
||||
return r;
|
||||
|
@ -962,7 +962,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
kfree(dr);
|
||||
return -EFAULT;
|
||||
}
|
||||
snoop(&ps->dev->dev, "control urb\n");
|
||||
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
|
||||
"bRrequestType=%02x wValue=%04x "
|
||||
"wIndex=%04x wLength=%04x\n",
|
||||
dr->bRequest, dr->bRequestType, dr->wValue,
|
||||
dr->wIndex, dr->wLength);
|
||||
break;
|
||||
|
||||
case USBDEVFS_URB_TYPE_BULK:
|
||||
|
@ -43,14 +43,16 @@
|
||||
#include <linux/usb_gadget.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/at91sam9261_matrix.h>
|
||||
|
||||
#include "at91_udc.h"
|
||||
|
||||
@ -78,27 +80,11 @@
|
||||
static const char driver_name [] = "at91_udc";
|
||||
static const char ep0name[] = "ep0";
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Read from a UDP register.
|
||||
*/
|
||||
static inline unsigned long at91_udp_read(unsigned int reg)
|
||||
{
|
||||
void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
|
||||
|
||||
return __raw_readl(udp_base + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to a UDP register.
|
||||
*/
|
||||
static inline void at91_udp_write(unsigned int reg, unsigned long value)
|
||||
{
|
||||
void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
|
||||
|
||||
__raw_writel(value, udp_base + reg);
|
||||
}
|
||||
#define at91_udp_read(dev, reg) \
|
||||
__raw_readl((dev)->udp_baseaddr + (reg))
|
||||
#define at91_udp_write(dev, reg, val) \
|
||||
__raw_writel((val), (dev)->udp_baseaddr + (reg))
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -210,13 +196,13 @@ static int proc_udc_show(struct seq_file *s, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = at91_udp_read(AT91_UDP_FRM_NUM);
|
||||
tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM);
|
||||
seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
|
||||
(tmp & AT91_UDP_FRM_OK) ? " ok" : "",
|
||||
(tmp & AT91_UDP_FRM_ERR) ? " err" : "",
|
||||
(tmp & AT91_UDP_NUM));
|
||||
|
||||
tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
||||
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
||||
seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
|
||||
(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
|
||||
(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
|
||||
@ -224,13 +210,13 @@ static int proc_udc_show(struct seq_file *s, void *unused)
|
||||
(tmp & AT91_UDP_CONFG) ? " confg" : "",
|
||||
(tmp & AT91_UDP_FADDEN) ? " fadden" : "");
|
||||
|
||||
tmp = at91_udp_read(AT91_UDP_FADDR);
|
||||
tmp = at91_udp_read(udc, AT91_UDP_FADDR);
|
||||
seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp,
|
||||
(tmp & AT91_UDP_FEN) ? " fen" : "",
|
||||
(tmp & AT91_UDP_FADD));
|
||||
|
||||
proc_irq_show(s, "imr ", at91_udp_read(AT91_UDP_IMR));
|
||||
proc_irq_show(s, "isr ", at91_udp_read(AT91_UDP_ISR));
|
||||
proc_irq_show(s, "imr ", at91_udp_read(udc, AT91_UDP_IMR));
|
||||
proc_irq_show(s, "isr ", at91_udp_read(udc, AT91_UDP_ISR));
|
||||
|
||||
if (udc->enabled && udc->vbus) {
|
||||
proc_ep_show(s, &udc->ep[0]);
|
||||
@ -286,6 +272,7 @@ static inline void remove_debug_file(struct at91_udc *udc) {}
|
||||
static void done(struct at91_ep *ep, struct at91_request *req, int status)
|
||||
{
|
||||
unsigned stopped = ep->stopped;
|
||||
struct at91_udc *udc = ep->udc;
|
||||
|
||||
list_del_init(&req->queue);
|
||||
if (req->req.status == -EINPROGRESS)
|
||||
@ -301,7 +288,7 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status)
|
||||
|
||||
/* ep0 is always ready; other endpoints need a non-empty queue */
|
||||
if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
|
||||
at91_udp_write(AT91_UDP_IDR, ep->int_mask);
|
||||
at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -554,8 +541,8 @@ ok:
|
||||
* reset/init endpoint fifo. NOTE: leaves fifo_bank alone,
|
||||
* since endpoint resets don't reset hw pingpong state.
|
||||
*/
|
||||
at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(AT91_UDP_RST_EP, 0);
|
||||
at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(dev, AT91_UDP_RST_EP, 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
@ -564,6 +551,7 @@ ok:
|
||||
static int at91_ep_disable (struct usb_ep * _ep)
|
||||
{
|
||||
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
|
||||
struct at91_udc *udc = ep->udc;
|
||||
unsigned long flags;
|
||||
|
||||
if (ep == &ep->udc->ep[0])
|
||||
@ -579,8 +567,8 @@ static int at91_ep_disable (struct usb_ep * _ep)
|
||||
|
||||
/* reset fifos and endpoint */
|
||||
if (ep->udc->clocked) {
|
||||
at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(AT91_UDP_RST_EP, 0);
|
||||
at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(udc, AT91_UDP_RST_EP, 0);
|
||||
__raw_writel(0, ep->creg);
|
||||
}
|
||||
|
||||
@ -695,10 +683,10 @@ static int at91_ep_queue(struct usb_ep *_ep,
|
||||
* reconfigures the endpoints.
|
||||
*/
|
||||
if (dev->wait_for_config_ack) {
|
||||
tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
||||
tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT);
|
||||
tmp ^= AT91_UDP_CONFG;
|
||||
VDBG("toggle config\n");
|
||||
at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
||||
at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp);
|
||||
}
|
||||
if (req->req.length == 0) {
|
||||
ep0_in_status:
|
||||
@ -727,7 +715,7 @@ ep0_in_status:
|
||||
|
||||
if (req && !status) {
|
||||
list_add_tail (&req->queue, &ep->queue);
|
||||
at91_udp_write(AT91_UDP_IER, ep->int_mask);
|
||||
at91_udp_write(dev, AT91_UDP_IER, ep->int_mask);
|
||||
}
|
||||
done:
|
||||
local_irq_restore(flags);
|
||||
@ -758,6 +746,7 @@ static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
||||
static int at91_ep_set_halt(struct usb_ep *_ep, int value)
|
||||
{
|
||||
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
|
||||
struct at91_udc *udc = ep->udc;
|
||||
u32 __iomem *creg;
|
||||
u32 csr;
|
||||
unsigned long flags;
|
||||
@ -785,8 +774,8 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value)
|
||||
csr |= AT91_UDP_FORCESTALL;
|
||||
VDBG("halt %s\n", ep->ep.name);
|
||||
} else {
|
||||
at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(AT91_UDP_RST_EP, 0);
|
||||
at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(udc, AT91_UDP_RST_EP, 0);
|
||||
csr &= ~AT91_UDP_FORCESTALL;
|
||||
}
|
||||
__raw_writel(csr, creg);
|
||||
@ -813,9 +802,11 @@ static struct usb_ep_ops at91_ep_ops = {
|
||||
|
||||
static int at91_get_frame(struct usb_gadget *gadget)
|
||||
{
|
||||
struct at91_udc *udc = to_udc(gadget);
|
||||
|
||||
if (!to_udc(gadget)->clocked)
|
||||
return -EINVAL;
|
||||
return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
|
||||
return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
|
||||
}
|
||||
|
||||
static int at91_wakeup(struct usb_gadget *gadget)
|
||||
@ -833,11 +824,11 @@ static int at91_wakeup(struct usb_gadget *gadget)
|
||||
|
||||
/* NOTE: some "early versions" handle ESR differently ... */
|
||||
|
||||
glbstate = at91_udp_read(AT91_UDP_GLB_STAT);
|
||||
glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
||||
if (!(glbstate & AT91_UDP_ESR))
|
||||
goto done;
|
||||
glbstate |= AT91_UDP_ESR;
|
||||
at91_udp_write(AT91_UDP_GLB_STAT, glbstate);
|
||||
at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
|
||||
|
||||
done:
|
||||
local_irq_restore(flags);
|
||||
@ -861,6 +852,7 @@ static void udc_reinit(struct at91_udc *udc)
|
||||
ep->stopped = 0;
|
||||
ep->fifo_bank = 0;
|
||||
ep->ep.maxpacket = ep->maxpacket;
|
||||
ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
|
||||
// initialiser une queue par endpoint
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
}
|
||||
@ -915,14 +907,41 @@ static void pullup(struct at91_udc *udc, int is_on)
|
||||
if (!udc->enabled || !udc->vbus)
|
||||
is_on = 0;
|
||||
DBG("%sactive\n", is_on ? "" : "in");
|
||||
|
||||
if (is_on) {
|
||||
clk_on(udc);
|
||||
at91_udp_write(AT91_UDP_TXVC, 0);
|
||||
at91_set_gpio_value(udc->board.pullup_pin, 1);
|
||||
} else {
|
||||
at91_udp_write(udc, AT91_UDP_TXVC, 0);
|
||||
if (cpu_is_at91rm9200())
|
||||
at91_set_gpio_value(udc->board.pullup_pin, 1);
|
||||
else if (cpu_is_at91sam9260()) {
|
||||
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
|
||||
|
||||
txvc |= AT91_UDP_TXVC_PUON;
|
||||
at91_udp_write(udc, AT91_UDP_TXVC, txvc);
|
||||
} else if (cpu_is_at91sam9261()) {
|
||||
u32 usbpucr;
|
||||
|
||||
usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
|
||||
usbpucr |= AT91_MATRIX_USBPUCR_PUON;
|
||||
at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
|
||||
}
|
||||
} else {
|
||||
stop_activity(udc);
|
||||
at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
||||
at91_set_gpio_value(udc->board.pullup_pin, 0);
|
||||
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
||||
if (cpu_is_at91rm9200())
|
||||
at91_set_gpio_value(udc->board.pullup_pin, 0);
|
||||
else if (cpu_is_at91sam9260()) {
|
||||
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
|
||||
|
||||
txvc &= ~AT91_UDP_TXVC_PUON;
|
||||
at91_udp_write(udc, AT91_UDP_TXVC, txvc);
|
||||
} else if (cpu_is_at91sam9261()) {
|
||||
u32 usbpucr;
|
||||
|
||||
usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
|
||||
usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
|
||||
at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
|
||||
}
|
||||
clk_off(udc);
|
||||
}
|
||||
}
|
||||
@ -936,7 +955,10 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
|
||||
// VDBG("vbus %s\n", is_active ? "on" : "off");
|
||||
local_irq_save(flags);
|
||||
udc->vbus = (is_active != 0);
|
||||
pullup(udc, is_active);
|
||||
if (udc->driver)
|
||||
pullup(udc, is_active);
|
||||
else
|
||||
pullup(udc, 0);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
@ -1086,7 +1108,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
||||
|
||||
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
||||
| USB_REQ_SET_CONFIGURATION:
|
||||
tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
|
||||
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
|
||||
if (pkt.r.wValue)
|
||||
udc->wait_for_config_ack = (tmp == 0);
|
||||
else
|
||||
@ -1103,7 +1125,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
||||
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
||||
| USB_REQ_GET_STATUS:
|
||||
tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
|
||||
if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
|
||||
if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
|
||||
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
|
||||
PACKET("get device status\n");
|
||||
__raw_writeb(tmp, dreg);
|
||||
@ -1114,17 +1136,17 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
||||
| USB_REQ_SET_FEATURE:
|
||||
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
|
||||
goto stall;
|
||||
tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
||||
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
||||
tmp |= AT91_UDP_ESR;
|
||||
at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
||||
at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
|
||||
goto succeed;
|
||||
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
||||
| USB_REQ_CLEAR_FEATURE:
|
||||
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
|
||||
goto stall;
|
||||
tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
||||
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
||||
tmp &= ~AT91_UDP_ESR;
|
||||
at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
||||
at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
|
||||
goto succeed;
|
||||
|
||||
/*
|
||||
@ -1206,8 +1228,8 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
||||
} else if (ep->is_in)
|
||||
goto stall;
|
||||
|
||||
at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(AT91_UDP_RST_EP, 0);
|
||||
at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
|
||||
at91_udp_write(udc, AT91_UDP_RST_EP, 0);
|
||||
tmp = __raw_readl(ep->creg);
|
||||
tmp |= CLR_FX;
|
||||
tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
|
||||
@ -1222,7 +1244,10 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
||||
#undef w_length
|
||||
|
||||
/* pass request up to the gadget driver */
|
||||
status = udc->driver->setup(&udc->gadget, &pkt.r);
|
||||
if (udc->driver)
|
||||
status = udc->driver->setup(&udc->gadget, &pkt.r);
|
||||
else
|
||||
status = -ENODEV;
|
||||
if (status < 0) {
|
||||
stall:
|
||||
VDBG("req %02x.%02x protocol STALL; stat %d\n",
|
||||
@ -1300,13 +1325,13 @@ static void handle_ep0(struct at91_udc *udc)
|
||||
if (udc->wait_for_addr_ack) {
|
||||
u32 tmp;
|
||||
|
||||
at91_udp_write(AT91_UDP_FADDR,
|
||||
at91_udp_write(udc, AT91_UDP_FADDR,
|
||||
AT91_UDP_FEN | udc->addr);
|
||||
tmp = at91_udp_read(AT91_UDP_GLB_STAT);
|
||||
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
|
||||
tmp &= ~AT91_UDP_FADDEN;
|
||||
if (udc->addr)
|
||||
tmp |= AT91_UDP_FADDEN;
|
||||
at91_udp_write(AT91_UDP_GLB_STAT, tmp);
|
||||
at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
|
||||
|
||||
udc->wait_for_addr_ack = 0;
|
||||
VDBG("address %d\n", udc->addr);
|
||||
@ -1374,28 +1399,28 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
|
||||
while (rescans--) {
|
||||
u32 status;
|
||||
|
||||
status = at91_udp_read(AT91_UDP_ISR)
|
||||
& at91_udp_read(AT91_UDP_IMR);
|
||||
status = at91_udp_read(udc, AT91_UDP_ISR)
|
||||
& at91_udp_read(udc, AT91_UDP_IMR);
|
||||
if (!status)
|
||||
break;
|
||||
|
||||
/* USB reset irq: not maskable */
|
||||
if (status & AT91_UDP_ENDBUSRES) {
|
||||
at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
|
||||
at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS);
|
||||
at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
|
||||
at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS);
|
||||
/* Atmel code clears this irq twice */
|
||||
at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
||||
at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
||||
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
||||
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
|
||||
VDBG("end bus reset\n");
|
||||
udc->addr = 0;
|
||||
stop_activity(udc);
|
||||
|
||||
/* enable ep0 */
|
||||
at91_udp_write(AT91_UDP_CSR(0),
|
||||
at91_udp_write(udc, AT91_UDP_CSR(0),
|
||||
AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
|
||||
udc->gadget.speed = USB_SPEED_FULL;
|
||||
udc->suspended = 0;
|
||||
at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
|
||||
at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0));
|
||||
|
||||
/*
|
||||
* NOTE: this driver keeps clocks off unless the
|
||||
@ -1406,9 +1431,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
|
||||
|
||||
/* host initiated suspend (3+ms bus idle) */
|
||||
} else if (status & AT91_UDP_RXSUSP) {
|
||||
at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP);
|
||||
at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM);
|
||||
at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP);
|
||||
at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
|
||||
at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
|
||||
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
|
||||
// VDBG("bus suspend\n");
|
||||
if (udc->suspended)
|
||||
continue;
|
||||
@ -1425,9 +1450,9 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
|
||||
|
||||
/* host initiated resume */
|
||||
} else if (status & AT91_UDP_RXRSM) {
|
||||
at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM);
|
||||
at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP);
|
||||
at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM);
|
||||
at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
|
||||
at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
|
||||
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
|
||||
// VDBG("bus resume\n");
|
||||
if (!udc->suspended)
|
||||
continue;
|
||||
@ -1485,8 +1510,6 @@ static struct at91_udc controller = {
|
||||
},
|
||||
.udc = &controller,
|
||||
.maxpacket = 8,
|
||||
.creg = (void __iomem *)(AT91_VA_BASE_UDP
|
||||
+ AT91_UDP_CSR(0)),
|
||||
.int_mask = 1 << 0,
|
||||
},
|
||||
.ep[1] = {
|
||||
@ -1497,8 +1520,6 @@ static struct at91_udc controller = {
|
||||
.udc = &controller,
|
||||
.is_pingpong = 1,
|
||||
.maxpacket = 64,
|
||||
.creg = (void __iomem *)(AT91_VA_BASE_UDP
|
||||
+ AT91_UDP_CSR(1)),
|
||||
.int_mask = 1 << 1,
|
||||
},
|
||||
.ep[2] = {
|
||||
@ -1509,8 +1530,6 @@ static struct at91_udc controller = {
|
||||
.udc = &controller,
|
||||
.is_pingpong = 1,
|
||||
.maxpacket = 64,
|
||||
.creg = (void __iomem *)(AT91_VA_BASE_UDP
|
||||
+ AT91_UDP_CSR(2)),
|
||||
.int_mask = 1 << 2,
|
||||
},
|
||||
.ep[3] = {
|
||||
@ -1521,8 +1540,6 @@ static struct at91_udc controller = {
|
||||
},
|
||||
.udc = &controller,
|
||||
.maxpacket = 8,
|
||||
.creg = (void __iomem *)(AT91_VA_BASE_UDP
|
||||
+ AT91_UDP_CSR(3)),
|
||||
.int_mask = 1 << 3,
|
||||
},
|
||||
.ep[4] = {
|
||||
@ -1533,8 +1550,6 @@ static struct at91_udc controller = {
|
||||
.udc = &controller,
|
||||
.is_pingpong = 1,
|
||||
.maxpacket = 256,
|
||||
.creg = (void __iomem *)(AT91_VA_BASE_UDP
|
||||
+ AT91_UDP_CSR(4)),
|
||||
.int_mask = 1 << 4,
|
||||
},
|
||||
.ep[5] = {
|
||||
@ -1545,8 +1560,6 @@ static struct at91_udc controller = {
|
||||
.udc = &controller,
|
||||
.is_pingpong = 1,
|
||||
.maxpacket = 256,
|
||||
.creg = (void __iomem *)(AT91_VA_BASE_UDP
|
||||
+ AT91_UDP_CSR(5)),
|
||||
.int_mask = 1 << 5,
|
||||
},
|
||||
/* ep6 and ep7 are also reserved (custom silicon might use them) */
|
||||
@ -1572,9 +1585,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_FULL
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !driver->unbind
|
||||
|| !driver->setup) {
|
||||
DBG("bad parameter.\n");
|
||||
return -EINVAL;
|
||||
@ -1595,6 +1607,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
if (retval) {
|
||||
DBG("driver->bind() returned %d\n", retval);
|
||||
udc->driver = NULL;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->gadget.dev.driver_data = NULL;
|
||||
udc->enabled = 0;
|
||||
udc->selfpowered = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1611,12 +1627,12 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct at91_udc *udc = &controller;
|
||||
|
||||
if (!driver || driver != udc->driver)
|
||||
if (!driver || driver != udc->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_disable();
|
||||
udc->enabled = 0;
|
||||
at91_udp_write(AT91_UDP_IDR, ~0);
|
||||
at91_udp_write(udc, AT91_UDP_IDR, ~0);
|
||||
pullup(udc, 0);
|
||||
local_irq_enable();
|
||||
|
||||
@ -1641,6 +1657,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct at91_udc *udc;
|
||||
int retval;
|
||||
struct resource *res;
|
||||
|
||||
if (!dev->platform_data) {
|
||||
/* small (so we copy it) but critical! */
|
||||
@ -1658,7 +1675,13 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENXIO;
|
||||
|
||||
if (!request_mem_region(res->start,
|
||||
res->end - res->start + 1,
|
||||
driver_name)) {
|
||||
DBG("someone's using UDC memory\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -1668,15 +1691,23 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
||||
udc->gadget.dev.parent = dev;
|
||||
udc->board = *(struct at91_udc_data *) dev->platform_data;
|
||||
udc->pdev = pdev;
|
||||
udc_reinit(udc);
|
||||
udc->enabled = 0;
|
||||
|
||||
udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
|
||||
if (!udc->udp_baseaddr) {
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
udc_reinit(udc);
|
||||
|
||||
/* get interface and function clocks */
|
||||
udc->iclk = clk_get(dev, "udc_clk");
|
||||
udc->fclk = clk_get(dev, "udpck");
|
||||
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
|
||||
DBG("clocks missing\n");
|
||||
return -ENODEV;
|
||||
retval = -ENODEV;
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
retval = device_register(&udc->gadget.dev);
|
||||
@ -1685,8 +1716,10 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
||||
|
||||
/* don't do anything until we have both gadget driver and VBUS */
|
||||
clk_enable(udc->iclk);
|
||||
at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
||||
at91_udp_write(AT91_UDP_IDR, 0xffffffff);
|
||||
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
||||
at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
|
||||
/* Clear all pending interrupts - UDP may be used by bootloader. */
|
||||
at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff);
|
||||
clk_disable(udc->iclk);
|
||||
|
||||
/* request UDC and maybe VBUS irqs */
|
||||
@ -1698,6 +1731,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
||||
goto fail1;
|
||||
}
|
||||
if (udc->board.vbus_pin > 0) {
|
||||
/*
|
||||
* Get the initial state of VBUS - we cannot expect
|
||||
* a pending interrupt.
|
||||
*/
|
||||
udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
|
||||
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
|
||||
IRQF_DISABLED, driver_name, udc)) {
|
||||
DBG("request vbus irq %d failed\n",
|
||||
@ -1720,7 +1758,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
||||
fail1:
|
||||
device_unregister(&udc->gadget.dev);
|
||||
fail0:
|
||||
release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
DBG("%s probe failed, %d\n", driver_name, retval);
|
||||
return retval;
|
||||
}
|
||||
@ -1728,13 +1766,14 @@ fail0:
|
||||
static int __devexit at91udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_udc *udc = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
DBG("remove\n");
|
||||
|
||||
pullup(udc, 0);
|
||||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
||||
if (udc->driver != 0)
|
||||
usb_gadget_unregister_driver(udc->driver);
|
||||
pullup(udc, 0);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
remove_debug_file(udc);
|
||||
@ -1742,7 +1781,10 @@ static int __devexit at91udc_remove(struct platform_device *pdev)
|
||||
free_irq(udc->board.vbus_pin, udc);
|
||||
free_irq(udc->udp_irq, udc);
|
||||
device_unregister(&udc->gadget.dev);
|
||||
release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
|
||||
|
||||
iounmap(udc->udp_baseaddr);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, res->end - res->start + 1);
|
||||
|
||||
clk_put(udc->iclk);
|
||||
clk_put(udc->fclk);
|
||||
|
@ -51,10 +51,10 @@
|
||||
#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */
|
||||
#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */
|
||||
#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */
|
||||
#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */
|
||||
#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */
|
||||
#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */
|
||||
#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */
|
||||
#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */
|
||||
#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */
|
||||
|
||||
#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */
|
||||
#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */
|
||||
@ -84,7 +84,7 @@
|
||||
|
||||
#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */
|
||||
#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */
|
||||
|
||||
#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -141,6 +141,7 @@ struct at91_udc {
|
||||
struct clk *iclk, *fclk;
|
||||
struct platform_device *pdev;
|
||||
struct proc_dir_entry *pde;
|
||||
void __iomem *udp_baseaddr;
|
||||
int udp_irq;
|
||||
};
|
||||
|
||||
|
@ -779,7 +779,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
return -EINVAL;
|
||||
if (dum->driver)
|
||||
return -EBUSY;
|
||||
if (!driver->bind || !driver->unbind || !driver->setup
|
||||
if (!driver->bind || !driver->setup
|
||||
|| driver->speed == USB_SPEED_UNKNOWN)
|
||||
return -EINVAL;
|
||||
|
||||
@ -837,7 +837,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
err_bind_driver:
|
||||
driver_unregister (&driver->driver);
|
||||
err_register:
|
||||
driver->unbind (&dum->gadget);
|
||||
if (driver->unbind)
|
||||
driver->unbind (&dum->gadget);
|
||||
spin_lock_irq (&dum->lock);
|
||||
dum->pullup = 0;
|
||||
set_link_state (dum);
|
||||
@ -857,7 +858,7 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
|
||||
if (!dum)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != dum->driver)
|
||||
if (!driver || driver != dum->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
|
||||
|
@ -4100,7 +4100,7 @@ static struct usb_gadget_driver fsg_driver = {
|
||||
#endif
|
||||
.function = (char *) longname,
|
||||
.bind = fsg_bind,
|
||||
.unbind = __exit_p(fsg_unbind),
|
||||
.unbind = fsg_unbind,
|
||||
.disconnect = fsg_disconnect,
|
||||
.setup = fsg_setup,
|
||||
.suspend = fsg_suspend,
|
||||
|
@ -123,7 +123,7 @@ struct gmidi_device {
|
||||
struct usb_request *req; /* for control responses */
|
||||
u8 config;
|
||||
struct usb_ep *in_ep, *out_ep;
|
||||
struct snd_card *card;
|
||||
struct snd_card *card;
|
||||
struct snd_rawmidi *rmidi;
|
||||
struct snd_rawmidi_substream *in_substream;
|
||||
struct snd_rawmidi_substream *out_substream;
|
||||
@ -490,7 +490,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
int status = req->status;
|
||||
|
||||
switch (status) {
|
||||
case 0: /* normal completion */
|
||||
case 0: /* normal completion */
|
||||
if (ep == dev->out_ep) {
|
||||
/* we received stuff.
|
||||
req is queued again, below */
|
||||
@ -505,7 +505,7 @@ static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
break;
|
||||
|
||||
/* this endpoint is normally active while we're configured */
|
||||
case -ECONNABORTED: /* hardware forced ep reset */
|
||||
case -ECONNABORTED: /* hardware forced ep reset */
|
||||
case -ECONNRESET: /* request dequeued */
|
||||
case -ESHUTDOWN: /* disconnect from host */
|
||||
VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
|
||||
@ -656,7 +656,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
|
||||
case USB_SPEED_LOW: speed = "low"; break;
|
||||
case USB_SPEED_FULL: speed = "full"; break;
|
||||
case USB_SPEED_HIGH: speed = "high"; break;
|
||||
default: speed = "?"; break;
|
||||
default: speed = "?"; break;
|
||||
}
|
||||
|
||||
dev->config = number;
|
||||
@ -1308,7 +1308,7 @@ static struct usb_gadget_driver gmidi_driver = {
|
||||
.speed = USB_SPEED_FULL,
|
||||
.function = (char *)longname,
|
||||
.bind = gmidi_bind,
|
||||
.unbind = __exit_p(gmidi_unbind),
|
||||
.unbind = gmidi_unbind,
|
||||
|
||||
.setup = gmidi_setup,
|
||||
.disconnect = gmidi_disconnect,
|
||||
@ -1316,7 +1316,7 @@ static struct usb_gadget_driver gmidi_driver = {
|
||||
.suspend = gmidi_suspend,
|
||||
.resume = gmidi_resume,
|
||||
|
||||
.driver = {
|
||||
.driver = {
|
||||
.name = (char *)shortname,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
|
@ -1432,7 +1432,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !driver->unbind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
@ -1495,7 +1494,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != dev->driver)
|
||||
if (!driver || driver != dev->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
@ -1808,13 +1807,8 @@ static void goku_remove(struct pci_dev *pdev)
|
||||
struct goku_udc *dev = pci_get_drvdata(pdev);
|
||||
|
||||
DBG(dev, "%s\n", __FUNCTION__);
|
||||
/* start with the driver above us */
|
||||
if (dev->driver) {
|
||||
/* should have been done already by driver model core */
|
||||
WARN(dev, "pci remove, driver '%s' is still registered\n",
|
||||
dev->driver->driver.name);
|
||||
usb_gadget_unregister_driver(dev->driver);
|
||||
}
|
||||
|
||||
BUG_ON(dev->driver);
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
remove_proc_entry(proc_node_name, NULL);
|
||||
|
@ -422,9 +422,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name);
|
||||
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !driver->unbind || !driver->disconnect || !driver->setup)
|
||||
|| driver->speed != USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
@ -471,7 +472,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != dev->driver)
|
||||
if (!driver || driver != dev->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
@ -2125,9 +2126,11 @@ static int lh7a40x_udc_remove(struct platform_device *pdev)
|
||||
|
||||
DEBUG("%s: %p\n", __FUNCTION__, pdev);
|
||||
|
||||
if (dev->driver)
|
||||
return -EBUSY;
|
||||
|
||||
udc_disable(dev);
|
||||
remove_proc_files();
|
||||
usb_gadget_unregister_driver(dev->driver);
|
||||
|
||||
free_irq(IRQ_USBINTR, dev);
|
||||
|
||||
|
@ -2020,7 +2020,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_HIGH
|
||||
|| !driver->bind
|
||||
|| !driver->unbind
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!dev)
|
||||
@ -2107,7 +2106,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != dev->driver)
|
||||
if (!driver || driver != dev->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave (&dev->lock, flags);
|
||||
@ -2803,13 +2802,7 @@ static void net2280_remove (struct pci_dev *pdev)
|
||||
{
|
||||
struct net2280 *dev = pci_get_drvdata (pdev);
|
||||
|
||||
/* start with the driver above us */
|
||||
if (dev->driver) {
|
||||
/* should have been done already by driver model core */
|
||||
WARN (dev, "pci remove, driver '%s' is still registered\n",
|
||||
dev->driver->driver.name);
|
||||
usb_gadget_unregister_driver (dev->driver);
|
||||
}
|
||||
BUG_ON(dev->driver);
|
||||
|
||||
/* then clean up the resources we allocated during probe() */
|
||||
net2280_led_shutdown (dev);
|
||||
|
@ -2043,7 +2043,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
// FIXME if otg, check: driver->is_otg
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !driver->unbind
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
@ -2087,9 +2086,11 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
status = otg_set_peripheral(udc->transceiver, &udc->gadget);
|
||||
if (status < 0) {
|
||||
ERR("can't bind to transceiver\n");
|
||||
driver->unbind (&udc->gadget);
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
if (driver->unbind) {
|
||||
driver->unbind (&udc->gadget);
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
@ -2117,7 +2118,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
|
||||
if (!udc)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != udc->driver)
|
||||
if (!driver || driver != udc->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
if (machine_is_omap_innovator() || machine_is_omap_osk())
|
||||
@ -2870,6 +2871,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
|
||||
|
||||
if (!udc)
|
||||
return -ENODEV;
|
||||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
||||
udc->done = &done;
|
||||
|
||||
|
@ -1623,7 +1623,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
if (!driver
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !driver->unbind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
@ -1694,7 +1693,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != dev->driver)
|
||||
if (!driver || driver != dev->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_disable();
|
||||
@ -2638,9 +2637,11 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa2xx_udc *dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (dev->driver)
|
||||
return -EBUSY;
|
||||
|
||||
udc_disable(dev);
|
||||
remove_proc_files();
|
||||
usb_gadget_unregister_driver(dev->driver);
|
||||
|
||||
if (dev->got_irq) {
|
||||
free_irq(IRQ_USB, dev);
|
||||
|
@ -296,7 +296,7 @@ static struct usb_gadget_driver gs_gadget_driver = {
|
||||
#endif /* CONFIG_USB_GADGET_DUALSPEED */
|
||||
.function = GS_LONG_NAME,
|
||||
.bind = gs_bind,
|
||||
.unbind = __exit_p(gs_unbind),
|
||||
.unbind = gs_unbind,
|
||||
.setup = gs_setup,
|
||||
.disconnect = gs_disconnect,
|
||||
.driver = {
|
||||
|
@ -187,7 +187,6 @@ ohci_at91_start (struct usb_hcd *hcd)
|
||||
{
|
||||
struct at91_usbh_data *board = hcd->self.controller->platform_data;
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
struct usb_device *root = hcd->self.root_hub;
|
||||
int ret;
|
||||
|
||||
if ((ret = ohci_init(ohci)) < 0)
|
||||
@ -221,7 +220,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
|
||||
*/
|
||||
.start = ohci_at91_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
|
@ -269,7 +269,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
|
||||
*/
|
||||
.start = ohci_au1xxx_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
@ -336,7 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
|
||||
static struct platform_driver ohci_hcd_au1xxx_driver = {
|
||||
.probe = ohci_hcd_au1xxx_drv_probe,
|
||||
.remove = ohci_hcd_au1xxx_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
/*.suspend = ohci_hcd_au1xxx_drv_suspend, */
|
||||
/*.resume = ohci_hcd_au1xxx_drv_resume, */
|
||||
.driver = {
|
||||
|
@ -16,7 +16,7 @@
|
||||
case PIPE_CONTROL: temp = "ctrl"; break; \
|
||||
case PIPE_BULK: temp = "bulk"; break; \
|
||||
case PIPE_INTERRUPT: temp = "intr"; break; \
|
||||
default: temp = "isoc"; break; \
|
||||
default: temp = "isoc"; break; \
|
||||
}; temp;})
|
||||
#define pipestring(pipe) edstring(usb_pipetype(pipe))
|
||||
|
||||
@ -205,13 +205,13 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
|
||||
(temp & RH_PS_PSSC) ? " PSSC" : "", \
|
||||
(temp & RH_PS_PESC) ? " PESC" : "", \
|
||||
(temp & RH_PS_CSC) ? " CSC" : "", \
|
||||
\
|
||||
\
|
||||
(temp & RH_PS_LSDA) ? " LSDA" : "", \
|
||||
(temp & RH_PS_PPS) ? " PPS" : "", \
|
||||
(temp & RH_PS_PRS) ? " PRS" : "", \
|
||||
(temp & RH_PS_POCI) ? " POCI" : "", \
|
||||
(temp & RH_PS_PSS) ? " PSS" : "", \
|
||||
\
|
||||
\
|
||||
(temp & RH_PS_PES) ? " PES" : "", \
|
||||
(temp & RH_PS_CCS) ? " CCS" : "" \
|
||||
);
|
||||
@ -563,7 +563,7 @@ show_periodic (struct class_device *class_dev, char *buf)
|
||||
(info & ED_SKIP) ? " K" : "",
|
||||
(ed->hwHeadP &
|
||||
cpu_to_hc32(ohci, ED_H)) ?
|
||||
" H" : "");
|
||||
" H" : "");
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
|
@ -204,7 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
|
||||
static struct platform_driver ohci_hcd_ep93xx_driver = {
|
||||
.probe = ohci_hcd_ep93xx_drv_probe,
|
||||
.remove = ohci_hcd_ep93xx_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ohci_hcd_ep93xx_drv_suspend,
|
||||
.resume = ohci_hcd_ep93xx_drv_resume,
|
||||
|
@ -3,77 +3,21 @@
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
*
|
||||
* [ Initialisation is based on Linus' ]
|
||||
* [ uhci code and gregs ohci fragments ]
|
||||
* [ (C) Copyright 1999 Linus Torvalds ]
|
||||
* [ (C) Copyright 1999 Gregory P. Smith]
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller
|
||||
* interfaces (though some non-x86 Intel chips use it). It supports
|
||||
* smarter hardware than UHCI. A download link for the spec available
|
||||
* through the http://www.usb.org website.
|
||||
*
|
||||
* History:
|
||||
*
|
||||
* 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer)
|
||||
* 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net)
|
||||
* 2003/02/24 show registers in sysfs (Kevin Brosius)
|
||||
*
|
||||
* 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
|
||||
* bandwidth accounting; if debugging, show schedules in driverfs
|
||||
* 2002/07/19 fixes to management of ED and schedule state.
|
||||
* 2002/06/09 SA-1111 support (Christopher Hoover)
|
||||
* 2002/06/01 remember frame when HC won't see EDs any more; use that info
|
||||
* to fix urb unlink races caused by interrupt latency assumptions;
|
||||
* minor ED field and function naming updates
|
||||
* 2002/01/18 package as a patch for 2.5.3; this should match the
|
||||
* 2.4.17 kernel modulo some bugs being fixed.
|
||||
*
|
||||
* 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
|
||||
* from post-2.4.5 patches.
|
||||
* 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning
|
||||
* 2001/09/07 match PCI PM changes, errnos from Linus' tree
|
||||
* 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
|
||||
* pbook pci quirks gone (please fix pbook pci sw!) (db)
|
||||
*
|
||||
* 2001/04/08 Identify version on module load (gb)
|
||||
* 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
|
||||
pci_map_single (db)
|
||||
* 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
|
||||
* 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
|
||||
*
|
||||
* 2000/09/26 fixed races in removing the private portion of the urb
|
||||
* 2000/09/07 disable bulk and control lists when unlinking the last
|
||||
* endpoint descriptor in order to avoid unrecoverable errors on
|
||||
* the Lucent chips. (rwc@sgi)
|
||||
* 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
|
||||
* urb unlink probs, indentation fixes
|
||||
* 2000/08/11 various oops fixes mostly affecting iso and cleanup from
|
||||
* device unplugs.
|
||||
* 2000/06/28 use PCI hotplug framework, for better power management
|
||||
* and for Cardbus support (David Brownell)
|
||||
* 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling
|
||||
* when the controller loses power; handle UE; cleanup; ...
|
||||
*
|
||||
* v5.2 1999/12/07 URB 3rd preview,
|
||||
* v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
|
||||
* v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume
|
||||
* i386: HUB, Keyboard, Mouse, Printer
|
||||
*
|
||||
* v4.3 1999/10/27 multiple HCs, bulk_request
|
||||
* v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
|
||||
* v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
|
||||
* v4.0 1999/08/18
|
||||
* v3.0 1999/06/25
|
||||
* v2.1 1999/05/09 code clean up
|
||||
* v2.0 1999/05/04
|
||||
* v1.0 1999/04/27 initial release
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pci.h>
|
||||
@ -89,7 +33,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
@ -183,11 +127,11 @@ static int ohci_urb_enqueue (
|
||||
int i, size = 0;
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
|
||||
|
||||
#ifdef OHCI_VERBOSE_DEBUG
|
||||
urb_print (urb, "SUB", usb_pipein (pipe));
|
||||
#endif
|
||||
|
||||
|
||||
/* every endpoint has a ed, locate and maybe (re)initialize it */
|
||||
if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
|
||||
return -ENOMEM;
|
||||
@ -232,7 +176,7 @@ static int ohci_urb_enqueue (
|
||||
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
|
||||
INIT_LIST_HEAD (&urb_priv->pending);
|
||||
urb_priv->length = size;
|
||||
urb_priv->ed = ed;
|
||||
urb_priv->ed = ed;
|
||||
|
||||
/* allocate the TDs (deferring hash chain updates) */
|
||||
for (i = 0; i < size; i++) {
|
||||
@ -242,7 +186,7 @@ static int ohci_urb_enqueue (
|
||||
urb_free_priv (ohci, urb_priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
|
||||
@ -313,13 +257,13 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
#ifdef OHCI_VERBOSE_DEBUG
|
||||
urb_print (urb, "UNLINK", 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
if (HC_IS_RUNNING(hcd->state)) {
|
||||
if (HC_IS_RUNNING(hcd->state)) {
|
||||
urb_priv_t *urb_priv;
|
||||
|
||||
/* Unless an IRQ completed the unlink while it was being
|
||||
@ -512,11 +456,11 @@ static int ohci_init (struct ohci_hcd *ohci)
|
||||
|
||||
/* Start an OHCI controller, set the BUS operational
|
||||
* resets USB and controller
|
||||
* enable interrupts
|
||||
* enable interrupts
|
||||
*/
|
||||
static int ohci_run (struct ohci_hcd *ohci)
|
||||
{
|
||||
u32 mask, temp;
|
||||
u32 mask, temp;
|
||||
int first = ohci->fminterval == 0;
|
||||
struct usb_hcd *hcd = ohci_to_hcd(ohci);
|
||||
|
||||
@ -534,7 +478,7 @@ static int ohci_run (struct ohci_hcd *ohci)
|
||||
/* also: power/overcurrent flags in roothub.a */
|
||||
}
|
||||
|
||||
/* Reset USB nearly "by the book". RemoteWakeupConnected was
|
||||
/* Reset USB nearly "by the book". RemoteWakeupConnected was
|
||||
* saved if boot firmware (BIOS/SMM/...) told us it's connected,
|
||||
* or if bus glue did the same (e.g. for PCI add-in cards with
|
||||
* PCI PM support).
|
||||
@ -765,9 +709,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||
dl_done_list (ohci);
|
||||
spin_unlock (&ohci->lock);
|
||||
if (HC_IS_RUNNING(hcd->state))
|
||||
ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable);
|
||||
ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable);
|
||||
}
|
||||
|
||||
|
||||
/* could track INTR_SO to reduce available PCI/... bandwidth */
|
||||
|
||||
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
|
||||
@ -778,12 +722,12 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||
finish_unlinks (ohci, ohci_frame_no(ohci));
|
||||
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
|
||||
&& HC_IS_RUNNING(hcd->state))
|
||||
ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable);
|
||||
ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable);
|
||||
spin_unlock (&ohci->lock);
|
||||
|
||||
if (HC_IS_RUNNING(hcd->state)) {
|
||||
ohci_writel (ohci, ints, ®s->intrstatus);
|
||||
ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable);
|
||||
ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable);
|
||||
// flush those writes
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
}
|
||||
@ -794,7 +738,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void ohci_stop (struct usb_hcd *hcd)
|
||||
{
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
|
||||
ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
|
||||
@ -812,8 +756,8 @@ static void ohci_stop (struct usb_hcd *hcd)
|
||||
remove_debug_files (ohci);
|
||||
ohci_mem_cleanup (ohci);
|
||||
if (ohci->hcca) {
|
||||
dma_free_coherent (hcd->self.controller,
|
||||
sizeof *ohci->hcca,
|
||||
dma_free_coherent (hcd->self.controller,
|
||||
sizeof *ohci->hcca,
|
||||
ohci->hcca, ohci->hcca_dma);
|
||||
ohci->hcca = NULL;
|
||||
ohci->hcca_dma = 0;
|
||||
@ -836,7 +780,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
|
||||
* recycle any "live" eds/tds (and urbs) right away.
|
||||
* later, khubd disconnect processing will recycle the other state,
|
||||
* (either as disconnect/reconnect, or maybe someday as a reset).
|
||||
*/
|
||||
*/
|
||||
spin_lock_irq(&ohci->lock);
|
||||
disable (ohci);
|
||||
usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
|
||||
@ -875,11 +819,11 @@ static int ohci_restart (struct ohci_hcd *ohci)
|
||||
/* empty the interrupt branches */
|
||||
for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
|
||||
for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
|
||||
|
||||
|
||||
/* no EDs to remove */
|
||||
ohci->ed_rm_list = NULL;
|
||||
|
||||
/* empty control and bulk lists */
|
||||
/* empty control and bulk lists */
|
||||
ohci->ed_controltail = NULL;
|
||||
ohci->ed_bulktail = NULL;
|
||||
|
||||
@ -941,6 +885,10 @@ MODULE_LICENSE ("GPL");
|
||||
#include "ohci-au1xxx.c"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PNX8550
|
||||
#include "ohci-pnx8550.c"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
|
||||
#include "ohci-ppc-soc.c"
|
||||
#endif
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
*
|
||||
* This file is licenced under GPL
|
||||
*/
|
||||
|
||||
@ -23,13 +23,13 @@
|
||||
(temp & RH_PS_PSSC) ? " PSSC" : "", \
|
||||
(temp & RH_PS_PESC) ? " PESC" : "", \
|
||||
(temp & RH_PS_CSC) ? " CSC" : "", \
|
||||
\
|
||||
\
|
||||
(temp & RH_PS_LSDA) ? " LSDA" : "", \
|
||||
(temp & RH_PS_PPS) ? " PPS" : "", \
|
||||
(temp & RH_PS_PRS) ? " PRS" : "", \
|
||||
(temp & RH_PS_POCI) ? " POCI" : "", \
|
||||
(temp & RH_PS_PSS) ? " PSS" : "", \
|
||||
\
|
||||
\
|
||||
(temp & RH_PS_PES) ? " PES" : "", \
|
||||
(temp & RH_PS_CCS) ? " CCS" : "" \
|
||||
);
|
||||
@ -484,7 +484,7 @@ ohci_hub_descriptor (
|
||||
temp = 0;
|
||||
if (rh & RH_A_NPS) /* no power switching? */
|
||||
temp |= 0x0002;
|
||||
if (rh & RH_A_PSM) /* per-port power switching? */
|
||||
if (rh & RH_A_PSM) /* per-port power switching? */
|
||||
temp |= 0x0001;
|
||||
if (rh & RH_A_NOCP) /* no overcurrent reporting? */
|
||||
temp |= 0x0010;
|
||||
@ -555,7 +555,7 @@ static void start_hnp(struct ohci_hcd *ohci);
|
||||
#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
|
||||
|
||||
/* called from some task, normally khubd */
|
||||
static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
|
||||
static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
|
||||
{
|
||||
__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
|
||||
u32 temp;
|
||||
@ -570,10 +570,13 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
|
||||
/* spin until any current reset finishes */
|
||||
for (;;) {
|
||||
temp = ohci_readl (ohci, portstat);
|
||||
/* handle e.g. CardBus eject */
|
||||
if (temp == ~(u32)0)
|
||||
return -ESHUTDOWN;
|
||||
if (!(temp & RH_PS_PRS))
|
||||
break;
|
||||
udelay (500);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(temp & RH_PS_CCS))
|
||||
break;
|
||||
@ -586,6 +589,8 @@ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
|
||||
now = ohci_readl(ohci, &ohci->regs->fmnumber);
|
||||
} while (tick_before(now, reset_done));
|
||||
/* caller synchronizes using PRSC */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ohci_hub_control (
|
||||
@ -702,7 +707,7 @@ static int ohci_hub_control (
|
||||
&ohci->regs->roothub.portstatus [wIndex]);
|
||||
break;
|
||||
case USB_PORT_FEAT_RESET:
|
||||
root_port_reset (ohci, wIndex);
|
||||
retval = root_port_reset (ohci, wIndex);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
|
@ -38,7 +38,7 @@ static void lh7a404_start_hc(struct platform_device *dev)
|
||||
CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */
|
||||
udelay(1000);
|
||||
USBH_CMDSTATUS = OHCI_HCR;
|
||||
|
||||
|
||||
printk(KERN_DEBUG __FILE__
|
||||
": Clock to USB host has been enabled \n");
|
||||
}
|
||||
@ -89,7 +89,7 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
|
||||
retval = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
pr_debug("ioremap failed");
|
||||
@ -174,7 +174,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
|
||||
*/
|
||||
.start = ohci_lh7a404_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
@ -242,7 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev)
|
||||
static struct platform_driver ohci_hcd_lh7a404_driver = {
|
||||
.probe = ohci_hcd_lh7a404_drv_probe,
|
||||
.remove = ohci_hcd_lh7a404_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
/*.suspend = ohci_hcd_lh7a404_drv_suspend, */
|
||||
/*.resume = ohci_hcd_lh7a404_drv_resume, */
|
||||
.driver = {
|
||||
|
@ -1,24 +1,24 @@
|
||||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* There's basically three types of memory:
|
||||
* OHCI deals with three types of memory:
|
||||
* - data used only by the HCD ... kmalloc is fine
|
||||
* - async and periodic schedules, shared by HC and HCD ... these
|
||||
* need to use dma_pool or dma_alloc_coherent
|
||||
* - driver buffers, read/written by HC ... the hcd glue or the
|
||||
* device driver provides us with dma addresses
|
||||
*
|
||||
* There's also PCI "register" data, which is memory mapped.
|
||||
* No memory seen by this driver is pagable.
|
||||
* There's also "register" data, which is memory mapped.
|
||||
* No memory seen by this driver (or any HCD) may be paged out.
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -447,7 +447,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
|
||||
.reset = ohci_omap_init,
|
||||
.start = ohci_omap_start,
|
||||
.stop = ohci_omap_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
@ -533,7 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev)
|
||||
static struct platform_driver ohci_hcd_omap_driver = {
|
||||
.probe = ohci_hcd_omap_drv_probe,
|
||||
.remove = ohci_hcd_omap_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ohci_omap_suspend,
|
||||
.resume = ohci_omap_resume,
|
||||
|
@ -3,17 +3,17 @@
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
*
|
||||
* [ Initialisation is based on Linus' ]
|
||||
* [ uhci code and gregs ohci fragments ]
|
||||
* [ (C) Copyright 1999 Linus Torvalds ]
|
||||
* [ (C) Copyright 1999 Gregory P. Smith]
|
||||
*
|
||||
*
|
||||
* PCI Bus Glue
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONFIG_PCI
|
||||
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
|
||||
#endif
|
||||
@ -83,7 +83,7 @@ ohci_pci_start (struct usb_hcd *hcd)
|
||||
pci_dev_put(b);
|
||||
}
|
||||
|
||||
/* Check for Compaq's ZFMicro chipset, which needs short
|
||||
/* Check for Compaq's ZFMicro chipset, which needs short
|
||||
* delays before control or bulk queues get re-activated
|
||||
* in finish_unlinks()
|
||||
*/
|
||||
@ -238,8 +238,8 @@ static struct pci_driver ohci_pci_driver = {
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
};
|
||||
|
||||
|
||||
static int __init ohci_hcd_pci_init (void)
|
||||
|
||||
static int __init ohci_hcd_pci_init (void)
|
||||
{
|
||||
printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
|
||||
if (usb_disabled())
|
||||
@ -253,8 +253,8 @@ module_init (ohci_hcd_pci_init);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void __exit ohci_hcd_pci_cleanup (void)
|
||||
{
|
||||
static void __exit ohci_hcd_pci_cleanup (void)
|
||||
{
|
||||
pci_unregister_driver (&ohci_pci_driver);
|
||||
}
|
||||
module_exit (ohci_hcd_pci_cleanup);
|
||||
|
@ -4,7 +4,7 @@
|
||||
* driver for Philips PNX4008 USB Host
|
||||
*
|
||||
* Authors: Dmitry Chigirev <source@mvista.com>
|
||||
* Vitaly Wool <vitalywool@gmail.com>
|
||||
* Vitaly Wool <vitalywool@gmail.com>
|
||||
*
|
||||
* register initialization is based on code examples provided by Philips
|
||||
* Copyright (c) 2005 Koninklijke Philips Electronics N.V.
|
||||
@ -29,7 +29,7 @@
|
||||
#include <asm/arch/irqs.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
|
||||
#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
|
||||
#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
|
||||
|
||||
/* USB_CTRL bit defines */
|
||||
#define USB_SLAVE_HCLK_EN (1 << 24)
|
||||
|
258
drivers/usb/host/ohci-pnx8550.c
Normal file
258
drivers/usb/host/ohci-pnx8550.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
|
||||
* (C) Copyright 2002 Hewlett-Packard Company
|
||||
* (C) Copyright 2005 Embedded Alley Solutions, Inc.
|
||||
*
|
||||
* Bus Glue for PNX8550
|
||||
*
|
||||
* Written by Christopher Hoover <ch@hpl.hp.com>
|
||||
* Based on fragments of previous driver by Russell King et al.
|
||||
*
|
||||
* Modified for LH7A404 from ohci-sa1111.c
|
||||
* by Durgesh Pattamatta <pattamattad@sharpsec.com>
|
||||
*
|
||||
* Modified for PNX8550 from ohci-sa1111.c and sa-omap.c
|
||||
* by Vitaly Wool <vitalywool@gmail.com>
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/mach-pnx8550/usb.h>
|
||||
#include <asm/mach-pnx8550/int.h>
|
||||
#include <asm/mach-pnx8550/pci.h>
|
||||
|
||||
#ifndef CONFIG_PNX8550
|
||||
#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined."
|
||||
#endif
|
||||
|
||||
extern int usb_disabled(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void pnx8550_start_hc(struct platform_device *dev)
|
||||
{
|
||||
/*
|
||||
* Set register CLK48CTL to enable and 48MHz
|
||||
*/
|
||||
outl(0x00000003, PCI_BASE | 0x0004770c);
|
||||
|
||||
/*
|
||||
* Set register CLK12CTL to enable and 48MHz
|
||||
*/
|
||||
outl(0x00000003, PCI_BASE | 0x00047710);
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
static void pnx8550_stop_hc(struct platform_device *dev)
|
||||
{
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* configure so an HC device and id are always provided */
|
||||
/* always called with process context; sleeping is OK */
|
||||
|
||||
|
||||
/**
|
||||
* usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Allocates basic resources for this USB host controller, and
|
||||
* then invokes the start() method for the HCD associated with it
|
||||
* through the hotplug entry's driver_data.
|
||||
*
|
||||
*/
|
||||
int usb_hcd_pnx8550_probe (const struct hc_driver *driver,
|
||||
struct platform_device *dev)
|
||||
{
|
||||
int retval;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
if (dev->resource[0].flags != IORESOURCE_MEM ||
|
||||
dev->resource[1].flags != IORESOURCE_IRQ) {
|
||||
dev_err (&dev->dev,"invalid resource type\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd (driver, &dev->dev, "pnx8550");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
hcd->rsrc_start = dev->resource[0].start;
|
||||
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
dev_err(&dev->dev, "request_mem_region [0x%08llx, 0x%08llx] "
|
||||
"failed\n", hcd->rsrc_start, hcd->rsrc_len);
|
||||
retval = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
dev_err(&dev->dev, "ioremap [[0x%08llx, 0x%08llx] failed\n",
|
||||
hcd->rsrc_start, hcd->rsrc_len);
|
||||
retval = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
pnx8550_start_hc(dev);
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
pnx8550_stop_hc(dev);
|
||||
iounmap(hcd->regs);
|
||||
err2:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err1:
|
||||
usb_put_hcd(hcd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* may be called without controller electrically present */
|
||||
/* may be called with controller, bus, and devices active */
|
||||
|
||||
/**
|
||||
* usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs
|
||||
* @dev: USB Host Controller being removed
|
||||
* Context: !in_interrupt()
|
||||
*
|
||||
* Reverses the effect of usb_hcd_pnx8550_probe(), first invoking
|
||||
* the HCD's stop() method. It is always called from a thread
|
||||
* context, normally "rmmod", "apmd", or something similar.
|
||||
*
|
||||
*/
|
||||
void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev)
|
||||
{
|
||||
usb_remove_hcd(hcd);
|
||||
pnx8550_stop_hc(dev);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __devinit
|
||||
ohci_pnx8550_start (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
int ret;
|
||||
|
||||
ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci);
|
||||
|
||||
if ((ret = ohci_init(ohci)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = ohci_run (ohci)) < 0) {
|
||||
err ("can't start %s", hcd->self.bus_name);
|
||||
ohci_stop (hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static const struct hc_driver ohci_pnx8550_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "PNX8550 OHCI",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ohci_irq,
|
||||
.flags = HCD_USB11 | HCD_MEMORY,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.start = ohci_pnx8550_start,
|
||||
.stop = ohci_stop,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ohci_urb_enqueue,
|
||||
.urb_dequeue = ohci_urb_dequeue,
|
||||
.endpoint_disable = ohci_endpoint_disable,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ohci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
.hub_irq_enable = ohci_rhsc_enable,
|
||||
#ifdef CONFIG_PM
|
||||
.bus_suspend = ohci_bus_suspend,
|
||||
.bus_resume = ohci_bus_resume,
|
||||
#endif
|
||||
.start_port_reset = ohci_start_port_reset,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int ohci_hcd_pnx8550_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_hcd_pnx8550_remove(hcd, pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("pnx8550-ohci");
|
||||
|
||||
static struct platform_driver ohci_hcd_pnx8550_driver = {
|
||||
.driver = {
|
||||
.name = "pnx8550-ohci",
|
||||
},
|
||||
.probe = ohci_hcd_pnx8550_drv_probe,
|
||||
.remove = ohci_hcd_pnx8550_drv_remove,
|
||||
};
|
||||
|
||||
static int __init ohci_hcd_pnx8550_init (void)
|
||||
{
|
||||
pr_debug (DRIVER_INFO " (pnx8550)");
|
||||
pr_debug ("block sizes: ed %d td %d\n",
|
||||
sizeof (struct ed), sizeof (struct td));
|
||||
|
||||
return platform_driver_register(&ohci_hcd_pnx8550_driver);
|
||||
}
|
||||
|
||||
static void __exit ohci_hcd_pnx8550_cleanup (void)
|
||||
{
|
||||
platform_driver_unregister(&ohci_hcd_pnx8550_driver);
|
||||
}
|
||||
|
||||
module_init (ohci_hcd_pnx8550_init);
|
||||
module_exit (ohci_hcd_pnx8550_cleanup);
|
@ -5,7 +5,7 @@
|
||||
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
|
||||
* (C) Copyright 2002 Hewlett-Packard Company
|
||||
* (C) Copyright 2003-2005 MontaVista Software Inc.
|
||||
*
|
||||
*
|
||||
* Bus Glue for PPC On-Chip OHCI driver
|
||||
* Tested on Freescale MPC5200 and IBM STB04xxx
|
||||
*
|
||||
@ -85,7 +85,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
|
||||
err2:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err1:
|
||||
usb_put_hcd(hcd);
|
||||
usb_put_hcd(hcd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
|
||||
*/
|
||||
.start = ohci_ppc_soc_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
@ -197,7 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
|
||||
static struct platform_driver ohci_hcd_ppc_soc_driver = {
|
||||
.probe = ohci_hcd_ppc_soc_drv_probe,
|
||||
.remove = ohci_hcd_ppc_soc_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
#ifdef CONFIG_PM
|
||||
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
|
||||
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/
|
||||
|
@ -47,7 +47,7 @@ static int pxa27x_ohci_select_pmm( int mode )
|
||||
switch ( mode ) {
|
||||
case PMM_NPS_MODE:
|
||||
UHCRHDA |= RH_A_NPS;
|
||||
break;
|
||||
break;
|
||||
case PMM_GLOBAL_MODE:
|
||||
UHCRHDA &= ~(RH_A_NPS & RH_A_PSM);
|
||||
break;
|
||||
@ -60,7 +60,7 @@ static int pxa27x_ohci_select_pmm( int mode )
|
||||
break;
|
||||
default:
|
||||
printk( KERN_ERR
|
||||
"Invalid mode %d, set to non-power switch mode.\n",
|
||||
"Invalid mode %d, set to non-power switch mode.\n",
|
||||
mode );
|
||||
|
||||
UHCRHDA |= RH_A_NPS;
|
||||
@ -270,7 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
|
||||
*/
|
||||
.start = ohci_pxa27x_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
@ -359,9 +359,9 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
|
||||
static struct platform_driver ohci_hcd_pxa27x_driver = {
|
||||
.probe = ohci_hcd_pxa27x_drv_probe,
|
||||
.remove = ohci_hcd_pxa27x_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ohci_hcd_pxa27x_drv_suspend,
|
||||
.suspend = ohci_hcd_pxa27x_drv_suspend,
|
||||
.resume = ohci_hcd_pxa27x_drv_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
@ -89,7 +89,7 @@ __acquires(ohci->lock)
|
||||
|
||||
/*-------------------------------------------------------------------------*
|
||||
* ED handling functions
|
||||
*-------------------------------------------------------------------------*/
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
/* search for the right schedule branch to use for a periodic ed.
|
||||
* does some load balancing; returns the branch, or negative errno.
|
||||
@ -107,7 +107,6 @@ static int balance (struct ohci_hcd *ohci, int interval, int load)
|
||||
*/
|
||||
for (i = 0; i < interval ; i++) {
|
||||
if (branch < 0 || ohci->load [branch] > ohci->load [i]) {
|
||||
#if 1 /* CONFIG_USB_BANDWIDTH */
|
||||
int j;
|
||||
|
||||
/* usb 1.1 says 90% of one frame */
|
||||
@ -117,8 +116,7 @@ static int balance (struct ohci_hcd *ohci, int interval, int load)
|
||||
}
|
||||
if (j < NUM_INTS)
|
||||
continue;
|
||||
#endif
|
||||
branch = i;
|
||||
branch = i;
|
||||
}
|
||||
}
|
||||
return branch;
|
||||
@ -171,7 +169,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
|
||||
/* link an ed into one of the HC chains */
|
||||
|
||||
static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
|
||||
{
|
||||
{
|
||||
int branch;
|
||||
|
||||
if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING)
|
||||
@ -248,7 +246,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
|
||||
}
|
||||
ed->branch = branch;
|
||||
periodic_link (ohci, ed);
|
||||
}
|
||||
}
|
||||
|
||||
/* the HC may not see the schedule updates yet, but if it does
|
||||
* then they'll be properly ordered.
|
||||
@ -277,7 +275,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
|
||||
*prev = ed->ed_next;
|
||||
}
|
||||
ohci->load [i] -= ed->load;
|
||||
}
|
||||
}
|
||||
ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval;
|
||||
|
||||
ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",
|
||||
@ -285,7 +283,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
|
||||
ed, ed->branch, ed->load, ed->interval);
|
||||
}
|
||||
|
||||
/* unlink an ed from one of the HC chains.
|
||||
/* unlink an ed from one of the HC chains.
|
||||
* just the link to the ed is unlinked.
|
||||
* the link from the ed still points to another operational ed or 0
|
||||
* so the HC can eventually finish the processing of the unlinked ed
|
||||
@ -307,7 +305,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
|
||||
* When finish_unlinks() runs later, after SOF interrupt, it will often
|
||||
* complete one or more URB unlinks before making that state change.
|
||||
*/
|
||||
static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
|
||||
static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
|
||||
{
|
||||
ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
|
||||
wmb ();
|
||||
@ -397,7 +395,7 @@ static struct ed *ed_get (
|
||||
unsigned int pipe,
|
||||
int interval
|
||||
) {
|
||||
struct ed *ed;
|
||||
struct ed *ed;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave (&ohci->lock, flags);
|
||||
@ -413,9 +411,9 @@ static struct ed *ed_get (
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* dummy td; end of td list for ed */
|
||||
/* dummy td; end of td list for ed */
|
||||
td = td_alloc (ohci, GFP_ATOMIC);
|
||||
if (!td) {
|
||||
if (!td) {
|
||||
/* out of memory */
|
||||
ed_free (ohci, ed);
|
||||
ed = NULL;
|
||||
@ -462,7 +460,7 @@ static struct ed *ed_get (
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore (&ohci->lock, flags);
|
||||
return ed;
|
||||
return ed;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -474,7 +472,7 @@ done:
|
||||
* and that ed->state is ED_OPER
|
||||
*/
|
||||
static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
|
||||
{
|
||||
{
|
||||
ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE);
|
||||
ed_deschedule (ohci, ed);
|
||||
|
||||
@ -541,7 +539,7 @@ td_fill (struct ohci_hcd *ohci, u32 info,
|
||||
td->ed = urb_priv->ed;
|
||||
td->next_dl_td = NULL;
|
||||
td->index = index;
|
||||
td->urb = urb;
|
||||
td->urb = urb;
|
||||
td->data_dma = data;
|
||||
if (!len)
|
||||
data = 0;
|
||||
@ -553,8 +551,8 @@ td_fill (struct ohci_hcd *ohci, u32 info,
|
||||
(data & 0x0FFF) | 0xE000);
|
||||
td->ed->last_iso = info & 0xffff;
|
||||
} else {
|
||||
td->hwCBP = cpu_to_hc32 (ohci, data);
|
||||
}
|
||||
td->hwCBP = cpu_to_hc32 (ohci, data);
|
||||
}
|
||||
if (data)
|
||||
td->hwBE = cpu_to_hc32 (ohci, data + len - 1);
|
||||
else
|
||||
@ -597,7 +595,7 @@ static void td_submit_urb (
|
||||
* use the device toggle bits for resetting, and rely on the fact
|
||||
* that resetting toggle is meaningless if the endpoint is active.
|
||||
*/
|
||||
if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
|
||||
if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) {
|
||||
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
|
||||
is_out, 1);
|
||||
urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C);
|
||||
@ -721,16 +719,16 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
|
||||
list_del (&td->td_list);
|
||||
|
||||
/* ISO ... drivers see per-TD length/status */
|
||||
if (tdINFO & TD_ISO) {
|
||||
u16 tdPSW = ohci_hwPSW (ohci, td, 0);
|
||||
if (tdINFO & TD_ISO) {
|
||||
u16 tdPSW = ohci_hwPSW (ohci, td, 0);
|
||||
int dlen = 0;
|
||||
|
||||
/* NOTE: assumes FC in tdINFO == 0, and that
|
||||
* only the first of 0..MAXPSW psws is used.
|
||||
*/
|
||||
|
||||
cc = (tdPSW >> 12) & 0xF;
|
||||
if (tdINFO & TD_CC) /* hc didn't touch? */
|
||||
cc = (tdPSW >> 12) & 0xF;
|
||||
if (tdINFO & TD_CC) /* hc didn't touch? */
|
||||
return;
|
||||
|
||||
if (usb_pipeout (urb->pipe))
|
||||
@ -758,7 +756,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
|
||||
int type = usb_pipetype (urb->pipe);
|
||||
u32 tdBE = hc32_to_cpup (ohci, &td->hwBE);
|
||||
|
||||
cc = TD_CC_GET (tdINFO);
|
||||
cc = TD_CC_GET (tdINFO);
|
||||
|
||||
/* update packet status if needed (short is normally ok) */
|
||||
if (cc == TD_DATAUNDERRUN
|
||||
@ -787,7 +785,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
|
||||
urb, td, 1 + td->index, cc,
|
||||
urb->actual_length,
|
||||
urb->transfer_buffer_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -795,7 +793,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
|
||||
static inline struct td *
|
||||
ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
|
||||
{
|
||||
struct urb *urb = td->urb;
|
||||
struct urb *urb = td->urb;
|
||||
struct ed *ed = td->ed;
|
||||
struct list_head *tmp = td->td_list.next;
|
||||
__hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
|
||||
@ -805,7 +803,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
|
||||
*/
|
||||
ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP);
|
||||
wmb ();
|
||||
ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
|
||||
ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
|
||||
|
||||
/* put any later tds from this urb onto the donelist, after 'td',
|
||||
* order won't matter here: no errors, and nothing was transferred.
|
||||
@ -833,7 +831,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
|
||||
info &= ~cpu_to_hc32 (ohci, TD_CC);
|
||||
next->hwINFO = info;
|
||||
|
||||
next->next_dl_td = rev;
|
||||
next->next_dl_td = rev;
|
||||
rev = next;
|
||||
|
||||
ed->hwHeadP = next->hwNextTD | toggle;
|
||||
@ -881,8 +879,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
|
||||
/* get TD from hc's singly linked list, and
|
||||
* prepend to ours. ed->td_list changes later.
|
||||
*/
|
||||
while (td_dma) {
|
||||
int cc;
|
||||
while (td_dma) {
|
||||
int cc;
|
||||
|
||||
td = dma_to_td (ohci, td_dma);
|
||||
if (!td) {
|
||||
@ -901,10 +899,10 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
|
||||
&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
|
||||
td_rev = ed_halted (ohci, td, cc, td_rev);
|
||||
|
||||
td->next_dl_td = td_rev;
|
||||
td->next_dl_td = td_rev;
|
||||
td_rev = td;
|
||||
td_dma = hc32_to_cpup (ohci, &td->hwNextTD);
|
||||
}
|
||||
}
|
||||
return td_rev;
|
||||
}
|
||||
|
||||
@ -1013,9 +1011,9 @@ rescan_this:
|
||||
|
||||
if (modified)
|
||||
goto rescan_all;
|
||||
}
|
||||
}
|
||||
|
||||
/* maybe reenable control and bulk lists */
|
||||
/* maybe reenable control and bulk lists */
|
||||
if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
|
||||
&& ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
|
||||
&& !ohci->ed_rm_list) {
|
||||
@ -1041,20 +1039,20 @@ rescan_this:
|
||||
&ohci->regs->ed_bulkcurrent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
|
||||
if (control) {
|
||||
ohci->hc_control |= control;
|
||||
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
|
||||
mdelay(1);
|
||||
ohci_writel (ohci, ohci->hc_control,
|
||||
&ohci->regs->control);
|
||||
}
|
||||
ohci_writel (ohci, ohci->hc_control,
|
||||
&ohci->regs->control);
|
||||
}
|
||||
if (command) {
|
||||
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
|
||||
mdelay(1);
|
||||
ohci_writel (ohci, command, &ohci->regs->cmdstatus);
|
||||
}
|
||||
ohci_writel (ohci, command, &ohci->regs->cmdstatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1074,19 +1072,19 @@ dl_done_list (struct ohci_hcd *ohci)
|
||||
{
|
||||
struct td *td = dl_reverse_done_list (ohci);
|
||||
|
||||
while (td) {
|
||||
while (td) {
|
||||
struct td *td_next = td->next_dl_td;
|
||||
struct urb *urb = td->urb;
|
||||
urb_priv_t *urb_priv = urb->hcpriv;
|
||||
struct ed *ed = td->ed;
|
||||
|
||||
/* update URB's length and status from TD */
|
||||
td_done (ohci, urb, td);
|
||||
urb_priv->td_cnt++;
|
||||
td_done (ohci, urb, td);
|
||||
urb_priv->td_cnt++;
|
||||
|
||||
/* If all this urb's TDs are done, call complete() */
|
||||
if (urb_priv->td_cnt == urb_priv->length)
|
||||
finish_urb (ohci, urb);
|
||||
if (urb_priv->td_cnt == urb_priv->length)
|
||||
finish_urb (ohci, urb);
|
||||
|
||||
/* clean schedule: unlink EDs that are no longer busy */
|
||||
if (list_empty (&ed->td_list)) {
|
||||
@ -1094,25 +1092,26 @@ dl_done_list (struct ohci_hcd *ohci)
|
||||
start_ed_unlink (ohci, ed);
|
||||
|
||||
/* ... reenabling halted EDs only after fault cleanup */
|
||||
} else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE))
|
||||
} else if ((ed->hwINFO & cpu_to_hc32 (ohci,
|
||||
ED_SKIP | ED_DEQUEUE))
|
||||
== cpu_to_hc32 (ohci, ED_SKIP)) {
|
||||
td = list_entry (ed->td_list.next, struct td, td_list);
|
||||
if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
|
||||
if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
|
||||
ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
|
||||
/* ... hc may need waking-up */
|
||||
switch (ed->type) {
|
||||
case PIPE_CONTROL:
|
||||
ohci_writel (ohci, OHCI_CLF,
|
||||
&ohci->regs->cmdstatus);
|
||||
&ohci->regs->cmdstatus);
|
||||
break;
|
||||
case PIPE_BULK:
|
||||
ohci_writel (ohci, OHCI_BLF,
|
||||
&ohci->regs->cmdstatus);
|
||||
&ohci->regs->cmdstatus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td = td_next;
|
||||
}
|
||||
td = td_next;
|
||||
}
|
||||
}
|
||||
|
@ -447,7 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
|
||||
*/
|
||||
.start = ohci_s3c2410_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.shutdown = ohci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
@ -492,7 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
|
||||
static struct platform_driver ohci_hcd_s3c2410_driver = {
|
||||
.probe = ohci_hcd_s3c2410_drv_probe,
|
||||
.remove = ohci_hcd_s3c2410_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
|
||||
/*.resume = ohci_hcd_s3c2410_drv_resume, */
|
||||
.driver = {
|
||||
|
@ -4,7 +4,7 @@
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
|
||||
* (C) Copyright 2002 Hewlett-Packard Company
|
||||
*
|
||||
*
|
||||
* SA1111 Bus Glue
|
||||
*
|
||||
* Written by Christopher Hoover <ch@hpl.hp.com>
|
||||
@ -12,7 +12,7 @@
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/arch/assabet.h>
|
||||
@ -31,7 +31,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
|
||||
{
|
||||
unsigned int usb_rst = 0;
|
||||
|
||||
printk(KERN_DEBUG __FILE__
|
||||
printk(KERN_DEBUG __FILE__
|
||||
": starting SA-1111 OHCI USB Controller\n");
|
||||
|
||||
#ifdef CONFIG_SA1100_BADGE4
|
||||
@ -65,7 +65,7 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
|
||||
static void sa1111_stop_hc(struct sa1111_dev *dev)
|
||||
{
|
||||
unsigned int usb_rst;
|
||||
printk(KERN_DEBUG __FILE__
|
||||
printk(KERN_DEBUG __FILE__
|
||||
": stopping SA-1111 OHCI USB Controller\n");
|
||||
|
||||
/*
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* OHCI HCD (Host Controller Driver) for USB.
|
||||
*
|
||||
*
|
||||
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
|
||||
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
|
||||
*
|
||||
*
|
||||
* This file is licenced under the GPL.
|
||||
*/
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
*/
|
||||
typedef __u32 __bitwise __hc32;
|
||||
typedef __u16 __bitwise __hc16;
|
||||
|
||||
|
||||
/*
|
||||
* OHCI Endpoint Descriptor (ED) ... holds TD queue
|
||||
* See OHCI spec, section 4.2
|
||||
@ -24,7 +24,7 @@ typedef __u16 __bitwise __hc16;
|
||||
*/
|
||||
struct ed {
|
||||
/* first fields are hardware-specified */
|
||||
__hc32 hwINFO; /* endpoint config bitmap */
|
||||
__hc32 hwINFO; /* endpoint config bitmap */
|
||||
/* info bits defined by hcd */
|
||||
#define ED_DEQUEUE (1 << 27)
|
||||
/* info bits defined by the hardware */
|
||||
@ -52,11 +52,11 @@ struct ed {
|
||||
* usually: OPER --> UNLINK --> (IDLE | OPER) --> ...
|
||||
*/
|
||||
u8 state; /* ED_{IDLE,UNLINK,OPER} */
|
||||
#define ED_IDLE 0x00 /* NOT linked to HC */
|
||||
#define ED_UNLINK 0x01 /* being unlinked from hc */
|
||||
#define ED_IDLE 0x00 /* NOT linked to HC */
|
||||
#define ED_UNLINK 0x01 /* being unlinked from hc */
|
||||
#define ED_OPER 0x02 /* IS linked to hc */
|
||||
|
||||
u8 type; /* PIPE_{BULK,...} */
|
||||
u8 type; /* PIPE_{BULK,...} */
|
||||
|
||||
/* periodic scheduling params (for intr and iso) */
|
||||
u8 branch;
|
||||
@ -70,7 +70,7 @@ struct ed {
|
||||
|
||||
#define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* OHCI Transfer Descriptor (TD) ... one per transfer segment
|
||||
* See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt)
|
||||
@ -107,22 +107,22 @@ struct td {
|
||||
|
||||
/* (no hwINFO #defines yet for iso tds) */
|
||||
|
||||
__hc32 hwCBP; /* Current Buffer Pointer (or 0) */
|
||||
__hc32 hwNextTD; /* Next TD Pointer */
|
||||
__hc32 hwBE; /* Memory Buffer End Pointer */
|
||||
__hc32 hwCBP; /* Current Buffer Pointer (or 0) */
|
||||
__hc32 hwNextTD; /* Next TD Pointer */
|
||||
__hc32 hwBE; /* Memory Buffer End Pointer */
|
||||
|
||||
/* PSW is only for ISO. Only 1 PSW entry is used, but on
|
||||
* big-endian PPC hardware that's the second entry.
|
||||
*/
|
||||
#define MAXPSW 2
|
||||
__hc16 hwPSW [MAXPSW];
|
||||
__hc16 hwPSW [MAXPSW];
|
||||
|
||||
/* rest are purely for the driver's use */
|
||||
__u8 index;
|
||||
struct ed *ed;
|
||||
struct td *td_hash; /* dma-->td hashtable */
|
||||
struct td *next_dl_td;
|
||||
struct urb *urb;
|
||||
__u8 index;
|
||||
struct ed *ed;
|
||||
struct td *td_hash; /* dma-->td hashtable */
|
||||
struct td *next_dl_td;
|
||||
struct urb *urb;
|
||||
|
||||
dma_addr_t td_dma; /* addr of this TD */
|
||||
dma_addr_t data_dma; /* addr of data it points to */
|
||||
@ -152,8 +152,8 @@ struct td {
|
||||
#define TD_NOTACCESSED 0x0F
|
||||
|
||||
|
||||
/* map OHCI TD status codes (CC) to errno values */
|
||||
static const int cc_to_error [16] = {
|
||||
/* map OHCI TD status codes (CC) to errno values */
|
||||
static const int cc_to_error [16] = {
|
||||
/* No Error */ 0,
|
||||
/* CRC Error */ -EILSEQ,
|
||||
/* Bit Stuff */ -EPROTO,
|
||||
@ -169,7 +169,7 @@ static const int cc_to_error [16] = {
|
||||
/* BufferOver */ -ECOMM,
|
||||
/* BuffUnder */ -ENOSR,
|
||||
/* (for HCD) */ -EALREADY,
|
||||
/* (for HCD) */ -EALREADY
|
||||
/* (for HCD) */ -EALREADY
|
||||
};
|
||||
|
||||
|
||||
@ -182,7 +182,7 @@ struct ohci_hcca {
|
||||
#define NUM_INTS 32
|
||||
__hc32 int_table [NUM_INTS]; /* periodic schedule */
|
||||
|
||||
/*
|
||||
/*
|
||||
* OHCI defines u16 frame_no, followed by u16 zero pad.
|
||||
* Since some processors can't do 16 bit bus accesses,
|
||||
* portable access must be a 32 bits wide.
|
||||
@ -262,10 +262,10 @@ struct ohci_regs {
|
||||
* HcCommandStatus (cmdstatus) register masks
|
||||
*/
|
||||
#define OHCI_HCR (1 << 0) /* host controller reset */
|
||||
#define OHCI_CLF (1 << 1) /* control list filled */
|
||||
#define OHCI_BLF (1 << 2) /* bulk list filled */
|
||||
#define OHCI_OCR (1 << 3) /* ownership change request */
|
||||
#define OHCI_SOC (3 << 16) /* scheduling overrun count */
|
||||
#define OHCI_CLF (1 << 1) /* control list filled */
|
||||
#define OHCI_BLF (1 << 2) /* bulk list filled */
|
||||
#define OHCI_OCR (1 << 3) /* ownership change request */
|
||||
#define OHCI_SOC (3 << 16) /* scheduling overrun count */
|
||||
|
||||
/*
|
||||
* masks used with interrupt registers:
|
||||
@ -285,20 +285,20 @@ struct ohci_regs {
|
||||
|
||||
|
||||
/* OHCI ROOT HUB REGISTER MASKS */
|
||||
|
||||
|
||||
/* roothub.portstatus [i] bits */
|
||||
#define RH_PS_CCS 0x00000001 /* current connect status */
|
||||
#define RH_PS_PES 0x00000002 /* port enable status*/
|
||||
#define RH_PS_PSS 0x00000004 /* port suspend status */
|
||||
#define RH_PS_POCI 0x00000008 /* port over current indicator */
|
||||
#define RH_PS_PRS 0x00000010 /* port reset status */
|
||||
#define RH_PS_PPS 0x00000100 /* port power status */
|
||||
#define RH_PS_LSDA 0x00000200 /* low speed device attached */
|
||||
#define RH_PS_CSC 0x00010000 /* connect status change */
|
||||
#define RH_PS_PESC 0x00020000 /* port enable status change */
|
||||
#define RH_PS_PSSC 0x00040000 /* port suspend status change */
|
||||
#define RH_PS_OCIC 0x00080000 /* over current indicator change */
|
||||
#define RH_PS_PRSC 0x00100000 /* port reset status change */
|
||||
#define RH_PS_CCS 0x00000001 /* current connect status */
|
||||
#define RH_PS_PES 0x00000002 /* port enable status*/
|
||||
#define RH_PS_PSS 0x00000004 /* port suspend status */
|
||||
#define RH_PS_POCI 0x00000008 /* port over current indicator */
|
||||
#define RH_PS_PRS 0x00000010 /* port reset status */
|
||||
#define RH_PS_PPS 0x00000100 /* port power status */
|
||||
#define RH_PS_LSDA 0x00000200 /* low speed device attached */
|
||||
#define RH_PS_CSC 0x00010000 /* connect status change */
|
||||
#define RH_PS_PESC 0x00020000 /* port enable status change */
|
||||
#define RH_PS_PSSC 0x00040000 /* port suspend status change */
|
||||
#define RH_PS_OCIC 0x00080000 /* over current indicator change */
|
||||
#define RH_PS_PRSC 0x00100000 /* port reset status change */
|
||||
|
||||
/* roothub.status bits */
|
||||
#define RH_HS_LPS 0x00000001 /* local power status */
|
||||
@ -333,7 +333,7 @@ typedef struct urb_priv {
|
||||
} urb_priv_t;
|
||||
|
||||
#define TD_HASH_SIZE 64 /* power'o'two */
|
||||
// sizeof (struct td) ~= 64 == 2^6 ...
|
||||
// sizeof (struct td) ~= 64 == 2^6 ...
|
||||
#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
|
||||
|
||||
|
||||
@ -364,11 +364,11 @@ struct ohci_hcd {
|
||||
|
||||
struct ed *ed_bulktail; /* last in bulk list */
|
||||
struct ed *ed_controltail; /* last in ctrl list */
|
||||
struct ed *periodic [NUM_INTS]; /* shadow int_table */
|
||||
struct ed *periodic [NUM_INTS]; /* shadow int_table */
|
||||
|
||||
/*
|
||||
* OTG controllers and transceivers need software interaction;
|
||||
* other external transceivers should be software-transparent
|
||||
* other external transceivers should be software-transparent
|
||||
*/
|
||||
struct otg_transceiver *transceiver;
|
||||
|
||||
@ -385,7 +385,7 @@ struct ohci_hcd {
|
||||
*/
|
||||
int num_ports;
|
||||
int load [NUM_INTS];
|
||||
u32 hc_control; /* copy of hc control reg */
|
||||
u32 hc_control; /* copy of hc control reg */
|
||||
unsigned long next_statechange; /* suspend/resume */
|
||||
u32 fminterval; /* saved register */
|
||||
unsigned autostop:1; /* rh auto stopping/stopped */
|
||||
@ -598,11 +598,11 @@ static inline void disable (struct ohci_hcd *ohci)
|
||||
}
|
||||
|
||||
#define FI 0x2edf /* 12000 bits per frame (-1) */
|
||||
#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7))
|
||||
#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7))
|
||||
#define FIT (1 << 31)
|
||||
#define LSTHRESH 0x628 /* lowspeed bit threshold */
|
||||
|
||||
static void periodic_reinit (struct ohci_hcd *ohci)
|
||||
static inline void periodic_reinit (struct ohci_hcd *ohci)
|
||||
{
|
||||
u32 fi = ohci->fminterval & 0x03fff;
|
||||
u32 fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT;
|
||||
@ -626,11 +626,11 @@ static void periodic_reinit (struct ohci_hcd *ohci)
|
||||
temp = ohci_readl (hc, &hc->regs->roothub.register); \
|
||||
temp; })
|
||||
|
||||
static u32 roothub_a (struct ohci_hcd *hc)
|
||||
static inline u32 roothub_a (struct ohci_hcd *hc)
|
||||
{ return read_roothub (hc, a, 0xfc0fe000); }
|
||||
static inline u32 roothub_b (struct ohci_hcd *hc)
|
||||
{ return ohci_readl (hc, &hc->regs->roothub.b); }
|
||||
static inline u32 roothub_status (struct ohci_hcd *hc)
|
||||
{ return ohci_readl (hc, &hc->regs->roothub.status); }
|
||||
static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
|
||||
static inline u32 roothub_portstatus (struct ohci_hcd *hc, int i)
|
||||
{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
@ -210,15 +211,16 @@ struct u132 {
|
||||
* these cannot be inlines because we need the structure offset!!
|
||||
* Does anyone have a better way?????
|
||||
*/
|
||||
#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \
|
||||
offsetof(struct ohci_regs, member), 0, data);
|
||||
#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \
|
||||
offsetof(struct ohci_regs, member), 0, data);
|
||||
#define u132_read_pcimem(u132, member, data) \
|
||||
usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
|
||||
ohci_regs, member), 0, data);
|
||||
#define u132_write_pcimem(u132, member, data) \
|
||||
usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
|
||||
ohci_regs, member), 0, data);
|
||||
#define u132_write_pcimem_byte(u132, member, data) \
|
||||
usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
|
||||
ohci_regs, member), 0x0e, data);
|
||||
static inline struct u132 *udev_to_u132(struct u132_udev *udev)
|
||||
{
|
||||
u8 udev_number = udev->udev_number;
|
||||
@ -1574,59 +1576,12 @@ static char *hcfs2string(int state)
|
||||
return "?";
|
||||
}
|
||||
|
||||
static int u132_usb_reset(struct u132 *u132)
|
||||
{
|
||||
int retval;
|
||||
retval = u132_read_pcimem(u132, control, &u132->hc_control);
|
||||
if (retval)
|
||||
return retval;
|
||||
u132->hc_control &= OHCI_CTRL_RWC;
|
||||
retval = u132_write_pcimem(u132, control, u132->hc_control);
|
||||
if (retval)
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int u132_init(struct u132 *u132)
|
||||
{
|
||||
int retval;
|
||||
u32 control;
|
||||
u132_disable(u132);
|
||||
u132->next_statechange =
|
||||
jiffies; /* SMM owns the HC? not for long! */ {
|
||||
u32 control;
|
||||
retval = u132_read_pcimem(u132, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (control & OHCI_CTRL_IR) {
|
||||
u32 temp = 50;
|
||||
retval = u132_write_pcimem(u132, intrenable,
|
||||
OHCI_INTR_OC);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = u132_write_pcimem_byte(u132, cmdstatus,
|
||||
OHCI_OCR);
|
||||
if (retval)
|
||||
return retval;
|
||||
check:{
|
||||
retval = u132_read_pcimem(u132, control,
|
||||
&control);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (control & OHCI_CTRL_IR) {
|
||||
msleep(10);
|
||||
if (--temp == 0) {
|
||||
dev_err(&u132->platform_dev->dev, "USB "
|
||||
"HC takeover failed!(BIOS/SMM b"
|
||||
"ug) control=%08X\n", control);
|
||||
return -EBUSY;
|
||||
}
|
||||
goto check;
|
||||
}
|
||||
u132_usb_reset(u132);
|
||||
}
|
||||
}
|
||||
u132->next_statechange = jiffies;
|
||||
retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
|
||||
if (retval)
|
||||
return retval;
|
||||
@ -1725,7 +1680,7 @@ static int u132_run(struct u132 *u132)
|
||||
retry:retval = u132_read_pcimem(u132, cmdstatus, &status);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR);
|
||||
retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
|
||||
if (retval)
|
||||
return retval;
|
||||
extra:{
|
||||
@ -1782,7 +1737,7 @@ static int u132_run(struct u132 *u132)
|
||||
retval = u132_write_pcimem(u132, control, u132->hc_control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF);
|
||||
retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
|
||||
@ -1839,8 +1794,8 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
|
||||
{
|
||||
struct u132 *u132 = hcd_to_u132(hcd);
|
||||
if (u132->going > 1) {
|
||||
dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
|
||||
, u132->going);
|
||||
dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
|
||||
"een removed %d\n", u132, hcd, u132->going);
|
||||
} else if (u132->going > 0) {
|
||||
dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
|
||||
"ed\n", hcd);
|
||||
@ -2545,8 +2500,9 @@ static void u132_endpoint_disable(struct usb_hcd *hcd,
|
||||
{
|
||||
struct u132 *u132 = hcd_to_u132(hcd);
|
||||
if (u132->going > 2) {
|
||||
dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
|
||||
, u132->going);
|
||||
dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
|
||||
") has been removed %d\n", u132, hcd, hep,
|
||||
u132->going);
|
||||
} else {
|
||||
struct u132_endp *endp = hep->hcpriv;
|
||||
if (endp)
|
||||
@ -2790,7 +2746,6 @@ static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
|
||||
} else if (u132->going > 0) {
|
||||
dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
|
||||
"ed\n", hcd);
|
||||
dump_stack();
|
||||
return -ESHUTDOWN;
|
||||
} else {
|
||||
int i, changed = 0, length = 1;
|
||||
@ -3034,12 +2989,15 @@ static int __devexit u132_remove(struct platform_device *pdev)
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
if (hcd) {
|
||||
struct u132 *u132 = hcd_to_u132(hcd);
|
||||
dump_stack();
|
||||
if (u132->going++ > 1) {
|
||||
dev_err(&u132->platform_dev->dev, "already being remove"
|
||||
"d\n");
|
||||
return -ENODEV;
|
||||
} else {
|
||||
int rings = MAX_U132_RINGS;
|
||||
int endps = MAX_U132_ENDPS;
|
||||
dev_err(&u132->platform_dev->dev, "removing device u132"
|
||||
".%d\n", u132->sequence_num);
|
||||
msleep(100);
|
||||
down(&u132->sw_lock);
|
||||
u132_monitor_cancel_work(u132);
|
||||
@ -3121,10 +3079,24 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
|
||||
static int __devinit u132_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
int retval;
|
||||
u32 control;
|
||||
u32 rh_a = -1;
|
||||
u32 num_ports;
|
||||
msleep(100);
|
||||
if (u132_exiting > 0) {
|
||||
return -ENODEV;
|
||||
} /* refuse to confuse usbcore */
|
||||
}
|
||||
retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(pdev, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
|
||||
if (retval)
|
||||
return retval;
|
||||
num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
|
||||
if (pdev->dev.dma_mask) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -60,6 +60,11 @@ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
|
||||
Alan Stern"
|
||||
#define DRIVER_DESC "USB Universal Host Controller Interface driver"
|
||||
|
||||
/* for flakey hardware, ignore overcurrent indicators */
|
||||
static int ignore_oc;
|
||||
module_param(ignore_oc, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications");
|
||||
|
||||
/*
|
||||
* debug = 0, no debugging messages
|
||||
* debug = 1, dump failed URBs except for stalls
|
||||
@ -169,6 +174,11 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
|
||||
{
|
||||
int port;
|
||||
|
||||
/* If we have to ignore overcurrent events then almost by definition
|
||||
* we can't depend on resume-detect interrupts. */
|
||||
if (ignore_oc)
|
||||
return 1;
|
||||
|
||||
switch (to_pci_dev(uhci_dev(uhci))->vendor) {
|
||||
default:
|
||||
break;
|
||||
@ -921,7 +931,8 @@ static int __init uhci_hcd_init(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
|
||||
printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");
|
||||
printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "%s\n",
|
||||
ignore_oc ? ", overcurrent ignored" : "");
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
@ -52,10 +52,20 @@ static int any_ports_active(struct uhci_hcd *uhci)
|
||||
static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
|
||||
{
|
||||
int port;
|
||||
int mask = RWC_BITS;
|
||||
|
||||
/* Some boards (both VIA and Intel apparently) report bogus
|
||||
* overcurrent indications, causing massive log spam unless
|
||||
* we completely ignore them. This doesn't seem to be a problem
|
||||
* with the chipset so much as with the way it is connected on
|
||||
* the motherboard; if the overcurrent input is left to float
|
||||
* then it may constantly register false positives. */
|
||||
if (ignore_oc)
|
||||
mask &= ~USBPORTSC_OCC;
|
||||
|
||||
*buf = 0;
|
||||
for (port = 0; port < uhci->rh_numports; ++port) {
|
||||
if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) ||
|
||||
if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & mask) ||
|
||||
test_bit(port, &uhci->port_c_suspend))
|
||||
*buf |= (1 << (port + 1));
|
||||
}
|
||||
@ -263,7 +273,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
wPortChange |= USB_PORT_STAT_C_CONNECTION;
|
||||
if (status & USBPORTSC_PEC)
|
||||
wPortChange |= USB_PORT_STAT_C_ENABLE;
|
||||
if (status & USBPORTSC_OCC)
|
||||
if ((status & USBPORTSC_OCC) && !ignore_oc)
|
||||
wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
|
||||
|
||||
if (test_bit(port, &uhci->port_c_suspend)) {
|
||||
|
@ -159,13 +159,13 @@ void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
{
|
||||
input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
|
||||
input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
|
||||
input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
|
||||
}
|
||||
|
||||
void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
{
|
||||
input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
|
||||
input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
|
||||
}
|
||||
|
||||
void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||
|
@ -209,13 +209,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
|
||||
wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
|
||||
}
|
||||
}
|
||||
|
||||
if (data[1] & 0x10)
|
||||
wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
|
||||
}
|
||||
else
|
||||
wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
|
||||
wacom_report_key(wcombo, wacom->tool[0], data[1] & 0x10);
|
||||
|
||||
if (data[1] & 0x10) /* only report prox-in when in area */
|
||||
wacom_report_key(wcombo, wacom->tool[0], 1);
|
||||
if (!(data[1] & 0x90)) /* report prox-out when physically out */
|
||||
wacom_report_key(wcombo, wacom->tool[0], 0);
|
||||
wacom_input_sync(wcombo);
|
||||
|
||||
/* send pad data */
|
||||
@ -405,7 +407,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
|
||||
return 0;
|
||||
|
||||
if (wacom->features->type >= INTUOS3) {
|
||||
if (wacom->features->type >= INTUOS3S) {
|
||||
wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
|
||||
wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
|
||||
wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
|
||||
@ -423,7 +425,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||
|
||||
if (data[1] & 0x02) {
|
||||
/* Rotation packet */
|
||||
if (wacom->features->type >= INTUOS3) {
|
||||
if (wacom->features->type >= INTUOS3S) {
|
||||
/* I3 marker pen rotation reported as wheel
|
||||
* due to valuator limitation
|
||||
*/
|
||||
@ -547,11 +549,11 @@ static struct wacom_features wacom_features[] = {
|
||||
{ "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 },
|
||||
{ "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 },
|
||||
{ "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE },
|
||||
{ "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE },
|
||||
{ "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE },
|
||||
{ "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE },
|
||||
{ "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE },
|
||||
{ "Wacom Volito", 8, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom PenStation2", 8, 3250, 2320, 255, 63, GRAPHIRE },
|
||||
{ "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE },
|
||||
{ "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE },
|
||||
{ "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE },
|
||||
{ "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
|
||||
{ "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
|
||||
{ "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
|
||||
@ -580,7 +582,7 @@ static struct wacom_features wacom_features[] = {
|
||||
{ "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
|
||||
{ "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
|
||||
{ "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
|
||||
{ "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S },
|
||||
{ "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S },
|
||||
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
|
||||
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
|
||||
{ }
|
||||
|
@ -1376,7 +1376,7 @@ static int auerchar_open (struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
/* we have access to the device. Now lets allocate memory */
|
||||
ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL);
|
||||
ccp = kzalloc(sizeof(auerchar_t), GFP_KERNEL);
|
||||
if (ccp == NULL) {
|
||||
err ("out of memory");
|
||||
ret = -ENOMEM;
|
||||
@ -1384,7 +1384,6 @@ static int auerchar_open (struct inode *inode, struct file *file)
|
||||
}
|
||||
|
||||
/* Initialize device descriptor */
|
||||
memset( ccp, 0, sizeof(auerchar_t));
|
||||
init_MUTEX( &ccp->mutex);
|
||||
init_MUTEX( &ccp->readmutex);
|
||||
auerbuf_init (&ccp->bufctl);
|
||||
@ -1912,14 +1911,13 @@ static int auerswald_probe (struct usb_interface *intf,
|
||||
return -ENODEV;
|
||||
|
||||
/* allocate memory for our device and initialize it */
|
||||
cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL);
|
||||
cp = kzalloc (sizeof(auerswald_t), GFP_KERNEL);
|
||||
if (cp == NULL) {
|
||||
err ("out of memory");
|
||||
goto pfail;
|
||||
}
|
||||
|
||||
/* Initialize device descriptor */
|
||||
memset (cp, 0, sizeof(auerswald_t));
|
||||
init_MUTEX (&cp->mutex);
|
||||
cp->usbdev = usbdev;
|
||||
auerchain_init (&cp->controlchain);
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kref.h>
|
||||
@ -51,6 +52,10 @@ MODULE_AUTHOR("Tony Olech");
|
||||
MODULE_DESCRIPTION("FTDI ELAN driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
|
||||
static int distrust_firmware = 1;
|
||||
module_param(distrust_firmware, bool, 0);
|
||||
MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
|
||||
"t setup");
|
||||
extern struct platform_driver u132_platform_driver;
|
||||
static struct workqueue_struct *status_queue;
|
||||
static struct workqueue_struct *command_queue;
|
||||
@ -66,7 +71,9 @@ static struct list_head ftdi_static_list;
|
||||
* end of the global variables protected by ftdi_module_lock
|
||||
*/
|
||||
#include "usb_u132.h"
|
||||
#define TD_DEVNOTRESP 5
|
||||
#include <asm/io.h>
|
||||
#include "../core/hcd.h"
|
||||
#include "../host/ohci.h"
|
||||
/* Define these values to match your devices*/
|
||||
#define USB_FTDI_ELAN_VENDOR_ID 0x0403
|
||||
#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
|
||||
@ -551,7 +558,7 @@ static void ftdi_elan_status_work(struct work_struct *work)
|
||||
} else {
|
||||
dev_err(&ftdi->udev->dev, "initialized failed - trying "
|
||||
"again in 10 seconds\n");
|
||||
work_delay_in_msec = 10 *1000;
|
||||
work_delay_in_msec = 1 *1000;
|
||||
}
|
||||
} else if (ftdi->registered == 0) {
|
||||
work_delay_in_msec = 10;
|
||||
@ -2288,82 +2295,229 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
|
||||
}
|
||||
}
|
||||
|
||||
static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
|
||||
|
||||
#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \
|
||||
offsetof(struct ohci_regs, member), 0, data);
|
||||
#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \
|
||||
offsetof(struct ohci_regs, member), 0, data);
|
||||
#define OHCI_QUIRK_AMD756 0x01
|
||||
#define OHCI_QUIRK_SUPERIO 0x02
|
||||
#define OHCI_QUIRK_INITRESET 0x04
|
||||
#define OHCI_BIG_ENDIAN 0x08
|
||||
#define OHCI_QUIRK_ZFMICRO 0x10
|
||||
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
|
||||
#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
|
||||
OHCI_INTR_WDH)
|
||||
static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk)
|
||||
{
|
||||
int devices = 0;
|
||||
int retval;
|
||||
u32 hc_control;
|
||||
int num_ports;
|
||||
u32 control;
|
||||
u32 rh_a = -1;
|
||||
u32 status;
|
||||
u32 fminterval;
|
||||
u32 hc_fminterval;
|
||||
u32 periodicstart;
|
||||
u32 cmdstatus;
|
||||
u32 roothub_a;
|
||||
int mask = OHCI_INTR_INIT;
|
||||
int sleep_time = 0;
|
||||
int reset_timeout = 30; /* ... allow extra time */
|
||||
int temp;
|
||||
retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a);
|
||||
if (retval)
|
||||
return retval;
|
||||
num_ports = rh_a & RH_A_NDP;
|
||||
retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval);
|
||||
if (retval)
|
||||
return retval;
|
||||
hc_fminterval &= 0x3fff;
|
||||
if (hc_fminterval != FI) {
|
||||
}
|
||||
hc_fminterval |= FSMP(hc_fminterval) << 16;
|
||||
retval = ftdi_read_pcimem(ftdi, control, &hc_control);
|
||||
if (retval)
|
||||
return retval;
|
||||
switch (hc_control & OHCI_CTRL_HCFS) {
|
||||
case OHCI_USB_OPER:
|
||||
sleep_time = 0;
|
||||
break;
|
||||
case OHCI_USB_SUSPEND:
|
||||
case OHCI_USB_RESUME:
|
||||
hc_control &= OHCI_CTRL_RWC;
|
||||
hc_control |= OHCI_USB_RESUME;
|
||||
sleep_time = 10;
|
||||
break;
|
||||
default:
|
||||
hc_control &= OHCI_CTRL_RWC;
|
||||
hc_control |= OHCI_USB_RESET;
|
||||
sleep_time = 50;
|
||||
break;
|
||||
}
|
||||
retval = ftdi_write_pcimem(ftdi, control, hc_control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
msleep(sleep_time);
|
||||
retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (!(roothub_a & RH_A_NPS)) { /* power down each port */
|
||||
for (temp = 0; temp < num_ports; temp++) {
|
||||
retval = ftdi_write_pcimem(ftdi,
|
||||
roothub.portstatus[temp], RH_PS_LSDA);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
retval = ftdi_read_pcimem(ftdi, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR);
|
||||
if (retval)
|
||||
return retval;
|
||||
extra:{
|
||||
retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (0 != (status & OHCI_HCR)) {
|
||||
if (--reset_timeout == 0) {
|
||||
dev_err(&ftdi->udev->dev, "USB HC reset timed o"
|
||||
"ut!\n");
|
||||
return -ENODEV;
|
||||
} else {
|
||||
msleep(5);
|
||||
goto extra;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (quirk & OHCI_QUIRK_INITRESET) {
|
||||
retval = ftdi_write_pcimem(ftdi, control, hc_control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, fminterval,
|
||||
((fminterval & FIT) ^ FIT) | hc_fminterval);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, periodicstart,
|
||||
((9 *hc_fminterval) / 10) & 0x3fff);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
|
||||
if (!(quirk & OHCI_QUIRK_INITRESET)) {
|
||||
quirk |= OHCI_QUIRK_INITRESET;
|
||||
goto retry;
|
||||
} else
|
||||
dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n",
|
||||
fminterval, periodicstart);
|
||||
} /* start controller operations */
|
||||
hc_control &= OHCI_CTRL_RWC;
|
||||
hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
|
||||
retval = ftdi_write_pcimem(ftdi, control, hc_control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, intrstatus, mask);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, intrdisable,
|
||||
OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
|
||||
OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
|
||||
OHCI_INTR_SO);
|
||||
if (retval)
|
||||
return retval; /* handle root hub init quirks ... */
|
||||
retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
|
||||
if (retval)
|
||||
return retval;
|
||||
roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
|
||||
if (quirk & OHCI_QUIRK_SUPERIO) {
|
||||
roothub_a |= RH_A_NOCP;
|
||||
roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
|
||||
retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
|
||||
if (retval)
|
||||
return retval;
|
||||
} else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) {
|
||||
roothub_a |= RH_A_NPS;
|
||||
retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_write_pcimem(ftdi, roothub.b,
|
||||
(roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ftdi_read_pcimem(ftdi, control, &control);
|
||||
if (retval)
|
||||
return retval;
|
||||
mdelay((roothub_a >> 23) & 0x1fe);
|
||||
for (temp = 0; temp < num_ports; temp++) {
|
||||
u32 portstatus;
|
||||
retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp],
|
||||
&portstatus);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (1 & portstatus)
|
||||
devices += 1;
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn)
|
||||
{
|
||||
u32 latence_timer;
|
||||
u32 controlreg;
|
||||
int UxxxStatus;
|
||||
u32 pcidata;
|
||||
int reg = 0;
|
||||
int foundOHCI = 0;
|
||||
u8 fn;
|
||||
int activePCIfn = 0;
|
||||
u32 pciVID = 0;
|
||||
u32 pciPID = 0;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
msleep(750);
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
msleep(250);
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
msleep(1000);
|
||||
for (fn = 0; (fn < 4) && (!foundOHCI); fn++) {
|
||||
activePCIfn = fn << 8;
|
||||
ftdi->function = fn + 1;
|
||||
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
|
||||
&pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
pciVID = pcidata & 0xFFFF;
|
||||
pciPID = (pcidata >> 16) & 0xFFFF;
|
||||
if ((pciVID == 0x1045) && (pciPID == 0xc861)) {
|
||||
foundOHCI = 1;
|
||||
} else if ((pciVID == 0x1033) && (pciPID == 0x0035)) {
|
||||
foundOHCI = 1;
|
||||
} else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) {
|
||||
foundOHCI = 1;
|
||||
} else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) {
|
||||
foundOHCI = 1;
|
||||
} else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) {
|
||||
}
|
||||
}
|
||||
if (foundOHCI == 0) {
|
||||
return -ENXIO;
|
||||
}
|
||||
ftdi->platform_data.vendor = pciVID;
|
||||
ftdi->platform_data.device = pciPID;
|
||||
int activePCIfn = fn << 8;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
@ -2408,162 +2562,201 @@ static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
|
||||
&pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
for (reg = 0; reg <= 0x54; reg += 4) {
|
||||
UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn)
|
||||
{
|
||||
u32 latence_timer;
|
||||
int UxxxStatus;
|
||||
u32 pcidata;
|
||||
int reg = 0;
|
||||
int activePCIfn = fn << 8;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
reg = 16;
|
||||
UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
|
||||
0xFFFFFFFF);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
|
||||
&pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
|
||||
0x00000000);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
|
||||
&pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
reg = 12;
|
||||
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
|
||||
&latence_timer);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
latence_timer &= 0xFFFF00FF;
|
||||
latence_timer |= 0x00001600;
|
||||
UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
|
||||
latence_timer);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
|
||||
&pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
reg = 4;
|
||||
UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
|
||||
0x00);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
|
||||
&pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk)
|
||||
{
|
||||
int result;
|
||||
int UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_setup_controller(ftdi, fn);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
result = ftdi_elan_check_controller(ftdi, quirk);
|
||||
UxxxStatus = ftdi_elan_close_controller(ftdi, fn);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
|
||||
{
|
||||
u32 controlreg;
|
||||
u8 sensebits;
|
||||
int UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
msleep(750);
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
msleep(250);
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
msleep(1000);
|
||||
sensebits = (controlreg >> 16) & 0x000F;
|
||||
if (0x0D == sensebits)
|
||||
return 0;
|
||||
else
|
||||
return - ENXIO;
|
||||
}
|
||||
|
||||
static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)
|
||||
{
|
||||
int UxxxStatus;
|
||||
u32 pcidata;
|
||||
int U132Status;
|
||||
int reg;
|
||||
int reset_repeat = 0;
|
||||
do_reset:reg = 8;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reset_check:{
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
if (pcidata & 1) {
|
||||
msleep(500);
|
||||
if (reset_repeat++ > 100) {
|
||||
reset_repeat = 0;
|
||||
goto do_reset;
|
||||
} else
|
||||
goto reset_check;
|
||||
int reg = 0;
|
||||
u8 fn;
|
||||
int activePCIfn = 0;
|
||||
int max_devices = 0;
|
||||
int controllers = 0;
|
||||
int unrecognized = 0;
|
||||
ftdi->function = 0;
|
||||
for (fn = 0; (fn < 4); fn++) {
|
||||
u32 pciVID = 0;
|
||||
u32 pciPID = 0;
|
||||
int devices = 0;
|
||||
activePCIfn = fn << 8;
|
||||
UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
|
||||
&pcidata);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
pciVID = pcidata & 0xFFFF;
|
||||
pciPID = (pcidata >> 16) & 0xFFFF;
|
||||
if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) {
|
||||
devices = ftdi_elan_found_controller(ftdi, fn, 0);
|
||||
controllers += 1;
|
||||
} else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035))
|
||||
{
|
||||
devices = ftdi_elan_found_controller(ftdi, fn, 0);
|
||||
controllers += 1;
|
||||
} else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) {
|
||||
devices = ftdi_elan_found_controller(ftdi, fn, 0);
|
||||
controllers += 1;
|
||||
} else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802))
|
||||
{
|
||||
devices = ftdi_elan_found_controller(ftdi, fn, 0);
|
||||
controllers += 1;
|
||||
} else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) {
|
||||
devices = ftdi_elan_found_controller(ftdi, fn,
|
||||
OHCI_QUIRK_AMD756);
|
||||
controllers += 1;
|
||||
} else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) {
|
||||
devices = ftdi_elan_found_controller(ftdi, fn,
|
||||
OHCI_QUIRK_ZFMICRO);
|
||||
controllers += 1;
|
||||
} else if (0 == pcidata) {
|
||||
} else
|
||||
unrecognized += 1;
|
||||
if (devices > max_devices) {
|
||||
max_devices = devices;
|
||||
ftdi->function = fn + 1;
|
||||
ftdi->platform_data.vendor = pciVID;
|
||||
ftdi->platform_data.device = pciPID;
|
||||
}
|
||||
}
|
||||
goto dump_regs;
|
||||
msleep(500);
|
||||
reg = 0x28;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x40;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x34;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 4;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
msleep(250);
|
||||
reg = 8;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x28;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 8;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x48;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x54;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x58;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x34;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
msleep(100);
|
||||
reg = 0x50;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x54;
|
||||
power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
if (!(pcidata & 1)) {
|
||||
msleep(500);
|
||||
goto power_check;
|
||||
if (ftdi->function > 0) {
|
||||
UxxxStatus = ftdi_elan_setup_controller(ftdi,
|
||||
ftdi->function - 1);
|
||||
if (UxxxStatus)
|
||||
return UxxxStatus;
|
||||
return 0;
|
||||
} else if (controllers > 0) {
|
||||
return -ENXIO;
|
||||
} else if (unrecognized > 0) {
|
||||
return -ENXIO;
|
||||
} else {
|
||||
ftdi->enumerated = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
msleep(3000);
|
||||
reg = 0x54;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x58;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x54;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x54;
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
msleep(750);
|
||||
reg = 0x54;
|
||||
if (0) {
|
||||
U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
}
|
||||
if (0) {
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
}
|
||||
reg = 0x54;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
reg = 0x58;
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
dump_regs:for (reg = 0; reg <= 0x54; reg += 4) {
|
||||
U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
|
||||
if (U132Status)
|
||||
return U132Status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2688,6 +2881,7 @@ static void ftdi_elan_disconnect(struct usb_interface *interface)
|
||||
platform_device_unregister(&ftdi->platform_dev);
|
||||
ftdi->synchronized = 0;
|
||||
ftdi->enumerated = 0;
|
||||
ftdi->initialized = 0;
|
||||
ftdi->registered = 0;
|
||||
}
|
||||
flush_workqueue(status_queue);
|
||||
|
@ -282,6 +282,7 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
dev->dev = NULL;
|
||||
goto out;
|
||||
}
|
||||
dev_set_drvdata(dev->dev, dev);
|
||||
|
||||
servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
|
||||
|
||||
|
@ -120,8 +120,8 @@ static void tv_disconnect(struct usb_interface *interface)
|
||||
struct trancevibrator *dev;
|
||||
|
||||
dev = usb_get_intfdata (interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
device_remove_file(&interface->dev, &dev_attr_speed);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
usb_put_dev(dev->udev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
@ -79,160 +79,6 @@ struct gl_header {
|
||||
struct gl_packet packets;
|
||||
};
|
||||
|
||||
#ifdef GENELINK_ACK
|
||||
|
||||
// FIXME: this code is incomplete, not debugged; it doesn't
|
||||
// handle interrupts correctly; it should use the generic
|
||||
// status IRQ code (which didn't exist back in 2001).
|
||||
|
||||
struct gl_priv {
|
||||
struct urb *irq_urb;
|
||||
char irq_buf [INTERRUPT_BUFSIZE];
|
||||
};
|
||||
|
||||
static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = usb_control_msg(dev->udev,
|
||||
usb_sndctrlpipe(dev->udev, 0),
|
||||
request,
|
||||
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
value,
|
||||
0, // index
|
||||
0, // data buffer
|
||||
0, // size
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void gl_interrupt_complete(struct urb *urb)
|
||||
{
|
||||
int status = urb->status;
|
||||
|
||||
switch (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",
|
||||
__FUNCTION__, status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - nonzero urb status received: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
}
|
||||
|
||||
status = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (status)
|
||||
err("%s - usb_submit_urb failed with result %d",
|
||||
__FUNCTION__, status);
|
||||
}
|
||||
|
||||
static int gl_interrupt_read(struct usbnet *dev)
|
||||
{
|
||||
struct gl_priv *priv = dev->priv_data;
|
||||
int retval;
|
||||
|
||||
// issue usb interrupt read
|
||||
if (priv && priv->irq_urb) {
|
||||
// submit urb
|
||||
if ((retval = usb_submit_urb(priv->irq_urb, GFP_KERNEL)) != 0)
|
||||
dbg("gl_interrupt_read: submit fail - %X...", retval);
|
||||
else
|
||||
dbg("gl_interrupt_read: submit success...");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check whether another side is connected
|
||||
static int genelink_check_connect(struct usbnet *dev)
|
||||
{
|
||||
int retval;
|
||||
|
||||
dbg("genelink_check_connect...");
|
||||
|
||||
// detect whether another side is connected
|
||||
if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) {
|
||||
dbg("%s: genelink_check_connect write fail - %X",
|
||||
dev->net->name, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// usb interrupt read to ack another side
|
||||
if ((retval = gl_interrupt_read(dev)) != 0) {
|
||||
dbg("%s: genelink_check_connect read fail - %X",
|
||||
dev->net->name, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
dbg("%s: genelink_check_connect read success", dev->net->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// allocate and initialize the private data for genelink
|
||||
static int genelink_init(struct usbnet *dev)
|
||||
{
|
||||
struct gl_priv *priv;
|
||||
|
||||
// allocate the private data structure
|
||||
if ((priv = kmalloc(sizeof *priv, GFP_KERNEL)) == 0) {
|
||||
dbg("%s: cannot allocate private data per device",
|
||||
dev->net->name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// allocate irq urb
|
||||
if ((priv->irq_urb = usb_alloc_urb(0, GFP_KERNEL)) == 0) {
|
||||
dbg("%s: cannot allocate private irq urb per device",
|
||||
dev->net->name);
|
||||
kfree(priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// fill irq urb
|
||||
usb_fill_int_urb(priv->irq_urb, dev->udev,
|
||||
usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE),
|
||||
priv->irq_buf, INTERRUPT_BUFSIZE,
|
||||
gl_interrupt_complete, 0,
|
||||
GENELINK_INTERRUPT_INTERVAL);
|
||||
|
||||
// set private data pointer
|
||||
dev->priv_data = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// release the private data
|
||||
static int genelink_free(struct usbnet *dev)
|
||||
{
|
||||
struct gl_priv *priv = dev->priv_data;
|
||||
|
||||
if (!priv)
|
||||
return 0;
|
||||
|
||||
// FIXME: can't cancel here; it's synchronous, and
|
||||
// should have happened earlier in any case (interrupt
|
||||
// handling needs to be generic)
|
||||
|
||||
// cancel irq urb first
|
||||
usb_kill_urb(priv->irq_urb);
|
||||
|
||||
// free irq urb
|
||||
usb_free_urb(priv->irq_urb);
|
||||
|
||||
// free the private data structure
|
||||
kfree(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct gl_header *header;
|
||||
|
@ -124,10 +124,11 @@
|
||||
#define RX_URB_FAIL 3
|
||||
|
||||
/* Define these values to match your device */
|
||||
#define VENDOR_ID_REALTEK 0x0bda
|
||||
#define VENDOR_ID_REALTEK 0x0bda
|
||||
#define VENDOR_ID_MELCO 0x0411
|
||||
#define VENDOR_ID_MICRONET 0x3980
|
||||
#define VENDOR_ID_MICRONET 0x3980
|
||||
#define VENDOR_ID_LONGSHINE 0x07b8
|
||||
#define VENDOR_ID_OQO 0x1557
|
||||
#define VENDOR_ID_ZYXEL 0x0586
|
||||
|
||||
#define PRODUCT_ID_RTL8150 0x8150
|
||||
@ -144,6 +145,7 @@ static struct usb_device_id rtl8150_table[] = {
|
||||
{USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
|
||||
{USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
|
||||
{USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
|
||||
{USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)},
|
||||
{USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
|
||||
{}
|
||||
};
|
||||
|
@ -19,8 +19,11 @@
|
||||
static struct usb_device_id id_table [] = {
|
||||
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
|
||||
{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
|
||||
{ USB_DEVICE(0x1410, 0x1130) }, /* Novatel Wireless S720 CDMA/EV-DO */
|
||||
{ USB_DEVICE(0x1410, 0x2110) }, /* Novatel Wireless U720 CDMA/EV-DO */
|
||||
{ USB_DEVICE(0x1410, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */
|
||||
{ USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
|
||||
{ USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
@ -69,6 +69,7 @@ static struct usb_device_id id_table [] = {
|
||||
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
|
||||
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
|
||||
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
|
||||
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
|
||||
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
|
@ -962,21 +962,6 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
|
||||
cypress_set_termios(port, &priv->tmp_termios);
|
||||
return (0);
|
||||
break;
|
||||
/* these are called when setting baud rate from gpsd */
|
||||
case TCGETS:
|
||||
if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
return (0);
|
||||
break;
|
||||
case TCSETS:
|
||||
if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
/* here we need to call cypress_set_termios to invoke the new settings */
|
||||
cypress_set_termios(port, &priv->tmp_termios);
|
||||
return (0);
|
||||
break;
|
||||
/* This code comes from drivers/char/serial.c and ftdi_sio.c */
|
||||
case TIOCMIWAIT:
|
||||
while (priv != NULL) {
|
||||
|
@ -452,6 +452,7 @@ static struct usb_device_id id_table_combined [] = {
|
||||
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
|
||||
{ USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
|
||||
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
|
||||
{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
|
||||
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
|
||||
|
@ -312,8 +312,9 @@
|
||||
|
||||
/* CCS Inc. ICDU/ICDU40 product ID - the FT232BM is used in an in-circuit-debugger */
|
||||
/* unit for PIC16's/PIC18's */
|
||||
#define FTDI_CCSICDU20_0_PID 0xF9D0
|
||||
#define FTDI_CCSICDU40_1_PID 0xF9D1
|
||||
#define FTDI_CCSICDU20_0_PID 0xF9D0
|
||||
#define FTDI_CCSICDU40_1_PID 0xF9D1
|
||||
#define FTDI_CCSMACHX_2_PID 0xF9D2
|
||||
|
||||
/* Inside Accesso contactless reader (http://www.insidefr.com) */
|
||||
#define INSIDE_ACCESSO 0xFAD0
|
||||
|
@ -14,6 +14,9 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/serial.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static int debug;
|
||||
|
||||
static struct usb_device_id id_table [] = {
|
||||
{ USB_DEVICE(0x1404, 0xcddc) },
|
||||
@ -21,6 +24,26 @@ static struct usb_device_id id_table [] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct termios t;
|
||||
|
||||
dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
|
||||
|
||||
if (cmd == TCSETSF) {
|
||||
if (user_termios_to_kernel_termios(&t, (void __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
|
||||
t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
|
||||
|
||||
if (!(t.c_lflag & ICANON))
|
||||
return -EINVAL;
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static struct usb_driver funsoft_driver = {
|
||||
.name = "funsoft",
|
||||
.probe = usb_serial_probe,
|
||||
@ -39,6 +62,7 @@ static struct usb_serial_driver funsoft_device = {
|
||||
.num_bulk_in = NUM_DONT_CARE,
|
||||
.num_bulk_out = NUM_DONT_CARE,
|
||||
.num_ports = 1,
|
||||
.ioctl = funsoft_ioctl,
|
||||
};
|
||||
|
||||
static int __init funsoft_init(void)
|
||||
@ -63,3 +87,6 @@ static void __exit funsoft_exit(void)
|
||||
module_init(funsoft_init);
|
||||
module_exit(funsoft_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param(debug, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(debug, "Debug enabled or not");
|
||||
|
@ -87,10 +87,6 @@ static int klsi_105_write_room (struct usb_serial_port *port);
|
||||
static void klsi_105_read_bulk_callback (struct urb *urb);
|
||||
static void klsi_105_set_termios (struct usb_serial_port *port,
|
||||
struct ktermios *old);
|
||||
static int klsi_105_ioctl (struct usb_serial_port *port,
|
||||
struct file * file,
|
||||
unsigned int cmd,
|
||||
unsigned long arg);
|
||||
static void klsi_105_throttle (struct usb_serial_port *port);
|
||||
static void klsi_105_unthrottle (struct usb_serial_port *port);
|
||||
/*
|
||||
@ -140,7 +136,6 @@ static struct usb_serial_driver kl5kusb105d_device = {
|
||||
.chars_in_buffer = klsi_105_chars_in_buffer,
|
||||
.write_room = klsi_105_write_room,
|
||||
.read_bulk_callback =klsi_105_read_bulk_callback,
|
||||
.ioctl = klsi_105_ioctl,
|
||||
.set_termios = klsi_105_set_termios,
|
||||
/*.break_ctl = klsi_105_break_ctl,*/
|
||||
.tiocmget = klsi_105_tiocmget,
|
||||
@ -899,69 +894,6 @@ static int klsi_105_tiocmset (struct usb_serial_port *port, struct file *file,
|
||||
*/
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct klsi_105_private *priv = usb_get_serial_port_data(port);
|
||||
void __user *user_arg = (void __user *)arg;
|
||||
|
||||
dbg("%scmd=0x%x", __FUNCTION__, cmd);
|
||||
|
||||
/* Based on code from acm.c and others */
|
||||
switch (cmd) {
|
||||
case TIOCMIWAIT:
|
||||
/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
|
||||
/* TODO */
|
||||
dbg("%s - TIOCMIWAIT not handled", __FUNCTION__);
|
||||
return -ENOIOCTLCMD;
|
||||
case TIOCGICOUNT:
|
||||
/* return count of modemline transitions */
|
||||
/* TODO */
|
||||
dbg("%s - TIOCGICOUNT not handled", __FUNCTION__);
|
||||
return -ENOIOCTLCMD;
|
||||
case TCGETS:
|
||||
/* return current info to caller */
|
||||
dbg("%s - TCGETS data faked/incomplete", __FUNCTION__);
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios)))
|
||||
return -EFAULT;
|
||||
|
||||
if (kernel_termios_to_user_termios((struct termios __user *)arg,
|
||||
&priv->termios))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
case TCSETS:
|
||||
/* set port termios to the one given by the user */
|
||||
dbg("%s - TCSETS not handled", __FUNCTION__);
|
||||
|
||||
if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios)))
|
||||
return -EFAULT;
|
||||
|
||||
if (user_termios_to_kernel_termios(&priv->termios,
|
||||
(struct termios __user *)arg))
|
||||
return -EFAULT;
|
||||
klsi_105_set_termios(port, &priv->termios);
|
||||
return 0;
|
||||
case TCSETSW: {
|
||||
/* set port termios and try to wait for completion of last
|
||||
* write operation */
|
||||
/* We guess here. If there are not too many write urbs
|
||||
* outstanding, we lie. */
|
||||
/* what is the right way to wait here? schedule() ? */
|
||||
/*
|
||||
while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE)
|
||||
schedule();
|
||||
*/
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
default:
|
||||
dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd);
|
||||
return(-ENOIOCTLCMD);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
} /* klsi_105_ioctl */
|
||||
|
||||
static void klsi_105_throttle (struct usb_serial_port *port)
|
||||
{
|
||||
|
@ -2460,12 +2460,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
|
||||
tty_ldisc_deref(ld);
|
||||
return 0;
|
||||
|
||||
case TCGETS:
|
||||
if (kernel_termios_to_user_termios
|
||||
((struct termios __user *)argp, tty->termios))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
case TIOCSERGETLSR:
|
||||
dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
|
||||
return mos7840_get_lsr_info(mos7840_port, argp);
|
||||
|
@ -79,6 +79,7 @@ static int option_send_setup(struct usb_serial_port *port);
|
||||
#define OPTION_PRODUCT_COBRA 0x6500
|
||||
#define OPTION_PRODUCT_COBRA2 0x6600
|
||||
#define HUAWEI_PRODUCT_E600 0x1001
|
||||
#define HUAWEI_PRODUCT_E220 0x1003
|
||||
#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
|
||||
#define NOVATELWIRELESS_PRODUCT_U740 0x1400
|
||||
#define ANYDATA_PRODUCT_ID 0x6501
|
||||
@ -90,6 +91,7 @@ static struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
|
||||
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
|
||||
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
|
||||
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
|
||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
|
||||
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
|
||||
@ -103,6 +105,7 @@ static struct usb_device_id option_ids1[] = {
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
|
||||
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
|
||||
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
|
||||
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
|
||||
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
|
||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
|
||||
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
|
||||
|
@ -153,6 +153,13 @@ UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100,
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
|
||||
|
||||
/* Reported by <honkkis@gmail.com> */
|
||||
UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100,
|
||||
"Nokia",
|
||||
"E70",
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
|
||||
|
||||
/* Reported by Jon Hart <Jon.Hart@web.de> */
|
||||
UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100,
|
||||
"Nokia",
|
||||
@ -1328,6 +1335,15 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_RESIDUE ),
|
||||
|
||||
/* This prevents the kernel from detecting the virtual cd-drive with the
|
||||
* Windows drivers. <johann.wilhelm@student.tugraz.at>
|
||||
*/
|
||||
UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0xffff,
|
||||
"HUAWEI",
|
||||
"E220 USB-UMTS Install",
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_DEVICE),
|
||||
|
||||
/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
|
||||
UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001,
|
||||
"Minolta",
|
||||
|
Loading…
Reference in New Issue
Block a user