Commit 31c6329d authored by Linus Torvalds's avatar Linus Torvalds Committed by Linus Torvalds

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

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 5a56fafe 5313eab3
...@@ -106,9 +106,7 @@ MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all device ...@@ -106,9 +106,7 @@ MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all device
MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>"); MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");
MODULE_DESCRIPTION("USB-MIDI driver"); MODULE_DESCRIPTION("USB-MIDI driver");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#endif
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
......
...@@ -74,9 +74,9 @@ static void urb_print (struct urb * urb, char * str, int small) ...@@ -74,9 +74,9 @@ static void urb_print (struct urb * urb, char * str, int small)
static inline struct ed * static inline struct ed *
dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma); dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
#ifdef OHCI_VERBOSE_DEBUG
/* print non-empty branches of the periodic ed tree */ /* print non-empty branches of the periodic ed tree */
void ohci_dump_periodic (struct ohci_hcd *ohci, char *label) static void __attribute__ ((unused))
ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
{ {
int i, j; int i, j;
u32 *ed_p; u32 *ed_p;
...@@ -101,7 +101,6 @@ void ohci_dump_periodic (struct ohci_hcd *ohci, char *label) ...@@ -101,7 +101,6 @@ void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n", printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
label, ohci->hcd.self.bus_name); label, ohci->hcd.self.bus_name);
} }
#endif
static void ohci_dump_intr_mask (char *label, __u32 mask) static void ohci_dump_intr_mask (char *label, __u32 mask)
{ {
...@@ -241,6 +240,97 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose) ...@@ -241,6 +240,97 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
ohci_dump_roothub (controller, 1); ohci_dump_roothub (controller, 1);
} }
static void ohci_dump_td (char *label, struct td *td)
{
u32 tmp = le32_to_cpup (&td->hwINFO);
dbg ("%s td %p; urb %p index %d; hw next td %08x",
label, td,
td->urb, td->index,
le32_to_cpup (&td->hwNextTD));
if ((tmp & TD_ISO) == 0) {
char *toggle, *pid;
u32 cbp, be;
switch (tmp & TD_T) {
case TD_T_DATA0: toggle = "DATA0"; break;
case TD_T_DATA1: toggle = "DATA1"; break;
case TD_T_TOGGLE: toggle = "(CARRY)"; break;
default: toggle = "(?)"; break;
}
switch (tmp & TD_DP) {
case TD_DP_SETUP: pid = "SETUP"; break;
case TD_DP_IN: pid = "IN"; break;
case TD_DP_OUT: pid = "OUT"; break;
default: pid = "(bad pid)"; break;
}
dbg (" info %08x CC=%x %s DI=%d %s %s", tmp,
TD_CC_GET(tmp), /* EC, */ toggle,
(tmp & TD_DI) >> 21, pid,
(tmp & TD_R) ? "R" : "");
cbp = le32_to_cpup (&td->hwCBP);
be = le32_to_cpup (&td->hwBE);
dbg (" cbp %08x be %08x (len %d)", cbp, be,
cbp ? (be + 1 - cbp) : 0);
} else {
unsigned i;
dbg (" info %08x CC=%x DI=%d START=%04x", tmp,
TD_CC_GET(tmp), /* FC, */
(tmp & TD_DI) >> 21,
tmp & 0x0000ffff);
dbg (" bp0 %08x be %08x",
le32_to_cpup (&td->hwCBP) & ~0x0fff,
le32_to_cpup (&td->hwBE));
for (i = 0; i < MAXPSW; i++) {
dbg (" psw [%d] = %2x", i,
le16_to_cpu (td->hwPSW [i]));
}
}
}
/* caller MUST own hcd spinlock if verbose is set! */
static void __attribute__((unused))
ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
{
u32 tmp = ed->hwINFO;
char *type = "";
dbg ("%s: %s, ed %p state 0x%x type %d; next ed %08x",
ohci->hcd.self.bus_name, label,
ed, ed->state, ed->type,
le32_to_cpup (&ed->hwNextED));
switch (tmp & (ED_IN|ED_OUT)) {
case ED_OUT: type = "-OUT"; break;
case ED_IN: type = "-IN"; break;
/* else from TDs ... control */
}
dbg (" info %08x MAX=%d%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
0x0fff & (le32_to_cpu (tmp) >> 16),
(tmp & ED_ISO) ? " ISO" : "",
(tmp & ED_SKIP) ? " SKIP" : "",
(tmp & ED_LOWSPEED) ? " LOW" : "",
0x000f & (le32_to_cpu (tmp) >> 7),
type,
0x007f & le32_to_cpu (tmp));
dbg (" tds: head %08x%s%s tail %08x%s",
tmp = le32_to_cpup (&ed->hwHeadP),
(ed->hwHeadP & ED_H) ? " HALT" : "",
(ed->hwHeadP & ED_C) ? " CARRY" : "",
le32_to_cpup (&ed->hwTailP),
verbose ? "" : " (not listing)");
if (verbose) {
struct list_head *tmp;
/* use ed->td_list because HC concurrently modifies
* hwNextTD as it accumulates ed_donelist.
*/
list_for_each (tmp, &ed->td_list) {
struct td *td;
td = list_entry (tmp, struct td, td_list);
ohci_dump_td (" ->", td);
}
}
}
#endif #endif
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
* - lots more testing!! * - lots more testing!!
*/ */
#define DRIVER_VERSION "2002-Jun-10" #define DRIVER_VERSION "2002-Jun-15"
#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell" #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
...@@ -145,8 +145,8 @@ static int ohci_urb_enqueue ( ...@@ -145,8 +145,8 @@ static int ohci_urb_enqueue (
urb_print (urb, "SUB", usb_pipein (pipe)); urb_print (urb, "SUB", usb_pipein (pipe));
#endif #endif
/* every endpoint has a ed, locate and fill it */ /* every endpoint has a ed, locate and maybe (re)initialize it */
if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval)))
return -ENOMEM; return -ENOMEM;
/* for the private part of the URB we need the number of TDs (size) */ /* for the private part of the URB we need the number of TDs (size) */
...@@ -498,6 +498,7 @@ static void ohci_irq (struct usb_hcd *hcd) ...@@ -498,6 +498,7 @@ static void ohci_irq (struct usb_hcd *hcd)
struct ohci_regs *regs = ohci->regs; struct ohci_regs *regs = ohci->regs;
int ints; int ints;
/* we can eliminate a (slow) readl() if _only_ WDH caused this irq */
if ((ohci->hcca->done_head != 0) if ((ohci->hcca->done_head != 0)
&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { && ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
ints = OHCI_INTR_WDH; ints = OHCI_INTR_WDH;
......
...@@ -221,6 +221,7 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -221,6 +221,7 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma); ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);
if (ed) { if (ed) {
memset (ed, 0, sizeof (*ed)); memset (ed, 0, sizeof (*ed));
INIT_LIST_HEAD (&ed->td_list);
ed->dma = dma; ed->dma = dma;
/* hash it for later reverse mapping */ /* hash it for later reverse mapping */
if (!hash_add_ed (hc, ed, mem_flags)) { if (!hash_add_ed (hc, ed, mem_flags)) {
......
...@@ -131,8 +131,9 @@ static void intr_resub (struct ohci_hcd *hc, struct urb *urb) ...@@ -131,8 +131,9 @@ static void intr_resub (struct ohci_hcd *hc, struct urb *urb)
/* search for the right branch to insert an interrupt ed into the int tree /* search for the right branch to insert an interrupt ed into the int tree
* do some load balancing; * do some load balancing;
* returns the branch and * returns the branch
* sets the interval to interval = 2^integer (ld (interval)) * FIXME allow for failure, when there's no bandwidth left;
* and consider iso loads too
*/ */
static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load) static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load)
{ {
...@@ -152,19 +153,6 @@ static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load) ...@@ -152,19 +153,6 @@ static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* 2^int ( ld (inter)) */
static int ep_2_n_interval (int inter)
{
int i;
for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++)
continue;
return 1 << i;
}
/*-------------------------------------------------------------------------*/
/* the int tree is a binary tree /* the int tree is a binary tree
* in order to process it sequentially the indexes of the branches have * in order to process it sequentially the indexes of the branches have
* to be mapped the mapping reverses the bits of a word of num_bits length * to be mapped the mapping reverses the bits of a word of num_bits length
...@@ -230,8 +218,7 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi) ...@@ -230,8 +218,7 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
case PIPE_INTERRUPT: case PIPE_INTERRUPT:
load = ed->intriso.intr_info.int_load; load = ed->intriso.intr_info.int_load;
interval = ep_2_n_interval (ed->intriso.intr_info.int_period); interval = ed->interval;
ed->interval = interval;
int_branch = ep_int_balance (ohci, interval, load); int_branch = ep_int_balance (ohci, interval, load);
ed->intriso.intr_info.int_branch = int_branch; ed->intriso.intr_info.int_branch = int_branch;
...@@ -301,6 +288,7 @@ static void periodic_unlink ( ...@@ -301,6 +288,7 @@ static void periodic_unlink (
* just the link to the ed is unlinked. * just the link to the ed is unlinked.
* the link from the ed still points to another operational ed or 0 * 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 * so the HC can eventually finish the processing of the unlinked ed
* caller guarantees the ED has no active TDs.
*/ */
static int start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) static int start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
{ {
...@@ -387,84 +375,99 @@ static int start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -387,84 +375,99 @@ static int start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* (re)init an endpoint; this _should_ be done once at the /* get and maybe (re)init an endpoint. init _should_ be done only as part
* usb_set_configuration command, but the USB stack is a bit stateless * of usb_set_configuration() or usb_set_interface() ... but the USB stack
* so we do it at every transaction. * isn't very stateful, so we re-init whenever the HC isn't looking.
* if the state of the ed is ED_NEW then a dummy td is added and the
* state is changed to ED_UNLINK
* in all other cases the state is left unchanged
* the ed info fields are set even though most of them should
* not change
*/ */
static struct ed *ep_add_ed ( static struct ed *ed_get (
struct ohci_hcd *ohci,
struct usb_device *udev, struct usb_device *udev,
unsigned int pipe, unsigned int pipe,
int interval, int interval
int load,
int mem_flags
) { ) {
struct ohci_hcd *ohci = hcd_to_ohci (udev->bus->hcpriv); int is_out = !usb_pipein (pipe);
int type = usb_pipetype (pipe);
int bus_msecs = 0;
struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv; struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv;
struct td *td;
struct ed *ed; struct ed *ed;
unsigned ep; unsigned ep;
unsigned long flags; unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags);
ep = usb_pipeendpoint (pipe) << 1; ep = usb_pipeendpoint (pipe) << 1;
if (!usb_pipecontrol (pipe) && usb_pipeout (pipe)) if (type != PIPE_CONTROL && is_out)
ep |= 1; ep |= 1;
if (type == PIPE_INTERRUPT)
bus_msecs = usb_calc_bus_time (udev->speed, !is_out, 0,
usb_maxpacket (udev, pipe, is_out)) / 1000;
spin_lock_irqsave (&ohci->lock, flags);
if (!(ed = dev->ep [ep])) { if (!(ed = dev->ep [ep])) {
ed = ed_alloc (ohci, SLAB_ATOMIC); ed = ed_alloc (ohci, SLAB_ATOMIC);
if (!ed) { if (!ed) {
/* out of memory */ /* out of memory */
spin_unlock_irqrestore (&ohci->lock, flags); goto done;
return NULL;
} }
dev->ep [ep] = ed; dev->ep [ep] = ed;
} }
if (ed->state & ED_URB_DEL) { if (ed->state & ED_URB_DEL) {
/* pending unlink request */ /* pending unlink request */
spin_unlock_irqrestore (&ohci->lock, flags); ed = 0;
return NULL; goto done;
} }
if (ed->state == ED_NEW) { if (ed->state == ED_NEW) {
struct td *td;
ed->hwINFO = ED_SKIP; ed->hwINFO = ED_SKIP;
/* dummy td; end of td list for ed */ /* dummy td; end of td list for ed */
td = td_alloc (ohci, SLAB_ATOMIC); td = td_alloc (ohci, SLAB_ATOMIC);
if (!td) { if (!td) {
/* out of memory */ /* out of memory */
spin_unlock_irqrestore (&ohci->lock, flags); ed = 0;
return NULL; goto done;
} }
ed->dummy = td; ed->dummy = td;
ed->hwTailP = cpu_to_le32 (td->td_dma); ed->hwTailP = cpu_to_le32 (td->td_dma);
ed->hwHeadP = ed->hwTailP; /* ED_C, ED_H zeroed */ ed->hwHeadP = ed->hwTailP; /* ED_C, ED_H zeroed */
ed->state = ED_UNLINK; ed->state = ED_UNLINK;
ed->type = usb_pipetype (pipe); ed->type = type;
} }
// FIXME: don't do this if it's linked to the HC, or without knowing it's /* FIXME: Don't do this without knowing it's safe to clobber this
// safe to clobber state/mode info tied to (previous) config/altsetting. * state/mode info. Currently the upper layers don't support such
// (but dev0/ep0, used by set_address, must get clobbered) * guarantees; we're lucky changing config/altsetting is rare.
*/
ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe) if (ed->state == ED_UNLINK) {
| usb_pipeendpoint (pipe) << 7 u32 info;
| (usb_pipeisoc (pipe)? 0x8000: 0)
| (usb_pipecontrol (pipe) info = usb_pipedevice (pipe);
? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) info |= (ep >> 1) << 7;
| (udev->speed == USB_SPEED_LOW) << 13 info |= usb_maxpacket (udev, pipe, is_out) << 16;
| usb_maxpacket (udev, pipe, usb_pipeout (pipe)) info = cpu_to_le32 (info);
<< 16); if (udev->speed == USB_SPEED_LOW)
info |= ED_LOWSPEED;
if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) { /* control transfers store pids in tds */
ed->intriso.intr_info.int_period = interval; if (type != PIPE_CONTROL) {
ed->intriso.intr_info.int_load = load; info |= is_out ? ED_OUT : ED_IN;
} if (type == PIPE_ISOCHRONOUS)
info |= ED_ISO;
if (type == PIPE_INTERRUPT) {
ed->intriso.intr_info.int_load = bus_msecs;
if (interval > 32)
interval = 32;
}
}
ed->hwINFO = info;
/* value ignored except on periodic EDs, where
* we know it's already a power of 2
*/
ed->interval = interval;
}
done:
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
return ed; return ed;
} }
...@@ -736,8 +739,8 @@ static void td_done (struct urb *urb, struct td *td) ...@@ -736,8 +739,8 @@ static void td_done (struct urb *urb, struct td *td)
urb->iso_frame_desc [td->index].status = cc_to_error [cc]; urb->iso_frame_desc [td->index].status = cc_to_error [cc];
if (cc != 0) if (cc != 0)
dbg (" urb %p iso TD %d len %d CC %d", dbg (" urb %p iso TD %p (%d) len %d CC %d",
urb, td->index, dlen, cc); urb, td, 1 + td->index, dlen, cc);
/* BULK, INT, CONTROL ... drivers see aggregate length/status, /* BULK, INT, CONTROL ... drivers see aggregate length/status,
* except that "setup" bytes aren't counted and "short" transfers * except that "setup" bytes aren't counted and "short" transfers
...@@ -776,9 +779,13 @@ static void td_done (struct urb *urb, struct td *td) ...@@ -776,9 +779,13 @@ static void td_done (struct urb *urb, struct td *td)
- td->data_dma; - td->data_dma;
} }
#ifdef VERBOSE_DEBUG
if (cc != 0) if (cc != 0)
dbg (" urb %p TD %d CC %d, len=%d", dbg (" urb %p TD %p (%d) CC %d, len=%d/%d",
urb, td->index, cc, urb->actual_length); urb, td, 1 + td->index, cc,
urb->actual_length,
urb->transfer_buffer_length);
#endif
} }
} }
...@@ -812,8 +819,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) ...@@ -812,8 +819,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
if (urb_priv && ((td_list->index + 1) if (urb_priv && ((td_list->index + 1)
< urb_priv->length)) { < urb_priv->length)) {
#ifdef OHCI_VERBOSE_DEBUG #ifdef OHCI_VERBOSE_DEBUG
dbg ("urb %p TD %d of %d, patch ED", dbg ("urb %p TD %p (%d/%d), patch ED",
td_list->urb, td_list->urb, td_list,
1 + td_list->index, 1 + td_list->index,
urb_priv->length); urb_priv->length);
#endif #endif
......
...@@ -19,7 +19,7 @@ struct ed { ...@@ -19,7 +19,7 @@ struct ed {
#define ED_SKIP __constant_cpu_to_le32(1 << 14) #define ED_SKIP __constant_cpu_to_le32(1 << 14)
#define ED_LOWSPEED __constant_cpu_to_le32(1 << 13) #define ED_LOWSPEED __constant_cpu_to_le32(1 << 13)
#define ED_OUT __constant_cpu_to_le32(0x01 << 11) #define ED_OUT __constant_cpu_to_le32(0x01 << 11)
#define ED_IN __constant_cpu_to_le32(0x10 << 11) #define ED_IN __constant_cpu_to_le32(0x02 << 11)
__u32 hwTailP; /* tail of TD list */ __u32 hwTailP; /* tail of TD list */
__u32 hwHeadP; /* head of TD list */ __u32 hwHeadP; /* head of TD list */
#define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */ #define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */
...@@ -30,24 +30,24 @@ struct ed { ...@@ -30,24 +30,24 @@ struct ed {
dma_addr_t dma; /* addr of ED */ dma_addr_t dma; /* addr of ED */
struct ed *ed_prev; /* for non-interrupt EDs */ struct ed *ed_prev; /* for non-interrupt EDs */
struct td *dummy; struct td *dummy;
struct list_head td_list; /* "shadow list" of our TDs */
u8 state; /* ED_{NEW,UNLINK,OPER} */
#define ED_NEW 0x00 /* unused, no dummy td */
#define ED_UNLINK 0x01 /* dummy td, maybe linked to hc */
#define ED_OPER 0x02 /* dummy td, _is_ linked to hc */
#define ED_URB_DEL 0x08 /* for unlinking; masked in */
u8 type; /* PIPE_{BULK,...} */ u8 type; /* PIPE_{BULK,...} */
u8 interval; /* interrupt, isochronous */ u16 interval; /* interrupt, isochronous */
union { union {
struct intr_info { /* interrupt */ struct intr_info { /* interrupt */
u8 int_period;
u8 int_branch; u8 int_branch;
u8 int_load; u8 int_load;
} intr_info; } intr_info;
u16 last_iso; /* isochronous */ u16 last_iso; /* isochronous */
} intriso; } intriso;
u8 state; /* ED_{NEW,UNLINK,OPER} */
#define ED_NEW 0x00 /* unused, no dummy td */
#define ED_UNLINK 0x01 /* dummy td, maybe linked to hc */
#define ED_OPER 0x02 /* dummy td, _is_ linked to hc */
#define ED_URB_DEL 0x08 /* for unlinking; masked in */
/* HC may see EDs on rm_list until next frame (frame_no == tick) */ /* HC may see EDs on rm_list until next frame (frame_no == tick) */
u16 tick; u16 tick;
struct ed *ed_rm_list; struct ed *ed_rm_list;
...@@ -108,6 +108,8 @@ struct td { ...@@ -108,6 +108,8 @@ struct td {
dma_addr_t td_dma; /* addr of this TD */ dma_addr_t td_dma; /* addr of this TD */
dma_addr_t data_dma; /* addr of data it points to */ dma_addr_t data_dma; /* addr of data it points to */
struct list_head td_list; /* "shadow list", TDs on same ED */
} __attribute__ ((aligned(32))); /* c/b/i need 16; only iso needs 32 */ } __attribute__ ((aligned(32))); /* c/b/i need 16; only iso needs 32 */
#define TD_MASK ((u32)~0x1f) /* strip hw status in low addr bits */ #define TD_MASK ((u32)~0x1f) /* strip hw status in low addr bits */
......
...@@ -220,10 +220,11 @@ struct kaweth_device ...@@ -220,10 +220,11 @@ struct kaweth_device
struct urb *rx_urb; struct urb *rx_urb;
struct urb *tx_urb; struct urb *tx_urb;
struct urb *irq_urb; struct urb *irq_urb;
struct sk_buff *tx_skb;
__u8 *firmware_buf; __u8 *firmware_buf;
__u8 scratch[KAWETH_SCRATCH_SIZE]; __u8 scratch[KAWETH_SCRATCH_SIZE];
__u8 tx_buf[KAWETH_BUF_SIZE];
__u8 rx_buf[KAWETH_BUF_SIZE]; __u8 rx_buf[KAWETH_BUF_SIZE];
__u8 intbuffer[INTBUFFERSIZE]; __u8 intbuffer[INTBUFFERSIZE];
__u16 packet_filter_bitmap; __u16 packet_filter_bitmap;
...@@ -650,11 +651,13 @@ static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd) ...@@ -650,11 +651,13 @@ static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
static void kaweth_usb_transmit_complete(struct urb *urb) static void kaweth_usb_transmit_complete(struct urb *urb)
{ {
struct kaweth_device *kaweth = urb->context; struct kaweth_device *kaweth = urb->context;
struct sk_buff *skb = kaweth->tx_skb;
if (unlikely(urb->status != 0)) if (unlikely(urb->status != 0))
kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
netif_wake_queue(kaweth->net); netif_wake_queue(kaweth->net);
dev_kfree_skb(skb);
} }
/**************************************************************** /****************************************************************
...@@ -663,7 +666,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb) ...@@ -663,7 +666,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb)
static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
{ {
struct kaweth_device *kaweth = net->priv; struct kaweth_device *kaweth = net->priv;
int count = skb->len; char *private_header;
int res; int res;
...@@ -679,15 +682,30 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -679,15 +682,30 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth_async_set_rx_mode(kaweth); kaweth_async_set_rx_mode(kaweth);
netif_stop_queue(net); netif_stop_queue(net);
*((__u16 *)kaweth->tx_buf) = cpu_to_le16(skb->len); /* We now decide whether we can put our special header into the sk_buff */
if (skb_cloned(skb) || skb_headroom(skb) < 2) {
/* no such luck - we make our own */
struct sk_buff *copied_skb;
copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC);
dev_kfree_skb_any(skb);
skb = copied_skb;
if (!copied_skb) {
kaweth->stats.tx_errors++;
netif_start_queue(net);
spin_unlock(&kaweth->device_lock);
return 0;
}
}
memcpy(kaweth->tx_buf + 2, skb->data, skb->len); private_header = __skb_push(skb, 2);
*private_header = cpu_to_le16(skb->len);
kaweth->tx_skb = skb;
FILL_BULK_URB(kaweth->tx_urb, FILL_BULK_URB(kaweth->tx_urb,
kaweth->dev, kaweth->dev,
usb_sndbulkpipe(kaweth->dev, 2), usb_sndbulkpipe(kaweth->dev, 2),
kaweth->tx_buf, private_header,
count + 2, skb->len,
kaweth_usb_transmit_complete, kaweth_usb_transmit_complete,
kaweth); kaweth);
kaweth->end = 0; kaweth->end = 0;
...@@ -699,6 +717,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -699,6 +717,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth->stats.tx_errors++; kaweth->stats.tx_errors++;
netif_start_queue(net); netif_start_queue(net);
dev_kfree_skb(skb);
} }
else else
{ {
...@@ -707,8 +726,6 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -707,8 +726,6 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
net->trans_start = jiffies; net->trans_start = jiffies;
} }
dev_kfree_skb(skb);
spin_unlock(&kaweth->device_lock); spin_unlock(&kaweth->device_lock);
return 0; return 0;
......
...@@ -51,12 +51,6 @@ ...@@ -51,12 +51,6 @@
#include <linux/slab.h> #include <linux/slab.h>
/*
* kernel thread actions
*/
#define US_ACT_COMMAND 1
#define US_ACT_EXIT 5
/*********************************************************************** /***********************************************************************
* Host functions * Host functions
...@@ -204,7 +198,7 @@ static int device_reset( Scsi_Cmnd *srb ) ...@@ -204,7 +198,7 @@ static int device_reset( Scsi_Cmnd *srb )
US_DEBUGP("device_reset() called\n" ); US_DEBUGP("device_reset() called\n" );
/* if the device was removed, then we're already reset */ /* if the device was removed, then we're already reset */
if (atomic_read(&us->sm_state) == US_STATE_DETACHED) if (!test_bit(DEV_ATTACHED, &us->bitflags))
return SUCCESS; return SUCCESS;
scsi_unlock(srb->host); scsi_unlock(srb->host);
...@@ -235,7 +229,7 @@ static int bus_reset( Scsi_Cmnd *srb ) ...@@ -235,7 +229,7 @@ static int bus_reset( Scsi_Cmnd *srb )
US_DEBUGP("bus_reset() called\n"); US_DEBUGP("bus_reset() called\n");
/* if the device has been removed, this worked */ /* if the device has been removed, this worked */
if (atomic_read(&us->sm_state) == US_STATE_DETACHED) { if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
US_DEBUGP("-- device removed already\n"); US_DEBUGP("-- device removed already\n");
return SUCCESS; return SUCCESS;
} }
...@@ -337,8 +331,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length, ...@@ -337,8 +331,8 @@ static int proc_info (char *buffer, char **start, off_t offset, int length,
/* show the GUID of the device */ /* show the GUID of the device */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
SPRINTF(" Attached: %s\n", (atomic_read(&us->sm_state) == SPRINTF(" Attached: %s\n", (test_bit(DEV_ATTACHED, &us->bitflags)
US_STATE_DETACHED) ? "Yes" : "No"); ? "Yes" : "No"));
/* /*
* Calculate start of next buffer, and return value. * Calculate start of next buffer, and return value.
......
...@@ -99,13 +99,6 @@ MODULE_LICENSE("GPL"); ...@@ -99,13 +99,6 @@ MODULE_LICENSE("GPL");
static int my_host_number; static int my_host_number;
/*
* kernel thread actions
*/
#define US_ACT_COMMAND 1
#define US_ACT_EXIT 5
/* The list of structures and the protective lock for them */ /* The list of structures and the protective lock for them */
struct us_data *us_list; struct us_data *us_list;
struct semaphore us_list_semaphore; struct semaphore us_list_semaphore;
...@@ -426,7 +419,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -426,7 +419,7 @@ static int usb_stor_control_thread(void * __us)
down(&(us->dev_semaphore)); down(&(us->dev_semaphore));
/* our device has gone - pretend not ready */ /* our device has gone - pretend not ready */
if (atomic_read(&us->device_state) == US_STATE_DETACHED) { if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
US_DEBUGP("Request is for removed device\n"); US_DEBUGP("Request is for removed device\n");
/* For REQUEST_SENSE, it's the data. But /* For REQUEST_SENSE, it's the data. But
* for anything else, it should look like * for anything else, it should look like
...@@ -450,7 +443,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -450,7 +443,7 @@ static int usb_stor_control_thread(void * __us)
sizeof(usb_stor_sense_notready)); sizeof(usb_stor_sense_notready));
us->srb->result = CHECK_CONDITION << 1; us->srb->result = CHECK_CONDITION << 1;
} }
} else { /* atomic_read(&us->device_state) == STATE_DETACHED */ } else { /* test_bit(DEV_ATTACHED, &us->bitflags) */
/* Handle those devices which need us to fake /* Handle those devices which need us to fake
* their inquiry data */ * their inquiry data */
...@@ -557,9 +550,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -557,9 +550,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
unsigned int flags; unsigned int flags;
struct us_unusual_dev *unusual_dev; struct us_unusual_dev *unusual_dev;
struct us_data *ss = NULL; struct us_data *ss = NULL;
#ifdef CONFIG_USB_STORAGE_SDDR09
int result; int result;
#endif int new_device = 0;
/* these are temporary copies -- we test on these, then put them /* these are temporary copies -- we test on these, then put them
* in the us-data structure * in the us-data structure
...@@ -570,13 +562,13 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -570,13 +562,13 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
u8 subclass = 0; u8 subclass = 0;
u8 protocol = 0; u8 protocol = 0;
/* the altsettting on the interface we're probing that matched our /* the altsetting on the interface we're probing that matched our
* usb_match_id table * usb_match_id table
*/ */
struct usb_interface *intf = dev->actconfig->interface; struct usb_interface *intf = dev->actconfig->interface;
struct usb_interface_descriptor *altsetting = struct usb_interface_descriptor *altsetting =
intf[ifnum].altsetting + intf[ifnum].act_altsetting; intf[ifnum].altsetting + intf[ifnum].act_altsetting;
US_DEBUGP("act_altsettting is %d\n", intf[ifnum].act_altsetting); US_DEBUGP("act_altsetting is %d\n", intf[ifnum].act_altsetting);
/* clear the temporary strings */ /* clear the temporary strings */
memset(mf, 0, sizeof(mf)); memset(mf, 0, sizeof(mf));
...@@ -663,7 +655,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -663,7 +655,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
return NULL; return NULL;
} }
/* At this point, we're committed to using the device */ /* At this point, we've decided to try to use the device */
usb_get_dev(dev); usb_get_dev(dev);
/* clear the GUID and fetch the strings */ /* clear the GUID and fetch the strings */
...@@ -696,7 +688,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -696,7 +688,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
*/ */
ss = us_list; ss = us_list;
while ((ss != NULL) && while ((ss != NULL) &&
((ss->pusb_dev) || !GUID_EQUAL(guid, ss->guid))) (test_bit(DEV_ATTACHED, &ss->bitflags) ||
!GUID_EQUAL(guid, ss->guid)))
ss = ss->next; ss = ss->next;
if (ss != NULL) { if (ss != NULL) {
...@@ -710,29 +703,23 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -710,29 +703,23 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* establish the connection to the new device upon reconnect */ /* establish the connection to the new device upon reconnect */
ss->ifnum = ifnum; ss->ifnum = ifnum;
ss->pusb_dev = dev; ss->pusb_dev = dev;
atomic_set(&ss->device_state, US_STATE_ATTACHED); set_bit(DEV_ATTACHED, &ss->bitflags);
/* copy over the endpoint data */ /* copy over the endpoint data */
if (ep_in) ss->ep_in = ep_in->bEndpointAddress &
ss->ep_in = ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
USB_ENDPOINT_NUMBER_MASK; ss->ep_out = ep_out->bEndpointAddress &
if (ep_out) USB_ENDPOINT_NUMBER_MASK;
ss->ep_out = ep_out->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
ss->ep_int = ep_int; ss->ep_int = ep_int;
/* allocate an IRQ callback if one is needed */ /* allocate an IRQ callback if one is needed */
if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
usb_put_dev(dev); goto BadDevice;
return NULL;
}
/* allocate the URB we're going to use */ /* allocate the URB we're going to use */
ss->current_urb = usb_alloc_urb(0, GFP_KERNEL); ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ss->current_urb) { if (!ss->current_urb)
usb_put_dev(dev); goto BadDevice;
return NULL;
}
/* Re-Initialize the device if it needs it */ /* Re-Initialize the device if it needs it */
if (unusual_dev && unusual_dev->initFunction) if (unusual_dev && unusual_dev->initFunction)
...@@ -752,14 +739,12 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -752,14 +739,12 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
return NULL; return NULL;
} }
memset(ss, 0, sizeof(struct us_data)); memset(ss, 0, sizeof(struct us_data));
new_device = 1;
/* allocate the URB we're going to use */ /* allocate the URB we're going to use */
ss->current_urb = usb_alloc_urb(0, GFP_KERNEL); ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ss->current_urb) { if (!ss->current_urb)
kfree(ss); goto BadDevice;
usb_put_dev(dev);
return NULL;
}
/* Initialize the mutexes only when the struct is new */ /* Initialize the mutexes only when the struct is new */
init_completion(&(ss->notify)); init_completion(&(ss->notify));
...@@ -776,12 +761,10 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -776,12 +761,10 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
ss->unusual_dev = unusual_dev; ss->unusual_dev = unusual_dev;
/* copy over the endpoint data */ /* copy over the endpoint data */
if (ep_in) ss->ep_in = ep_in->bEndpointAddress &
ss->ep_in = ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
USB_ENDPOINT_NUMBER_MASK; ss->ep_out = ep_out->bEndpointAddress &
if (ep_out) USB_ENDPOINT_NUMBER_MASK;
ss->ep_out = ep_out->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
ss->ep_int = ep_int; ss->ep_int = ep_int;
/* establish the connection to the new device */ /* establish the connection to the new device */
...@@ -904,12 +887,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -904,12 +887,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
#endif #endif
default: default:
ss->transport_name = "Unknown"; /* ss->transport_name = "Unknown"; */
kfree(ss->current_urb); goto BadDevice;
kfree(ss);
usb_put_dev(dev);
return NULL;
break;
} }
US_DEBUGP("Transport: %s\n", ss->transport_name); US_DEBUGP("Transport: %s\n", ss->transport_name);
...@@ -959,22 +938,14 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -959,22 +938,14 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
#endif #endif
default: default:
ss->protocol_name = "Unknown"; /* ss->protocol_name = "Unknown"; */
kfree(ss->current_urb); goto BadDevice;
kfree(ss);
usb_put_dev(dev);
return NULL;
break;
} }
US_DEBUGP("Protocol: %s\n", ss->protocol_name); US_DEBUGP("Protocol: %s\n", ss->protocol_name);
/* allocate an IRQ callback if one is needed */ /* allocate an IRQ callback if one is needed */
if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) { if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
kfree(ss->current_urb); goto BadDevice;
kfree(ss);
usb_put_dev(dev);
return NULL;
}
/* /*
* Since this is a new device, we need to generate a scsi * Since this is a new device, we need to generate a scsi
...@@ -1001,16 +972,13 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1001,16 +972,13 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* start up our control thread */ /* start up our control thread */
atomic_set(&ss->sm_state, US_STATE_IDLE); atomic_set(&ss->sm_state, US_STATE_IDLE);
atomic_set(&ss->device_state, US_STATE_ATTACHED); set_bit(DEV_ATTACHED, &ss->bitflags);
ss->pid = kernel_thread(usb_stor_control_thread, ss, ss->pid = kernel_thread(usb_stor_control_thread, ss,
CLONE_VM); CLONE_VM);
if (ss->pid < 0) { if (ss->pid < 0) {
printk(KERN_WARNING USB_STORAGE printk(KERN_WARNING USB_STORAGE
"Unable to start control thread\n"); "Unable to start control thread\n");
kfree(ss->current_urb); goto BadDevice;
kfree(ss);
usb_put_dev(dev);
return NULL;
} }
/* wait for the thread to start */ /* wait for the thread to start */
...@@ -1018,7 +986,17 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1018,7 +986,17 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* now register - our detect function will be called */ /* now register - our detect function will be called */
ss->htmplt.module = THIS_MODULE; ss->htmplt.module = THIS_MODULE;
scsi_register_host(&(ss->htmplt)); result = scsi_register_host(&(ss->htmplt));
if (result) {
printk(KERN_WARNING USB_STORAGE
"Unable to register the scsi host\n");
/* tell the control thread to exit */
ss->action = US_ACT_EXIT;
up(&ss->sema);
wait_for_completion(&ss->notify);
goto BadDevice;
}
/* lock access to the data structures */ /* lock access to the data structures */
down(&us_list_semaphore); down(&us_list_semaphore);
...@@ -1038,6 +1016,31 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1038,6 +1016,31 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* return a pointer for the disconnect function */ /* return a pointer for the disconnect function */
return ss; return ss;
/* we come here if there are any problems */
BadDevice:
US_DEBUGP("storage_probe() failed\n");
down(&ss->irq_urb_sem);
if (ss->irq_urb) {
usb_unlink_urb(ss->irq_urb);
usb_free_urb(ss->irq_urb);
ss->irq_urb = NULL;
}
up(&ss->irq_urb_sem);
if (ss->current_urb) {
usb_unlink_urb(ss->current_urb);
usb_free_urb(ss->current_urb);
ss->current_urb = NULL;
}
clear_bit(DEV_ATTACHED, &ss->bitflags);
ss->pusb_dev = NULL;
if (new_device)
kfree(ss);
else
up(&ss->dev_semaphore);
usb_put_dev(dev);
return NULL;
} }
/* Handle a disconnect event from the USB core */ /* Handle a disconnect event from the USB core */
...@@ -1078,7 +1081,7 @@ static void storage_disconnect(struct usb_device *dev, void *ptr) ...@@ -1078,7 +1081,7 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
/* mark the device as gone */ /* mark the device as gone */
usb_put_dev(ss->pusb_dev); usb_put_dev(ss->pusb_dev);
ss->pusb_dev = NULL; ss->pusb_dev = NULL;
atomic_set(&ss->sm_state, US_STATE_DETACHED); clear_bit(DEV_ATTACHED, &ss->bitflags);
/* unlock access to the device data structure */ /* unlock access to the device data structure */
up(&(ss->dev_semaphore)); up(&(ss->dev_semaphore));
......
...@@ -103,9 +103,10 @@ struct us_unusual_dev { ...@@ -103,9 +103,10 @@ struct us_unusual_dev {
#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */
#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */
/* device attached/detached states */
#define US_STATE_DETACHED 1 /* kernel thread actions */
#define US_STATE_ATTACHED 2 #define US_ACT_COMMAND 1
#define US_ACT_EXIT 5
/* processing state machine states */ /* processing state machine states */
#define US_STATE_IDLE 1 #define US_STATE_IDLE 1
...@@ -127,10 +128,9 @@ struct us_data { ...@@ -127,10 +128,9 @@ struct us_data {
/* The device we're working with /* The device we're working with
* It's important to note: * It's important to note:
* (o) you must hold dev_semaphore to change pusb_dev * (o) you must hold dev_semaphore to change pusb_dev
* (o) device_state should change whenever pusb_dev does * (o) DEV_ATTACHED in bitflags should change whenever pusb_dev does
*/ */
struct semaphore dev_semaphore; /* protect pusb_dev */ struct semaphore dev_semaphore; /* protect pusb_dev */
atomic_t device_state; /* attached or detached */
struct usb_device *pusb_dev; /* this usb_device */ struct usb_device *pusb_dev; /* this usb_device */
unsigned int flags; /* from filter initially */ unsigned int flags; /* from filter initially */
...@@ -174,6 +174,7 @@ struct us_data { ...@@ -174,6 +174,7 @@ struct us_data {
struct semaphore ip_waitq; /* for CBI interrupts */ struct semaphore ip_waitq; /* for CBI interrupts */
unsigned long bitflags; /* single-bit flags: */ unsigned long bitflags; /* single-bit flags: */
#define IP_WANTED 1 /* is an IRQ expected? */ #define IP_WANTED 1 /* is an IRQ expected? */
#define DEV_ATTACHED 2 /* is the dev. attached?*/
/* interrupt communications data */ /* interrupt communications data */
struct semaphore irq_urb_sem; /* to protect irq_urb */ struct semaphore irq_urb_sem; /* to protect irq_urb */
......
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