Commit 0a8d2a86 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linuxusb.bkbits.net/linus-2.5

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 8f706ce4 ab7e3d48
...@@ -1722,12 +1722,12 @@ L: linux-usb-devel@lists.sourceforge.net ...@@ -1722,12 +1722,12 @@ L: linux-usb-devel@lists.sourceforge.net
S: Maintained S: Maintained
USB SERIAL KEYSPAN DRIVER USB SERIAL KEYSPAN DRIVER
P: Hugh Blemings P: Greg Kroah-Hartman
M: hugh@misc.nu M: greg@kroah.com
L: linux-usb-users@lists.sourceforge.net L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net
W: http://www.kroah.com/linux/
S: Maintained S: Maintained
W: http://misc.nu/hugh/keyspan/
USB SUBSYSTEM USB SUBSYSTEM
P: Greg Kroah-Hartman P: Greg Kroah-Hartman
......
This diff is collapsed.
...@@ -224,12 +224,12 @@ static const u8 rh_config_descriptor [] = { ...@@ -224,12 +224,12 @@ static const u8 rh_config_descriptor [] = {
* helper routine for returning string descriptors in UTF-16LE * helper routine for returning string descriptors in UTF-16LE
* input can actually be ISO-8859-1; ASCII is its 7-bit subset * input can actually be ISO-8859-1; ASCII is its 7-bit subset
*/ */
static int ascii2utf (char *ascii, u8 *utf, int utfmax) static int ascii2utf (char *s, u8 *utf, int utfmax)
{ {
int retval; int retval;
for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) { for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
*utf++ = *ascii++ & 0x7f; *utf++ = *s++;
*utf++ = 0; *utf++ = 0;
} }
return retval; return retval;
...@@ -248,8 +248,7 @@ static int ascii2utf (char *ascii, u8 *utf, int utfmax) ...@@ -248,8 +248,7 @@ static int ascii2utf (char *ascii, u8 *utf, int utfmax)
*/ */
static int rh_string ( static int rh_string (
int id, int id,
struct pci_dev *pci_desc, struct usb_hcd *hcd,
char *type,
u8 *data, u8 *data,
int len int len
) { ) {
...@@ -263,15 +262,16 @@ static int rh_string ( ...@@ -263,15 +262,16 @@ static int rh_string (
// serial number // serial number
} else if (id == 1) { } else if (id == 1) {
strcpy (buf, pci_desc->slot_name); strcpy (buf, hcd->bus_name);
// product description // product description
} else if (id == 2) { } else if (id == 2) {
strcpy (buf, pci_desc->name); strcpy (buf, hcd->product_desc);
// id 3 == vendor description // id 3 == vendor description
} else if (id == 3) { } else if (id == 3) {
sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type); sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,
hcd->description);
// unsupported IDs --> "protocol stall" // unsupported IDs --> "protocol stall"
} else } else
...@@ -338,9 +338,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -338,9 +338,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
break; break;
case USB_DT_STRING << 8: case USB_DT_STRING << 8:
urb->actual_length = rh_string ( urb->actual_length = rh_string (
wValue & 0xff, wValue & 0xff, hcd,
hcd->pdev,
(char *) hcd->description,
ubuf, wLength); ubuf, wLength);
break; break;
default: default:
...@@ -1004,6 +1002,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1004,6 +1002,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
hcd->self.hcpriv = (void *) hcd; hcd->self.hcpriv = (void *) hcd;
hcd->bus = &hcd->self; hcd->bus = &hcd->self;
hcd->bus_name = dev->slot_name; hcd->bus_name = dev->slot_name;
hcd->product_desc = dev->name;
INIT_LIST_HEAD (&hcd->dev_list); INIT_LIST_HEAD (&hcd->dev_list);
...@@ -1266,7 +1265,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1266,7 +1265,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
struct usb_hcd *hcd; struct usb_hcd *hcd;
struct hcd_dev *dev; struct hcd_dev *dev;
unsigned long flags; unsigned long flags;
int pipe; int pipe, temp;
if (!urb || urb->hcpriv || !urb->complete) if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL; return -EINVAL;
...@@ -1286,6 +1285,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1286,6 +1285,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state)) if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
return -ESHUTDOWN; return -ESHUTDOWN;
pipe = urb->pipe; pipe = urb->pipe;
temp = usb_pipetype (urb->pipe);
if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
usb_pipeout (pipe))) usb_pipeout (pipe)))
return -EPIPE; return -EPIPE;
...@@ -1298,7 +1298,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1298,7 +1298,7 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
/* enforce simple/standard policy */ /* enforce simple/standard policy */
allowed = USB_ASYNC_UNLINK; // affects later unlinks allowed = USB_ASYNC_UNLINK; // affects later unlinks
allowed |= USB_NO_FSBR; // only affects UHCI allowed |= USB_NO_FSBR; // only affects UHCI
switch (usb_pipetype (pipe)) { switch (temp) {
case PIPE_CONTROL: case PIPE_CONTROL:
allowed |= USB_DISABLE_SPD; allowed |= USB_DISABLE_SPD;
break; break;
...@@ -1317,15 +1317,55 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) ...@@ -1317,15 +1317,55 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags)
/* warn if submitter gave bogus flags */ /* warn if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) if (urb->transfer_flags != orig_flags)
warn ("BOGUS urb flags, %x --> %x", err ("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags); orig_flags, urb->transfer_flags);
} }
#endif #endif
/* /*
* FIXME: alloc periodic bandwidth here, for interrupt and iso? * Force periodic transfer intervals to be legal values that are
* Need to look at the ring submit mechanism for iso tds ... they * a power of two (so HCDs don't need to).
* aren't actually "periodic" in 2.4 kernels.
* *
* FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
switch (temp) {
case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
/* too big? */
switch (urb->dev->speed) {
case USB_SPEED_HIGH: /* units are microframes */
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
temp = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
if (temp == PIPE_INTERRUPT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
temp = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
temp = 1024;
}
default:
return -EINVAL;
}
/* power of two? */
while (temp > urb->interval)
temp >>= 1;
urb->interval = temp;
}
/*
* FIXME: make urb timeouts be generic, keeping the HCD cores * FIXME: make urb timeouts be generic, keeping the HCD cores
* as simple as possible. * as simple as possible.
*/ */
...@@ -1589,6 +1629,9 @@ static void hcd_irq (int irq, void *__hcd, struct pt_regs * r) ...@@ -1589,6 +1629,9 @@ static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
struct usb_hcd *hcd = __hcd; struct usb_hcd *hcd = __hcd;
int start = hcd->state; int start = hcd->state;
if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
return;
hcd->driver->irq (hcd); hcd->driver->irq (hcd);
if (hcd->state != start && hcd->state == USB_STATE_HALT) if (hcd->state != start && hcd->state == USB_STATE_HALT)
hc_died (hcd); hc_died (hcd);
...@@ -1642,7 +1685,8 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) ...@@ -1642,7 +1685,8 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev) // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
if (urb->status) if (urb->status)
dbg ("giveback urb %p status %d", urb, urb->status); dbg ("giveback urb %p status %d len %d",
urb, urb->status, urb->actual_length);
/* if no error, make sure urb->next progresses */ /* if no error, make sure urb->next progresses */
else if (urb->next) { else if (urb->next) {
......
...@@ -39,7 +39,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -39,7 +39,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
struct usb_bus self; /* hcd is-a bus */ struct usb_bus self; /* hcd is-a bus */
const char *bus_name; const char *bus_name;
const char *product_desc; /* product/vendor string */
const char *description; /* "ehci-hcd" etc */ const char *description; /* "ehci-hcd" etc */
struct timer_list rh_timer; /* drives root hub */ struct timer_list rh_timer; /* drives root hub */
......
/* /*
* Copyright (c) 2000-2001 by David Brownell * Copyright (c) 2000-2002 by David Brownell
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
...@@ -31,10 +31,6 @@ ...@@ -31,10 +31,6 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#ifndef CONFIG_USB_DEBUG
#define CONFIG_USB_DEBUG /* this is still experimental! */
#endif
#ifdef CONFIG_USB_DEBUG #ifdef CONFIG_USB_DEBUG
#define DEBUG #define DEBUG
#else #else
...@@ -73,19 +69,25 @@ ...@@ -73,19 +69,25 @@
* ... * ...
* *
* HISTORY: * HISTORY:
*
* 2002-03-05 Initial high-speed ISO support; reduce ITD memory; shift
* more checking to generic hcd framework (db). Make it work with
* Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
* 2002-01-14 Minor cleanup; version synch. * 2002-01-14 Minor cleanup; version synch.
* 2002-01-08 Fix roothub handoff of FS/LS to companion controllers. * 2002-01-08 Fix roothub handoff of FS/LS to companion controllers.
* 2002-01-04 Control/Bulk queuing behaves. * 2002-01-04 Control/Bulk queuing behaves.
*
* 2001-12-12 Initial patch version for Linux 2.5.1 kernel. * 2001-12-12 Initial patch version for Linux 2.5.1 kernel.
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/ */
#define DRIVER_VERSION "$Revision: 0.26 $" #define DRIVER_VERSION "$Revision: 0.27 $"
#define DRIVER_AUTHOR "David Brownell" #define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
// #define EHCI_VERBOSE_DEBUG // #define EHCI_VERBOSE_DEBUG
// #define have_iso // #define have_split_iso
#ifdef CONFIG_DEBUG_SLAB #ifdef CONFIG_DEBUG_SLAB
# define EHCI_SLAB_FLAGS (SLAB_POISON) # define EHCI_SLAB_FLAGS (SLAB_POISON)
...@@ -187,6 +189,9 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -187,6 +189,9 @@ static int ehci_start (struct usb_hcd *hcd)
dbg_hcs_params (ehci, "ehci_start"); dbg_hcs_params (ehci, "ehci_start");
dbg_hcc_params (ehci, "ehci_start"); dbg_hcc_params (ehci, "ehci_start");
/* cache this readonly data; minimize PCI reads */
ehci->hcs_params = readl (&ehci->caps->hcs_params);
/* /*
* hw default: 1K periodic list heads, one per frame. * hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows. * periodic_size can shrink by USBCMD update if hcc_params allows.
...@@ -204,7 +209,7 @@ static int ehci_start (struct usb_hcd *hcd) ...@@ -204,7 +209,7 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->async = 0; ehci->async = 0;
ehci->reclaim = 0; ehci->reclaim = 0;
ehci->next_frame = -1; ehci->next_uframe = -1;
/* controller state: unknown --> reset */ /* controller state: unknown --> reset */
...@@ -310,7 +315,7 @@ static void ehci_stop (struct usb_hcd *hcd) ...@@ -310,7 +315,7 @@ static void ehci_stop (struct usb_hcd *hcd)
// root hub is shut down separately (first, when possible) // root hub is shut down separately (first, when possible)
scan_async (ehci); scan_async (ehci);
if (ehci->next_frame != -1) if (ehci->next_uframe != -1)
scan_periodic (ehci); scan_periodic (ehci);
ehci_mem_cleanup (ehci); ehci_mem_cleanup (ehci);
...@@ -332,14 +337,12 @@ static int ehci_get_frame (struct usb_hcd *hcd) ...@@ -332,14 +337,12 @@ static int ehci_get_frame (struct usb_hcd *hcd)
static int ehci_suspend (struct usb_hcd *hcd, u32 state) static int ehci_suspend (struct usb_hcd *hcd, u32 state)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 params;
int ports; int ports;
int i; int i;
dbg ("%s: suspend to %d", hcd->bus_name, state); dbg ("%s: suspend to %d", hcd->bus_name, state);
params = readl (&ehci->caps->hcs_params); ports = HCS_N_PORTS (ehci->hcs_params);
ports = HCS_N_PORTS (params);
// FIXME: This assumes what's probably a D3 level suspend... // FIXME: This assumes what's probably a D3 level suspend...
...@@ -375,14 +378,12 @@ dbg ("%s: suspend port %d", hcd->bus_name, i); ...@@ -375,14 +378,12 @@ dbg ("%s: suspend port %d", hcd->bus_name, i);
static int ehci_resume (struct usb_hcd *hcd) static int ehci_resume (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 params;
int ports; int ports;
int i; int i;
dbg ("%s: resume", hcd->bus_name); dbg ("%s: resume", hcd->bus_name);
params = readl (&ehci->caps->hcs_params); ports = HCS_N_PORTS (ehci->hcs_params);
ports = HCS_N_PORTS (params);
// FIXME: if controller didn't retain state, // FIXME: if controller didn't retain state,
// return and let generic code clean it up // return and let generic code clean it up
...@@ -426,7 +427,7 @@ static void ehci_tasklet (unsigned long param) ...@@ -426,7 +427,7 @@ static void ehci_tasklet (unsigned long param)
if (ehci->reclaim_ready) if (ehci->reclaim_ready)
end_unlink_async (ehci); end_unlink_async (ehci);
scan_async (ehci); scan_async (ehci);
if (ehci->next_frame != -1) if (ehci->next_uframe != -1)
scan_periodic (ehci); scan_periodic (ehci);
// FIXME: when nothing is connected to the root hub, // FIXME: when nothing is connected to the root hub,
...@@ -440,20 +441,20 @@ static void ehci_irq (struct usb_hcd *hcd) ...@@ -440,20 +441,20 @@ static void ehci_irq (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status = readl (&ehci->regs->status); u32 status = readl (&ehci->regs->status);
int bh = 0; int bh;
/* clear (just) interrupts */
status &= INTR_MASK; status &= INTR_MASK;
if (!status) /* irq sharing? */
return;
/* clear (just) interrupts */
writel (status, &ehci->regs->status); writel (status, &ehci->regs->status);
readl (&ehci->regs->command); /* unblock posted write */ readl (&ehci->regs->command); /* unblock posted write */
bh = 0;
if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
return;
#ifdef EHCI_VERBOSE_DEBUG #ifdef EHCI_VERBOSE_DEBUG
/* unrequested/ignored: Port Change Detect, Frame List Rollover */ /* unrequested/ignored: Port Change Detect, Frame List Rollover */
if (status & INTR_MASK) dbg_status (ehci, "irq", status);
dbg_status (ehci, "irq", status);
#endif #endif
/* INT, ERR, and IAA interrupt rates can be throttled */ /* INT, ERR, and IAA interrupt rates can be throttled */
...@@ -520,17 +521,15 @@ static int ehci_urb_enqueue ( ...@@ -520,17 +521,15 @@ static int ehci_urb_enqueue (
return intr_submit (ehci, urb, &qtd_list, mem_flags); return intr_submit (ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS: case PIPE_ISOCHRONOUS:
#ifdef have_iso
if (urb->dev->speed == USB_SPEED_HIGH) if (urb->dev->speed == USB_SPEED_HIGH)
return itd_submit (ehci, urb); return itd_submit (ehci, urb, mem_flags);
#ifdef have_split_iso
else else
return sitd_submit (ehci, urb); return sitd_submit (ehci, urb, mem_flags);
#else #else
// FIXME highspeed iso stuff is written but never run/tested. dbg ("no split iso support yet");
// and the split iso support isn't even written yet.
dbg ("no iso support yet");
return -ENOSYS; return -ENOSYS;
#endif /* have_iso */ #endif /* have_split_iso */
} }
return 0; return 0;
......
/* /*
* Copyright (c) 2001 by David Brownell * Copyright (c) 2001-2002 by David Brownell
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
...@@ -68,8 +68,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -68,8 +68,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* init status to no-changes */ /* init status to no-changes */
buf [0] = 0; buf [0] = 0;
temp = readl (&ehci->caps->hcs_params); ports = HCS_N_PORTS (ehci->hcs_params);
ports = HCS_N_PORTS (temp);
if (ports > 7) { if (ports > 7) {
buf [1] = 0; buf [1] = 0;
retval++; retval++;
...@@ -107,8 +106,7 @@ ehci_hub_descriptor ( ...@@ -107,8 +106,7 @@ ehci_hub_descriptor (
struct ehci_hcd *ehci, struct ehci_hcd *ehci,
struct usb_hub_descriptor *desc struct usb_hub_descriptor *desc
) { ) {
u32 params = readl (&ehci->caps->hcs_params); int ports = HCS_N_PORTS (ehci->hcs_params);
int ports = HCS_N_PORTS (params);
u16 temp; u16 temp;
desc->bDescriptorType = 0x29; desc->bDescriptorType = 0x29;
...@@ -124,10 +122,10 @@ ehci_hub_descriptor ( ...@@ -124,10 +122,10 @@ ehci_hub_descriptor (
memset (&desc->bitmap [temp], 0xff, temp); memset (&desc->bitmap [temp], 0xff, temp);
temp = 0x0008; /* per-port overcurrent reporting */ temp = 0x0008; /* per-port overcurrent reporting */
if (HCS_PPC (params)) /* per-port power control */ if (HCS_PPC (ehci->hcs_params))
temp |= 0x0001; temp |= 0x0001; /* per-port power control */
if (HCS_INDICATOR (params)) /* per-port indicators (LEDs) */ if (HCS_INDICATOR (ehci->hcs_params))
temp |= 0x0080; temp |= 0x0080; /* per-port indicators (LEDs) */
desc->wHubCharacteristics = cpu_to_le16 (temp); desc->wHubCharacteristics = cpu_to_le16 (temp);
} }
...@@ -142,8 +140,7 @@ static int ehci_hub_control ( ...@@ -142,8 +140,7 @@ static int ehci_hub_control (
u16 wLength u16 wLength
) { ) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 params = readl (&ehci->caps->hcs_params); int ports = HCS_N_PORTS (ehci->hcs_params);
int ports = HCS_N_PORTS (params);
u32 temp; u32 temp;
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
...@@ -189,7 +186,7 @@ static int ehci_hub_control ( ...@@ -189,7 +186,7 @@ static int ehci_hub_control (
/* ? */ /* ? */
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
if (HCS_PPC (params)) if (HCS_PPC (ehci->hcs_params))
writel (temp & ~PORT_POWER, writel (temp & ~PORT_POWER,
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
...@@ -300,7 +297,7 @@ static int ehci_hub_control ( ...@@ -300,7 +297,7 @@ static int ehci_hub_control (
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
if (HCS_PPC (params)) if (HCS_PPC (ehci->hcs_params))
writel (temp | PORT_POWER, writel (temp | PORT_POWER,
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
...@@ -312,6 +309,13 @@ static int ehci_hub_control ( ...@@ -312,6 +309,13 @@ static int ehci_hub_control (
hcd->bus_name, wIndex + 1); hcd->bus_name, wIndex + 1);
temp |= PORT_OWNER; temp |= PORT_OWNER;
} else { } else {
/* Philips 1562 wants CMD_RUN to reset */
if (!HCD_IS_RUNNING(ehci->hcd.state)) {
u32 cmd = readl (&ehci->regs->command);
cmd |= CMD_RUN;
writel (cmd, &ehci->regs->command);
ehci->hcd.state = USB_STATE_RUNNING;
}
vdbg ("%s port %d reset", vdbg ("%s port %d reset",
hcd->bus_name, wIndex + 1); hcd->bus_name, wIndex + 1);
temp |= PORT_RESET; temp |= PORT_RESET;
......
/* /*
* Copyright (c) 2001 by David Brownell * Copyright (c) 2001-2002 by David Brownell
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
...@@ -643,12 +643,19 @@ ehci_qh_make ( ...@@ -643,12 +643,19 @@ ehci_qh_make (
if (usb_pipecontrol (urb->pipe)) { if (usb_pipecontrol (urb->pipe)) {
info1 |= 64 << 16; /* usb2 fixed maxpacket */ info1 |= 64 << 16; /* usb2 fixed maxpacket */
info1 |= 1 << 14; /* toggle from qtd */ info1 |= 1 << 14; /* toggle from qtd */
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else if (usb_pipebulk (urb->pipe)) { } else if (usb_pipebulk (urb->pipe)) {
info1 |= 512 << 16; /* usb2 fixed maxpacket */ info1 |= 512 << 16; /* usb2 fixed maxpacket */
info2 |= (EHCI_TUNE_MULT_HS << 30); info2 |= (EHCI_TUNE_MULT_HS << 30);
} else } else {
info1 |= usb_maxpacket (urb->dev, urb->pipe, u32 temp;
usb_pipeout (urb->pipe)) << 16; temp = usb_maxpacket (urb->dev, urb->pipe,
usb_pipeout (urb->pipe));
info1 |= (temp & 0x3ff) << 16; /* maxpacket */
/* HS intr can be "high bandwidth" */
temp = 1 + ((temp >> 11) & 0x03);
info2 |= temp << 30; /* mult */
}
break; break;
default: default:
#ifdef DEBUG #ifdef DEBUG
......
This diff is collapsed.
/* /*
* Copyright (c) 2001 by David Brownell * Copyright (c) 2001-2002 by David Brownell
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
...@@ -49,7 +49,7 @@ struct ehci_hcd { /* one per controller */ ...@@ -49,7 +49,7 @@ struct ehci_hcd { /* one per controller */
unsigned i_thresh; /* uframes HC might cache */ unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */ union ehci_shadow *pshadow; /* mirror hw periodic table */
int next_frame; /* scan periodic, start here */ int next_uframe; /* scan periodic, start here */
unsigned periodic_urbs; /* how many urbs scheduled? */ unsigned periodic_urbs; /* how many urbs scheduled? */
/* deferred work from IRQ, etc */ /* deferred work from IRQ, etc */
...@@ -62,6 +62,7 @@ struct ehci_hcd { /* one per controller */ ...@@ -62,6 +62,7 @@ struct ehci_hcd { /* one per controller */
struct usb_hcd hcd; struct usb_hcd hcd;
struct ehci_caps *caps; struct ehci_caps *caps;
struct ehci_regs *regs; struct ehci_regs *regs;
u32 hcs_params; /* cached register copy */
/* per-HC memory pools (could be per-PCI-bus, but ...) */ /* per-HC memory pools (could be per-PCI-bus, but ...) */
struct pci_pool *qh_pool; /* qh per active urb */ struct pci_pool *qh_pool; /* qh per active urb */
...@@ -324,13 +325,14 @@ struct ehci_itd { ...@@ -324,13 +325,14 @@ struct ehci_itd {
union ehci_shadow itd_next; /* ptr to periodic q entry */ union ehci_shadow itd_next; /* ptr to periodic q entry */
struct urb *urb; struct urb *urb;
unsigned index; /* in urb->iso_frame_desc */
struct list_head itd_list; /* list of urb frames' itds */ struct list_head itd_list; /* list of urb frames' itds */
dma_addr_t buf_dma; /* frame's buffer address */ dma_addr_t buf_dma; /* frame's buffer address */
unsigned uframe; /* in periodic schedule */ /* for now, only one hw_transaction per itd */
u32 transaction [8]; /* copy of hw_transaction */ u32 transaction;
u16 index; /* in urb->iso_frame_desc */
u16 uframe; /* in periodic schedule */
u16 usecs;
} __attribute__ ((aligned (32))); } __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
/* /*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller ** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
** **
** Copyright (c) 1999-2001 Petko Manolov (pmanolov@lnxw.com) ** Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
** **
** **
** ChangeLog: ** ChangeLog:
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
** TODO: suppressing HCD warnings spewage on disconnect. ** TODO: suppressing HCD warnings spewage on disconnect.
** v0.4.13 Ethernet address is now set at probe(), not at open() ** v0.4.13 Ethernet address is now set at probe(), not at open()
** time as this seems to break dhcpd. ** time as this seems to break dhcpd.
** v0.5.0 branch to 2.5.x kernels
** v0.5.1 ethtool support added
*/ */
/* /*
...@@ -46,20 +48,25 @@ ...@@ -46,20 +48,25 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/uaccess.h>
#include "pegasus.h" #include "pegasus.h"
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v0.4.23 (2002/02/01)" #define DRIVER_VERSION "v0.5.1 (2002/03/06)"
#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>" #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
#define PEGASUS_USE_INTR #define PEGASUS_USE_INTR
#define PEGASUS_WRITE_EEPROM #define PEGASUS_WRITE_EEPROM
#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
BMSR_100FULL | BMSR_ANEGCAPABLE)
static int loopback = 0; static int loopback = 0;
static int mii_mode = 0; static int mii_mode = 0;
...@@ -461,8 +468,8 @@ static inline int reset_mac( pegasus_t *pegasus ) ...@@ -461,8 +468,8 @@ static inline int reset_mac( pegasus_t *pegasus )
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) { usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
__u16 auxmode; __u16 auxmode;
read_mii_word( pegasus, 0, 0x1b, &auxmode ); read_mii_word( pegasus, 0, MII_TPISTATUS, &auxmode );
write_mii_word( pegasus, 0, 0x1b, auxmode | 4 ); write_mii_word( pegasus, 0, MII_TPISTATUS, auxmode | 4 );
} }
return 0; return 0;
...@@ -481,16 +488,16 @@ static int enable_net_traffic( struct net_device *dev, struct usb_device *usb ) ...@@ -481,16 +488,16 @@ static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
if ( !(bmsr & 0x20) && !loopback ) if ( !(bmsr & 0x20) && !loopback )
warn( "%s: link NOT established (0x%x) - check the cable.", warn( "%s: link NOT established (0x%x) - check the cable.",
dev->name, bmsr ); dev->name, bmsr );
if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) ) if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
return 2; return 2;
if ( !(linkpart & 1) ) if ( !(linkpart & 1) )
warn( "link partner stat %x", linkpart ); warn( "link partner stat %x", linkpart );
data[0] = 0xc9; data[0] = 0xc9;
data[1] = 0; data[1] = 0;
if ( linkpart & (ANLPA_100TX_FD | ANLPA_10T_FD) ) if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
data[1] |= 0x20; /* set full duplex */ data[1] |= 0x20; /* set full duplex */
if ( linkpart & (ANLPA_100TX_FD | ANLPA_100TX_HD) ) if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
data[1] |= 0x10; /* set 100 Mbps */ data[1] |= 0x10; /* set 100 Mbps */
if ( mii_mode ) if ( mii_mode )
data[1] = 0; data[1] = 0;
...@@ -710,15 +717,26 @@ static inline void get_interrupt_interval( pegasus_t *pegasus ) ...@@ -710,15 +717,26 @@ static inline void get_interrupt_interval( pegasus_t *pegasus )
} }
static void set_carrier(struct net_device *net)
{
pegasus_t *pegasus;
short tmp;
pegasus = net->priv;
read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
if (tmp & BMSR_LSTATUS)
netif_carrier_on(net);
else
netif_carrier_off(net);
}
static int pegasus_open(struct net_device *net) static int pegasus_open(struct net_device *net)
{ {
pegasus_t *pegasus = (pegasus_t *)net->priv; pegasus_t *pegasus = (pegasus_t *)net->priv;
int res; int res;
if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
err("can't enable_net_traffic() - %d", res);
return -EIO;
}
FILL_BULK_URB( pegasus->rx_urb, pegasus->usb, FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1), usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus->rx_buff, PEGASUS_MAX_MTU,
...@@ -735,6 +753,11 @@ static int pegasus_open(struct net_device *net) ...@@ -735,6 +753,11 @@ static int pegasus_open(struct net_device *net)
#endif #endif
netif_start_queue( net ); netif_start_queue( net );
pegasus->flags |= PEGASUS_RUNNING; pegasus->flags |= PEGASUS_RUNNING;
if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
err("can't enable_net_traffic() - %d", res);
return -EIO;
}
set_carrier(net);
return 0; return 0;
} }
...@@ -760,24 +783,103 @@ static int pegasus_close( struct net_device *net ) ...@@ -760,24 +783,103 @@ static int pegasus_close( struct net_device *net )
} }
static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
{
pegasus_t *pegasus;
int cmd;
char tmp[128];
pegasus = net->priv;
if (get_user(cmd, (int *)uaddr))
return -EFAULT;
switch (cmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
pegasus->usb->devnum);
strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
case ETHTOOL_GSET: {
struct ethtool_cmd ecmd;
short lpa, bmcr;
if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
return -EFAULT;
ecmd.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_TP |
SUPPORTED_MII);
ecmd.port = PORT_TP;
ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = pegasus->phy;
read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
if (bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
SPEED_100 : SPEED_10;
if (ecmd.speed == SPEED_100)
ecmd.duplex = lpa & LPA_100FULL ?
DUPLEX_FULL : DUPLEX_HALF;
else
ecmd.duplex = lpa & LPA_10FULL ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
ecmd.autoneg = AUTONEG_DISABLE;
ecmd.speed = bmcr & BMCR_SPEED100 ?
SPEED_100 : SPEED_10;
ecmd.duplex = bmcr & BMCR_FULLDPLX ?
DUPLEX_FULL : DUPLEX_HALF;
}
if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
}
case ETHTOOL_SSET: {
return -EOPNOTSUPP;
}
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
edata.data = netif_carrier_ok(net);
if (copy_to_user(uaddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
default:
return -EOPNOTSUPP;
}
}
static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
{ {
__u16 *data = (__u16 *)&rq->ifr_data; __u16 *data = (__u16 *)&rq->ifr_data;
pegasus_t *pegasus = net->priv; pegasus_t *pegasus = net->priv;
switch(cmd) { switch(cmd) {
case SIOCDEVPRIVATE: case SIOCETHTOOL:
data[0] = pegasus->phy; return pegasus_ethtool_ioctl(net, rq->ifr_data);
case SIOCDEVPRIVATE+1: case SIOCDEVPRIVATE:
read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]); data[0] = pegasus->phy;
return 0; case SIOCDEVPRIVATE+1:
case SIOCDEVPRIVATE+2: read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
if ( !capable(CAP_NET_ADMIN) ) return 0;
return -EPERM; case SIOCDEVPRIVATE+2:
write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); if ( !capable(CAP_NET_ADMIN) )
return 0; return -EPERM;
default: write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
return -EOPNOTSUPP; return 0;
default:
return -EOPNOTSUPP;
} }
} }
......
/* /*
* Copyright (c) 1999,2000 Petko Manolov - Petkan (pmanolov@lnxw.com) * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -31,14 +31,6 @@ ...@@ -31,14 +31,6 @@
#define EPROM_WR_ENABLE 0x10 #define EPROM_WR_ENABLE 0x10
#define EPROM_LOAD 0x20 #define EPROM_LOAD 0x20
#define MII_BMCR 0x00
#define MII_BMSR 0x01
#define BMSR_MEDIA 0x7808
#define MII_ANLPA 0x05
#define ANLPA_100TX_FD 0x0100
#define ANLPA_100TX_HD 0x0080
#define ANLPA_10T_FD 0x0040
#define ANLPA_10T_HD 0x0020
#define PHY_DONE 0x80 #define PHY_DONE 0x80
#define PHY_READ 0x40 #define PHY_READ 0x40
#define PHY_WRITE 0x20 #define PHY_WRITE 0x20
...@@ -184,6 +176,8 @@ PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", ...@@ -184,6 +176,8 @@ PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)", PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
VENDOR_ADMTEK, 0x0986, VENDOR_ADMTEK, 0x0986,
DEFAULT_GPIO_RESET | HAS_HOME_PNA ) DEFAULT_GPIO_RESET | HAS_HOME_PNA )
PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100, PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
...@@ -254,6 +248,8 @@ PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, ...@@ -254,6 +248,8 @@ PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100, PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001, PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
......
...@@ -91,7 +91,7 @@ struct usblp { ...@@ -91,7 +91,7 @@ struct usblp {
struct usb_device *dev; /* USB device */ struct usb_device *dev; /* USB device */
devfs_handle_t devfs; /* devfs device */ devfs_handle_t devfs; /* devfs device */
struct semaphore sem; /* locks this struct, especially "dev" */ struct semaphore sem; /* locks this struct, especially "dev" */
struct urb readurb, writeurb; /* The urbs */ struct urb *readurb, *writeurb; /* The urbs */
wait_queue_head_t wait; /* Zzzzz ... */ wait_queue_head_t wait; /* Zzzzz ... */
int readcount; /* Counter for reads */ int readcount; /* Counter for reads */
int ifnum; /* Interface number */ int ifnum; /* Interface number */
...@@ -253,15 +253,15 @@ static int usblp_open(struct inode *inode, struct file *file) ...@@ -253,15 +253,15 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->used = 1; usblp->used = 1;
file->private_data = usblp; file->private_data = usblp;
usblp->writeurb.transfer_buffer_length = 0; usblp->writeurb->transfer_buffer_length = 0;
usblp->writeurb.status = 0; usblp->writeurb->status = 0;
usblp->wcomplete = 1; /* we begin writeable */ usblp->wcomplete = 1; /* we begin writeable */
usblp->rcomplete = 0; usblp->rcomplete = 0;
if (usblp->bidir) { if (usblp->bidir) {
usblp->readcount = 0; usblp->readcount = 0;
usblp->readurb.dev = usblp->dev; usblp->readurb->dev = usblp->dev;
if (usb_submit_urb(&usblp->readurb, GFP_KERNEL) < 0) { if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
retval = -EIO; retval = -EIO;
usblp->used = 0; usblp->used = 0;
file->private_data = NULL; file->private_data = NULL;
...@@ -278,8 +278,10 @@ static void usblp_cleanup (struct usblp *usblp) ...@@ -278,8 +278,10 @@ static void usblp_cleanup (struct usblp *usblp)
usblp_table [usblp->minor] = NULL; usblp_table [usblp->minor] = NULL;
info ("usblp%d: removed", usblp->minor); info ("usblp%d: removed", usblp->minor);
kfree (usblp->writeurb.transfer_buffer); kfree (usblp->writeurb->transfer_buffer);
kfree (usblp->device_id_string); kfree (usblp->device_id_string);
usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb);
kfree (usblp); kfree (usblp);
} }
...@@ -292,8 +294,8 @@ static int usblp_release(struct inode *inode, struct file *file) ...@@ -292,8 +294,8 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->used = 0; usblp->used = 0;
if (usblp->dev) { if (usblp->dev) {
if (usblp->bidir) if (usblp->bidir)
usb_unlink_urb(&usblp->readurb); usb_unlink_urb(usblp->readurb);
usb_unlink_urb(&usblp->writeurb); usb_unlink_urb(usblp->writeurb);
up(&usblp->sem); up(&usblp->sem);
} else /* finish cleanup from disconnect */ } else /* finish cleanup from disconnect */
usblp_cleanup (usblp); usblp_cleanup (usblp);
...@@ -306,8 +308,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait ...@@ -306,8 +308,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
{ {
struct usblp *usblp = file->private_data; struct usblp *usblp = file->private_data;
poll_wait(file, &usblp->wait, wait); poll_wait(file, &usblp->wait, wait);
return ((!usblp->bidir || usblp->readurb.status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM) return ((!usblp->bidir || usblp->readurb->status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM)
| (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM); | (usblp->writeurb->status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM);
} }
static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
...@@ -423,12 +425,12 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, ...@@ -423,12 +425,12 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
return -ENODEV; return -ENODEV;
} }
if (usblp->writeurb.status != 0) { if (usblp->writeurb->status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) { if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (!usblp->wcomplete) if (!usblp->wcomplete)
err("usblp%d: error %d writing to printer", err("usblp%d: error %d writing to printer",
usblp->minor, usblp->writeurb.status); usblp->minor, usblp->writeurb->status);
err = usblp->writeurb.status; err = usblp->writeurb->status;
} else } else
err = usblp_check_status(usblp, err); err = usblp_check_status(usblp, err);
up (&usblp->sem); up (&usblp->sem);
...@@ -440,23 +442,23 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, ...@@ -440,23 +442,23 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
continue; continue;
} }
writecount += usblp->writeurb.transfer_buffer_length; writecount += usblp->writeurb->transfer_buffer_length;
usblp->writeurb.transfer_buffer_length = 0; usblp->writeurb->transfer_buffer_length = 0;
if (writecount == count) { if (writecount == count) {
up (&usblp->sem); up (&usblp->sem);
break; break;
} }
usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ? usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
(count - writecount) : USBLP_BUF_SIZE; (count - writecount) : USBLP_BUF_SIZE;
if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount, if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
usblp->writeurb.transfer_buffer_length)) return -EFAULT; usblp->writeurb->transfer_buffer_length)) return -EFAULT;
usblp->writeurb.dev = usblp->dev; usblp->writeurb->dev = usblp->dev;
usblp->wcomplete = 0; usblp->wcomplete = 0;
if (usb_submit_urb(&usblp->writeurb, GFP_KERNEL)) { if (usb_submit_urb(usblp->writeurb, GFP_KERNEL)) {
count = -EIO; count = -EIO;
up (&usblp->sem); up (&usblp->sem);
break; break;
...@@ -516,29 +518,29 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t ...@@ -516,29 +518,29 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
goto done; goto done;
} }
if (usblp->readurb.status) { if (usblp->readurb->status) {
err("usblp%d: error %d reading from printer", err("usblp%d: error %d reading from printer",
usblp->minor, usblp->readurb.status); usblp->minor, usblp->readurb->status);
usblp->readurb.dev = usblp->dev; usblp->readurb->dev = usblp->dev;
usblp->readcount = 0; usblp->readcount = 0;
usb_submit_urb(&usblp->readurb, GFP_KERNEL); usb_submit_urb(usblp->readurb, GFP_KERNEL);
count = -EIO; count = -EIO;
goto done; goto done;
} }
count = count < usblp->readurb.actual_length - usblp->readcount ? count = count < usblp->readurb->actual_length - usblp->readcount ?
count : usblp->readurb.actual_length - usblp->readcount; count : usblp->readurb->actual_length - usblp->readcount;
if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) { if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
count = -EFAULT; count = -EFAULT;
goto done; goto done;
} }
if ((usblp->readcount += count) == usblp->readurb.actual_length) { if ((usblp->readcount += count) == usblp->readurb->actual_length) {
usblp->readcount = 0; usblp->readcount = 0;
usblp->readurb.dev = usblp->dev; usblp->readurb->dev = usblp->dev;
usblp->rcomplete = 0; usblp->rcomplete = 0;
if (usb_submit_urb(&usblp->readurb, GFP_KERNEL)) { if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
count = -EIO; count = -EIO;
goto done; goto done;
} }
...@@ -668,24 +670,42 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -668,24 +670,42 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
init_waitqueue_head(&usblp->wait); init_waitqueue_head(&usblp->wait);
usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!usblp->writeurb) {
err("out of memory");
kfree(usblp);
return NULL;
}
usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!usblp->readurb) {
err("out of memory");
usb_free_urb(usblp->writeurb);
kfree(usblp);
return NULL;
}
if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) { if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
err("out of memory"); err("out of memory");
usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb);
kfree(usblp); kfree(usblp);
return NULL; return NULL;
} }
if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
err("out of memory"); err("out of memory");
usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb);
kfree(usblp); kfree(usblp);
kfree(buf); kfree(buf);
return NULL; return NULL;
} }
FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), FILL_BULK_URB(usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf, 0, usblp_bulk_write, usblp); buf, 0, usblp_bulk_write, usblp);
if (bidir) if (bidir)
FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), FILL_BULK_URB(usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk_read, usblp); buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk_read, usblp);
/* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */ /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
...@@ -737,9 +757,9 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr) ...@@ -737,9 +757,9 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr)
lock_kernel(); lock_kernel();
usblp->dev = NULL; usblp->dev = NULL;
usb_unlink_urb(&usblp->writeurb); usb_unlink_urb(usblp->writeurb);
if (usblp->bidir) if (usblp->bidir)
usb_unlink_urb(&usblp->readurb); usb_unlink_urb(usblp->readurb);
if (!usblp->used) if (!usblp->used)
usblp_cleanup (usblp); usblp_cleanup (usblp);
......
/* /*
* USB IR Dongle driver * USB IR Dongle driver
* *
* Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com) * Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com)
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
* *
* See Documentation/usb/usb-serial.txt for more information on using this driver * See Documentation/usb/usb-serial.txt for more information on using this driver
* *
* 2002_Mar_07 greg kh
* moved some needed structures and #define values from the
* net/irda/irda-usb.h file into our file, as we don't want to depend on
* that codebase compiling correctly :)
*
* 2002_Jan_14 gb * 2002_Jan_14 gb
* Added module parameter to force specific number of XBOFs. * Added module parameter to force specific number of XBOFs.
* Added ir_xbof_change(). * Added ir_xbof_change().
...@@ -56,7 +61,6 @@ ...@@ -56,7 +61,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <net/irda/irda-usb.h>
#ifdef CONFIG_USB_SERIAL_DEBUG #ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1; static int debug = 1;
...@@ -73,6 +77,33 @@ ...@@ -73,6 +77,33 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_DESC "USB IR Dongle driver" #define DRIVER_DESC "USB IR Dongle driver"
/* USB IrDA class spec information */
#define USB_CLASS_IRDA 0x02
#define USB_DT_IRDA 0x21
#define IU_REQ_GET_CLASS_DESC 0x06
#define SPEED_2400 0x01
#define SPEED_9600 0x02
#define SPEED_19200 0x03
#define SPEED_38400 0x04
#define SPEED_57600 0x05
#define SPEED_115200 0x06
#define SPEED_576000 0x07
#define SPEED_1152000 0x08
#define SPEED_4000000 0x09
struct irda_class_desc {
u8 bLength;
u8 bDescriptorType;
u16 bcdSpecRevision;
u8 bmDataSize;
u8 bmWindowSize;
u8 bmMinTurnaroundTime;
u16 wBaudRate;
u8 bmAdditionalBOFs;
u8 bIrdaRateSniff;
u8 bMaxUnicastList;
} __attribute__ ((packed));
/* if overridden by the user, then use their value for the size of the read and /* if overridden by the user, then use their value for the size of the read and
* write urbs */ * write urbs */
static int buffer_size = 0; static int buffer_size = 0;
...@@ -158,7 +189,7 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, ...@@ -158,7 +189,7 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev,
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
IU_REQ_GET_CLASS_DESC, IU_REQ_GET_CLASS_DESC,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); 0, ifnum, desc, sizeof(*desc), HZ);
dbg("%s - ret=%d", __FUNCTION__, ret); dbg("%s - ret=%d", __FUNCTION__, ret);
if (ret < sizeof(*desc)) { if (ret < sizeof(*desc)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment