Commit 9cfc20f1 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/linux/linux/BK/bleeding-2.5

into kroah.com:/home/linux/linux/BK/gregkh-2.5
parents 8263f8c5 9dbfec80
......@@ -36,26 +36,7 @@ CONFIG_USB_OHCI_HCD
The module will be called ohci-hcd.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_UHCI
The Universal Host Controller Interface is a standard by Intel for
accessing the USB hardware in the PC (which is also called the USB
host controller). If your USB host controller conforms to this
standard, you may want to say Y, but see below. All recent boards
with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
i810, i820) conform to this standard. Also all VIA PCI chipsets
(like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
133).
Currently there exist two drivers for UHCI host controllers: this
one and the so-called JE driver, which you can get from
"UHCI alternate (JE) support", below. You need only one.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called usb-uhci.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_UHCI_ALT
CONFIG_USB_UHCI_HCD_ALT
The Universal Host Controller Interface is a standard by Intel for
accessing the USB hardware in the PC (which is also called the USB
host controller). If your USB host controller conforms to this
......@@ -65,31 +46,11 @@ CONFIG_USB_UHCI_ALT
(like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
133). If unsure, say Y.
Currently there exist two drivers for UHCI host controllers: this
so-called JE driver, and the one you get from "UHCI support", above.
You need only one.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called uhci.o. If you want to compile it as a
The module will be called uhci-hcd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_OHCI
The Open Host Controller Interface is a standard by
Compaq/Microsoft/National for accessing the USB PC hardware (also
called USB host controller). If your USB host controller conforms to
this standard, say Y. The USB host controllers on most non-Intel
architectures and on several x86 compatibles with non-Intel chipsets
-- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V,
Aladdin Pro..) -- conform to this standard.
You may want to read <file:Documentation/usb/ohci.txt>.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called usb-ohci.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_SL811HS
Say Y here if you have a SL811HS USB host controller in your system.
......
......@@ -2,23 +2,9 @@
# USB Host Controller Drivers
#
comment 'USB Host Controller Drivers'
dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
if [ "$CONFIG_USB_UHCI_HCD_ALT" != "y" ]; then
dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
fi
if [ "$CONFIG_USB_UHCI_HCD" != "y" ]; then
dep_tristate ' UHCI HCD Alternate (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
fi
#if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
# dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
#fi
#if [ "$CONFIG_USB_UHCI" != "y" ]; then
# dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
#else
# define_bool CONFIG_USB_UHCI_ALT n
#fi
#dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
dep_tristate ' EHCI HCD (USB 2.0) support' CONFIG_USB_EHCI_HCD $CONFIG_USB
dep_tristate ' OHCI HCD support' CONFIG_USB_OHCI_HCD $CONFIG_USB
dep_tristate ' UHCI HCD (most Intel and VIA) support' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB
if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB
dep_tristate ' SL811HS support' CONFIG_USB_SL811HS $CONFIG_USB
......
......@@ -190,6 +190,8 @@ static void ohci_dump_roothub (struct ohci_hcd *controller, int verbose)
__u32 temp, ndp, i;
temp = roothub_a (controller);
if (temp == ~(u32)0)
return;
ndp = (temp & RH_A_NDP);
if (verbose) {
......
......@@ -502,11 +502,19 @@ static void ohci_irq (struct usb_hcd *hcd)
if ((ohci->hcca->done_head != 0)
&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
} else if ((ints = (readl (&regs->intrstatus)
& readl (&regs->intrenable))) == 0) {
/* cardbus/... hardware gone before remove() */
} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
ohci->disabled++;
err ("%s device removed!", hcd->self.bus_name);
return;
/* interrupt for some other device? */
} else if ((ints &= readl (&regs->intrenable)) == 0) {
return;
}
// dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
if (ints & OHCI_INTR_UE) {
......
......@@ -1665,37 +1665,15 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
uhci_unlink_generic(uhci, urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urbp->status = urb->status = -ECONNABORTED;
spin_lock(&uhci->urb_remove_list_lock);
spin_lock(&uhci->urb_remove_list_lock);
/* If we're the first, set the next interrupt bit */
if (list_empty(&uhci->urb_remove_list))
uhci_set_next_interrupt(uhci);
list_add(&urbp->urb_list, &uhci->urb_remove_list);
spin_unlock(&uhci->urb_remove_list_lock);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
} else {
urb->status = -ENOENT;
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
if (in_interrupt()) { /* wait at least 1 frame */
static int errorcount = 10;
if (errorcount--)
dbg("uhci_urb_dequeue called from interrupt for urb %p", urb);
udelay(1000);
} else
schedule_timeout(1+1*HZ/1000);
uhci_finish_urb(hcd, urb);
}
/* If we're the first, set the next interrupt bit */
if (list_empty(&uhci->urb_remove_list))
uhci_set_next_interrupt(uhci);
list_add(&urbp->urb_list, &uhci->urb_remove_list);
spin_unlock(&uhci->urb_remove_list_lock);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
return 0;
}
......@@ -1788,7 +1766,7 @@ static void stall_callback(unsigned long ptr)
tmp = tmp->next;
u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
u->transfer_flags |= USB_TIMEOUT_KILLED;
uhci_urb_dequeue(hcd, u);
}
......
......@@ -271,21 +271,15 @@ static int uhci_urb_enqueue (struct usb_hcd *hcd, struct urb *urb, int mem_flags
static int uhci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags=0;
struct uhci_hcd *uhci;
struct uhci_hcd *uhci = hcd_to_uhci (hcd);
int ret;
dbg("uhci_urb_dequeue called for %p",urb);
uhci = hcd_to_uhci (hcd);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
int ret;
spin_lock_irqsave (&uhci->urb_list_lock, flags);
ret = uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
return ret;
}
else
return uhci_unlink_urb_sync(uhci, urb);
spin_lock_irqsave (&uhci->urb_list_lock, flags);
ret = uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
return ret;
}
/*--------------------------------------------------------------------------*/
static int uhci_get_frame (struct usb_hcd *hcd)
......
......@@ -541,22 +541,6 @@ static void uhci_clean_iso_step1(struct uhci_hcd *uhci, urb_priv_t *urb_priv)
}
}
/*-------------------------------------------------------------------*/
static void uhci_clean_iso_step2(struct uhci_hcd *uhci, urb_priv_t *urb_priv)
{
struct list_head *p;
uhci_desc_t *td;
int now=UHCI_GET_CURRENT_FRAME(uhci);
dbg("uhci_clean_iso_step2");
while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
td = list_entry (p, uhci_desc_t, desc_list);
list_del (p);
INIT_LIST_HEAD(&td->horizontal);
list_add_tail (&td->horizontal, &uhci->free_desc_td);
td->last_used=now;
}
}
/*-------------------------------------------------------------------*/
/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
......@@ -759,44 +743,6 @@ static int uhci_unlink_urb_async (struct uhci_hcd *uhci, struct urb *urb, int mo
return 0; // completion will follow
}
/*-------------------------------------------------------------------*/
// kills an urb by unlinking descriptors and waiting for at least one frame
static int uhci_unlink_urb_sync (struct uhci_hcd *uhci, struct urb *urb)
{
uhci_desc_t *qh;
urb_priv_t *urb_priv;
unsigned long flags=0;
spin_lock_irqsave (&uhci->urb_list_lock, flags);
// err("uhci_unlink_urb_sync %p, %i",urb,urb->status);
// move descriptors out the the running chains, dequeue urb
uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_DONT_STORE);
urb_priv = urb->hcpriv;
spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
// cleanup the rest
switch (usb_pipetype (urb->pipe)) {
case PIPE_INTERRUPT:
case PIPE_ISOCHRONOUS:
uhci_wait_ms(1);
uhci_clean_iso_step2(uhci, urb_priv);
break;
case PIPE_BULK:
case PIPE_CONTROL:
qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
uhci_clean_transfer(uhci, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
uhci_wait_ms(1);
}
urb->status = -ENOENT; // mark urb as killed
finish_urb(uhci,urb);
return 0;
}
/*-------------------------------------------------------------------*/
// unlink urbs for specific device or all devices
static void uhci_unlink_urbs(struct uhci_hcd *uhci, struct usb_device *usb_dev, int remove_all)
{
......@@ -816,8 +762,6 @@ static void uhci_unlink_urbs(struct uhci_hcd *uhci, struct usb_device *usb_dev,
// err("unlink urb: %p, dev %p, ud %p", urb, usb_dev,urb->dev);
//urb->transfer_flags |=USB_ASYNC_UNLINK;
if (remove_all || (usb_dev == urb->dev)) {
spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
err("forced removing of queued URB %p due to disconnect",urb);
......@@ -850,7 +794,7 @@ static void uhci_check_timeouts(struct uhci_hcd *uhci)
type = usb_pipetype (urb->pipe);
if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
urb->transfer_flags |= USB_TIMEOUT_KILLED;
async_dbg("uhci_check_timeout: timeout for %p",urb);
uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
}
......
/*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
**
** Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
**
**
** ChangeLog:
** .... Most of the time spend reading sources & docs.
** v0.2.x First official release for the Linux kernel.
** v0.3.0 Beutified and structured, some bugs fixed.
** v0.3.x URBifying bulk requests and bugfixing. First relatively
** stable release. Still can touch device's registers only
** from top-halves.
** v0.4.0 Control messages remained unurbified are now URBs.
** Now we can touch the HW at any time.
** v0.4.9 Control urbs again use process context to wait. Argh...
** Some long standing bugs (enable_net_traffic) fixed.
** Also nasty trick about resubmiting control urb from
** interrupt context used. Please let me know how it
** behaves. Pegasus II support added since this version.
** TODO: suppressing HCD warnings spewage on disconnect.
** v0.4.13 Ethernet address is now set at probe(), not at open()
** time as this seems to break dhcpd.
** v0.5.0 branch to 2.5.x kernels
** v0.5.1 ethtool support added
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* ChangeLog:
* .... Most of the time spent on reading sources & docs.
* v0.2.x First official release for the Linux kernel.
* v0.3.0 Beutified and structured, some bugs fixed.
* v0.3.x URBifying bulk requests and bugfixing. First relatively
* stable release. Still can touch device's registers only
* from top-halves.
* v0.4.0 Control messages remained unurbified are now URBs.
* Now we can touch the HW at any time.
* v0.4.9 Control urbs again use process context to wait. Argh...
* Some long standing bugs (enable_net_traffic) fixed.
* Also nasty trick about resubmiting control urb from
* interrupt context used. Please let me know how it
* behaves. Pegasus II support added since this version.
* TODO: suppressing HCD warnings spewage on disconnect.
* v0.4.13 Ethernet address is now set at probe(), not at open()
* time as this seems to break dhcpd.
* v0.5.0 branch to 2.5.x kernels
* v0.5.1 ethtool support added
* v0.5.5 rx socket buffers are in a pool and the their allocation
* is out of the interrupt routine.
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
......@@ -58,14 +46,13 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v0.5.4 (2002/04/11)"
#define DRIVER_VERSION "v0.5.6 (2002/06/23)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
static const char driver_name[] = "pegasus";
#define PEGASUS_USE_INTR
#define PEGASUS_WRITE_EEPROM
#undef PEGASUS_WRITE_EEPROM
#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
BMSR_100FULL | BMSR_ANEGCAPABLE)
......@@ -499,13 +486,57 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
return 0;
}
static void fill_skb_pool(pegasus_t *pegasus)
{
int i;
for (i=0; i < RX_SKBS; i++) {
if (pegasus->rx_pool[i])
continue;
pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2);
/*
** we give up if the allocation fail. the tasklet will be
** rescheduled again anyway...
*/
if (pegasus->rx_pool[i] == NULL)
return;
pegasus->rx_pool[i]->dev = pegasus->net;
skb_reserve(pegasus->rx_pool[i], 2);
}
}
static void free_skb_pool(pegasus_t *pegasus)
{
int i;
for (i=0; i < RX_SKBS; i++) {
if (pegasus->rx_pool[i]) {
dev_kfree_skb(pegasus->rx_pool[i]);
pegasus->rx_pool[i] = NULL;
}
}
}
static inline struct sk_buff *pull_skb(pegasus_t *pegasus)
{
int i;
struct sk_buff *skb;
for (i=0; i < RX_SKBS; i++) {
if (likely(pegasus->rx_pool[i] != NULL)) {
skb = pegasus->rx_pool[i];
pegasus->rx_pool[i] = NULL;
return skb;
}
}
return NULL;
}
static void read_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
struct net_device *net;
int count = urb->actual_length;
int rx_status;
struct sk_buff *skb;
int rx_status, count = urb->actual_length;
__u16 pkt_len;
if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
......@@ -519,7 +550,7 @@ static void read_bulk_callback(struct urb *urb)
case 0:
break;
case -ETIMEDOUT:
dbg("reset MAC");
dbg("%s: reset MAC", net->name);
pegasus->flags &= ~PEGASUS_RX_BUSY;
break;
case -ENOENT:
......@@ -546,23 +577,24 @@ static void read_bulk_callback(struct urb *urb)
}
pkt_len = (rx_status & 0xfff) - 8;
if (!pegasus->rx_skb)
goto tl_sched;
if (pegasus->rx_skb == NULL)
printk("%s: rx_skb == NULL\n", __FUNCTION__);
/*
** we are sure at this point pegasus->rx_skb != NULL
** so we go ahead and pass up the packet.
*/
skb_put(pegasus->rx_skb, pkt_len);
pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
netif_rx(pegasus->rx_skb);
if (!(skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
pegasus->rx_skb = NULL;
goto tl_sched;
}
skb->dev = net;
skb_reserve(skb, 2);
pegasus->rx_skb = skb;
pegasus->stats.rx_packets++;
pegasus->stats.rx_bytes += pkt_len;
spin_lock(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus);
spin_unlock(&pegasus->rx_pool_lock);
if (pegasus->rx_skb == NULL)
goto tl_sched;
goon:
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
......@@ -587,11 +619,19 @@ static void rx_fixup(unsigned long data)
pegasus = (pegasus_t *)data;
spin_lock_irq(&pegasus->rx_pool_lock);
fill_skb_pool(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
if (pegasus->flags & PEGASUS_RX_URB_FAIL)
if (pegasus->rx_skb)
goto try_again;
if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
if (pegasus->rx_skb == NULL) {
spin_lock_irq(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
}
if (pegasus->rx_skb == NULL) {
warn("wow, low on memory");
tasklet_schedule(&pegasus->rx_tl);
return;
}
......@@ -625,7 +665,6 @@ static void write_bulk_callback(struct urb *urb)
netif_wake_queue(pegasus->net);
}
#ifdef PEGASUS_USE_INTR
static void intr_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
......@@ -662,7 +701,6 @@ static void intr_callback(struct urb *urb)
}
}
}
#endif
static void pegasus_tx_timeout(struct net_device *net)
{
......@@ -748,15 +786,62 @@ static void set_carrier(struct net_device *net)
}
static void free_all_urbs(pegasus_t *pegasus)
{
usb_free_urb(pegasus->intr_urb);
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
}
static void unlink_all_urbs(pegasus_t *pegasus)
{
usb_unlink_urb(pegasus->intr_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_urb(pegasus->ctrl_urb);
}
static int alloc_urbs(pegasus_t *pegasus)
{
pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->ctrl_urb) {
return 0;
}
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
usb_free_urb(pegasus->ctrl_urb);
return 0;
}
pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->tx_urb) {
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
return 0;
}
pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->intr_urb) {
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
return 0;
}
return 1;
}
static int pegasus_open(struct net_device *net)
{
pegasus_t *pegasus = (pegasus_t *) net->priv;
int res;
if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2)))
if (pegasus->rx_skb == NULL)
pegasus->rx_skb = pull_skb(pegasus);
/*
** Note: no point to free the pool. it is empty :-)
*/
if (!pegasus->rx_skb)
return -ENOMEM;
pegasus->rx_skb->dev = net;
skb_reserve(pegasus->rx_skb, 2);
down(&pegasus->sem);
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
......@@ -765,19 +850,20 @@ static int pegasus_open(struct net_device *net)
read_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL)))
warn("%s: failed rx_urb %d", __FUNCTION__, res);
#ifdef PEGASUS_USE_INTR
FILL_INT_URB(pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval);
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL)))
warn("%s: failed intr_urb %d", __FUNCTION__, res);
#endif
netif_start_queue(net);
pegasus->flags |= PEGASUS_RUNNING;
if ((res = enable_net_traffic(net, pegasus->usb))) {
err("can't enable_net_traffic() - %d", res);
res = -EIO;
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_urb(pegasus->intr_urb);
free_skb_pool(pegasus);
goto exit;
}
set_carrier(net);
......@@ -797,13 +883,7 @@ static int pegasus_close(struct net_device *net)
netif_stop_queue(net);
if (!(pegasus->flags & PEGASUS_UNPLUG))
disable_net_traffic(pegasus);
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->ctrl_urb);
#ifdef PEGASUS_USE_INTR
usb_unlink_urb(pegasus->intr_urb);
#endif
unlink_all_urbs(pegasus);
up(&pegasus->sem);
return 0;
......@@ -986,38 +1066,14 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
pegasus->dev_index = dev_index;
init_waitqueue_head(&pegasus->ctrl_wait);
pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->ctrl_urb) {
kfree(pegasus);
return NULL;
}
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus);
return NULL;
}
pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->tx_urb) {
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
kfree(pegasus);
return NULL;
}
pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->intr_urb) {
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
if (!alloc_urbs(pegasus)) {
kfree(pegasus);
return NULL;
}
net = init_etherdev(NULL, 0);
if (!net) {
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
free_all_urbs(pegasus);
kfree(pegasus);
return NULL;
}
......@@ -1039,32 +1095,26 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
net->set_multicast_list = pegasus_set_multicast;
net->get_stats = pegasus_netdev_stats;
net->mtu = PEGASUS_MTU;
spin_lock_init(&pegasus->rx_pool_lock);
pegasus->features = usb_dev_id[dev_index].private;
#ifdef PEGASUS_USE_INTR
get_interrupt_interval(pegasus);
#endif
if (reset_mac(pegasus)) {
err("can't reset MAC");
unregister_netdev(pegasus->net);
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
free_all_urbs(pegasus);
kfree(pegasus->net);
kfree(pegasus);
pegasus = NULL;
goto exit;
}
info("%s: %s", net->name, usb_dev_id[dev_index].name);
set_ethernet_addr(pegasus);
fill_skb_pool(pegasus);
printk("%s: %s\n", net->name, usb_dev_id[dev_index].name);
if (pegasus->features & PEGASUS_II) {
info("setup Pegasus II specific registers");
setup_pegasus_II(pegasus);
}
pegasus->phy = mii_phy_probe(pegasus);
if (pegasus->phy == 0xff) {
warn("can't locate MII phy, using default");
......@@ -1087,14 +1137,9 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev(pegasus->net);
usb_put_dev(dev);
usb_unlink_urb(pegasus->intr_urb);
usb_unlink_urb(pegasus->tx_urb);
usb_unlink_urb(pegasus->rx_urb);
usb_unlink_urb(pegasus->ctrl_urb);
usb_free_urb(pegasus->intr_urb);
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
usb_free_urb(pegasus->ctrl_urb);
unlink_all_urbs(pegasus);
free_all_urbs(pegasus);
free_skb_pool(pegasus);
if (pegasus->rx_skb)
dev_kfree_skb(pegasus->rx_skb);
kfree(pegasus->net);
......
......@@ -2,18 +2,8 @@
* Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
......@@ -23,6 +13,7 @@
#define HAS_HOME_PNA 0x40000000
#define PEGASUS_MTU 1536
#define RX_SKBS 4
#define EPROM_WRITE 0x01
#define EPROM_READ 0x02
......@@ -100,10 +91,12 @@ typedef struct pegasus {
int intr_interval;
struct tasklet_struct rx_tl;
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct sk_buff *rx_pool[RX_SKBS];
struct sk_buff *rx_skb;
struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait;
struct semaphore sem;
spinlock_t rx_pool_lock;
unsigned char intr_buff[8];
__u8 tx_buff[PEGASUS_MTU];
__u8 eth_regs[4];
......
/*
* Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
......@@ -19,7 +18,6 @@
#include <linux/ethtool.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/usb.h>
#include <linux/init.h>
#include <asm/uaccess.h>
/* Version Information */
......@@ -106,7 +104,7 @@ unsigned long multicast_filter_limit = 32;
static void fill_skb_pool(rtl8150_t *);
static void free_skb_pool(rtl8150_t *);
static struct sk_buff *pull_skb(rtl8150_t *);
static inline struct sk_buff *pull_skb(rtl8150_t *);
static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
......@@ -312,7 +310,7 @@ static void read_bulk_callback(struct urb *urb)
case -ENOENT:
return; /* the urb is in unlink state */
case -ETIMEDOUT:
warn("reset needed may be?..");
warn("may be reset is needed?..");
goto goon;
default:
warn("Rx status %d", urb->status);
......@@ -331,13 +329,13 @@ static void read_bulk_callback(struct urb *urb)
netif_rx(dev->rx_skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
spin_lock(&dev->rx_pool_lock);
skb = pull_skb(dev);
spin_unlock(&dev->rx_pool_lock);
if (!skb)
goto resched;
skb->dev = netdev;
skb_reserve(skb, 2);
dev->rx_skb = skb;
goon:
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
......@@ -361,11 +359,16 @@ static void rx_fixup(unsigned long data)
dev = (rtl8150_t *)data;
spin_lock_irq(&dev->rx_pool_lock);
fill_skb_pool(dev);
spin_unlock_irq(&dev->rx_pool_lock);
if (test_bit(RX_URB_FAIL, &dev->flags))
if (dev->rx_skb)
goto try_again;
if (!(skb = pull_skb(dev)))
spin_lock_irq(&dev->rx_pool_lock);
skb = pull_skb(dev);
spin_unlock_irq(&dev->rx_pool_lock);
if (skb == NULL)
goto tlsched;
dev->rx_skb = skb;
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
......@@ -426,51 +429,41 @@ static void fill_skb_pool(rtl8150_t *dev)
{
struct sk_buff *skb;
int i;
unsigned long flags;
spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i])
continue;
skb = dev_alloc_skb(RTL8150_MTU + 2);
if (!skb) {
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return;
}
skb->dev = dev->netdev;
skb_reserve(skb, 2);
dev->rx_skb_pool[i] = skb;
}
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
}
static void free_skb_pool(rtl8150_t *dev)
{
int i;
spin_lock_irq(&dev->rx_pool_lock);
for (i = 0; i < RX_SKB_POOL_SIZE; i++)
if (dev->rx_skb_pool[i])
dev_kfree_skb(dev->rx_skb_pool[i]);
spin_unlock_irq(&dev->rx_pool_lock);
}
static struct sk_buff *pull_skb(rtl8150_t *dev)
static inline struct sk_buff *pull_skb(rtl8150_t *dev)
{
struct sk_buff *skb;
int i;
unsigned long flags;
spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i]) {
skb = dev->rx_skb_pool[i];
dev->rx_skb_pool[i] = NULL;
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return skb;
}
}
spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return NULL;
}
......@@ -578,8 +571,8 @@ static int rtl8150_open(struct net_device *netdev)
if (dev == NULL) {
return -ENODEV;
}
dev->rx_skb = pull_skb(dev);
if (dev->rx_skb == NULL)
dev->rx_skb = pull_skb(dev);
if (!dev->rx_skb)
return -ENOMEM;
......@@ -816,13 +809,13 @@ static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
dev = NULL;
}
static int __init usb_rtl8150_init(void)
int __init usb_rtl8150_init(void)
{
info(DRIVER_DESC " " DRIVER_VERSION);
return usb_register(&rtl8150_driver);
}
static void __exit usb_rtl8150_exit(void)
void __exit usb_rtl8150_exit(void)
{
usb_deregister(&rtl8150_driver);
}
......
......@@ -428,18 +428,13 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
void *data, u16 size)
{
int status;
struct usb_ctrlrequest *dr;
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr)
return -ENOMEM;
/* fill in the devrequest structure */
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size);
us->dr->bRequestType = requesttype;
us->dr->bRequest = request;
us->dr->wValue = cpu_to_le16(value);
us->dr->wIndex = cpu_to_le16(index);
us->dr->wLength = cpu_to_le16(size);
/* lock the URB */
down(&(us->current_urb_sem));
......@@ -452,7 +447,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
/* fill the URB */
FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe,
(unsigned char*) dr, data, size,
(unsigned char*) us->dr, data, size,
usb_stor_blocking_completion, NULL);
/* submit the URB */
......@@ -1162,7 +1157,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
int pipe;
/* issue the command -- use usb_control_msg() because
* the state machine is not yet alive */
* this is not a scsi queued-command */
pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
result = usb_control_msg(us->pusb_dev, pipe,
US_BULK_GET_MAX_LUN,
......@@ -1181,8 +1176,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
/* Use usb_clear_halt() because the state machine
* is not yet alive */
/* Use usb_clear_halt() because this is not a
* scsi queued-command */
usb_clear_halt(us->pusb_dev, pipe);
}
......@@ -1356,27 +1351,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
* Reset routines
***********************************************************************/
struct us_timeout {
struct us_data *us;
spinlock_t timer_lock;
};
/* The timeout event handler
*/
static void usb_stor_timeout_handler(unsigned long to__)
{
struct us_timeout *to = (struct us_timeout *) to__;
struct us_data *us = to->us;
US_DEBUGP("Timeout occurred\n");
/* abort the current request */
usb_stor_abort_transport(us);
/* let the reset routine know we have finished */
spin_unlock(&to->timer_lock);
}
/* This is the common part of the device reset code.
*
* It's handy that every transport mechanism uses the control endpoint for
......@@ -1385,28 +1359,20 @@ static void usb_stor_timeout_handler(unsigned long to__)
* Basically, we send a reset with a 20-second timeout, so we don't get
* jammed attempting to do the reset.
*/
void usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype,
static int usb_stor_reset_common(struct us_data *us,
u8 request, u8 requesttype,
u16 value, u16 index, void *data, u16 size)
{
int result;
struct us_timeout timeout_data = {us, SPIN_LOCK_UNLOCKED};
struct timer_list timeout_list;
/* prepare the timeout handler */
spin_lock(&timeout_data.timer_lock);
init_timer(&timeout_list);
/* A 20-second timeout may seem rather long, but a LaCie
* StudioDrive USB2 device takes 16+ seconds to get going
* following a powerup or USB attach event. */
timeout_list.expires = jiffies + 20 * HZ;
timeout_list.data = (unsigned long) &timeout_data;
timeout_list.function = usb_stor_timeout_handler;
add_timer(&timeout_list);
result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
request, requesttype, value, index, data, size);
/* Use usb_control_msg() because this is not a queued-command */
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
request, requesttype, value, index, data, size,
20*HZ);
if (result < 0)
goto Done;
......@@ -1415,41 +1381,30 @@ void usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype,
schedule_timeout(HZ*6);
set_current_state(TASK_RUNNING);
/* Use usb_clear_halt() because this is not a queued-command */
US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
result = usb_stor_clear_halt(us,
result = usb_clear_halt(us->pusb_dev,
usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
if (result < 0)
goto Done;
US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
result = usb_stor_clear_halt(us,
result = usb_clear_halt(us->pusb_dev,
usb_sndbulkpipe(us->pusb_dev, us->ep_out));
Done:
/* prevent the timer from coming back to haunt us */
if (!del_timer(&timeout_list)) {
/* the handler has already started; wait for it to finish */
spin_lock(&timeout_data.timer_lock);
/* change the abort into a timeout */
if (result == -ENOENT)
result = -ETIMEDOUT;
}
/* return a result code based on the result of the control message */
if (result >= 0)
US_DEBUGP("Soft reset done\n");
else
if (result < 0) {
US_DEBUGP("Soft reset failed: %d\n", result);
if (result == -ETIMEDOUT)
us->srb->result = DID_TIME_OUT << 16;
else if (result == -ENOENT)
us->srb->result = DID_ABORT << 16;
else if (result < 0)
us->srb->result = DID_ERROR << 16;
else
result = FAILED;
} else {
US_DEBUGP("Soft reset done\n");
us->srb->result = GOOD << 1;
result = SUCCESS;
}
return result;
}
/* This issues a CB[I] Reset to the device in question
......@@ -1463,10 +1418,9 @@ int usb_stor_CB_reset(struct us_data *us)
memset(cmd, 0xFF, sizeof(cmd));
cmd[0] = SEND_DIAGNOSTIC;
cmd[1] = 4;
usb_stor_reset_common(us, US_CBI_ADSC,
return usb_stor_reset_common(us, US_CBI_ADSC,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, cmd, sizeof(cmd));
return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
}
/* This issues a Bulk-only Reset to the device in question, including
......@@ -1476,8 +1430,7 @@ int usb_stor_Bulk_reset(struct us_data *us)
{
US_DEBUGP("Bulk reset requested\n");
usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
}
......@@ -361,65 +361,42 @@ static int usb_stor_control_thread(void * __us)
BUG_ON(action != US_ACT_COMMAND);
/* lock the device pointers */
down(&(us->dev_semaphore));
/* reject the command if the direction indicator
* is UNKNOWN
*/
if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) {
US_DEBUGP("UNKNOWN data direction\n");
us->srb->result = DID_ERROR << 16;
scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
scsi_unlock(host);
continue;
}
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
if (us->srb->target &&
else if (us->srb->target &&
!(us->flags & US_FL_SCM_MULT_TARG)) {
US_DEBUGP("Bad target number (%d/%d)\n",
us->srb->target, us->srb->lun);
us->srb->result = DID_BAD_TARGET << 16;
scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
scsi_unlock(host);
continue;
}
if (us->srb->lun > us->max_lun) {
else if (us->srb->lun > us->max_lun) {
US_DEBUGP("Bad LUN (%d/%d)\n",
us->srb->target, us->srb->lun);
us->srb->result = DID_BAD_TARGET << 16;
scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
scsi_unlock(host);
continue;
}
/* handle those devices which can't do a START_STOP */
if ((us->srb->cmnd[0] == START_STOP) &&
else if ((us->srb->cmnd[0] == START_STOP) &&
(us->flags & US_FL_START_STOP)) {
US_DEBUGP("Skipping START_STOP command\n");
us->srb->result = GOOD << 1;
scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
scsi_unlock(host);
continue;
}
/* lock the device pointers */
down(&(us->dev_semaphore));
/* our device has gone - pretend not ready */
if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
else if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
US_DEBUGP("Request is for removed device\n");
/* For REQUEST_SENSE, it's the data. But
* for anything else, it should look like
......@@ -443,24 +420,25 @@ static int usb_stor_control_thread(void * __us)
sizeof(usb_stor_sense_notready));
us->srb->result = CHECK_CONDITION << 1;
}
} else { /* test_bit(DEV_ATTACHED, &us->bitflags) */
} /* test_bit(DEV_ATTACHED, &us->bitflags) */
/* Handle those devices which need us to fake
* their inquiry data */
if ((us->srb->cmnd[0] == INQUIRY) &&
/* Handle those devices which need us to fake
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
(us->flags & US_FL_FIX_INQUIRY)) {
unsigned char data_ptr[36] = {
0x00, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
unsigned char data_ptr[36] = {
0x00, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
US_DEBUGP("Faking INQUIRY command\n");
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = GOOD << 1;
} else {
/* we've got a command, let's do it! */
US_DEBUG(usb_stor_show_command(us->srb));
us->proto_handler(us->srb, us);
}
US_DEBUGP("Faking INQUIRY command\n");
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = GOOD << 1;
}
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
us->proto_handler(us->srb, us);
}
/* unlock the device pointers */
......@@ -487,54 +465,114 @@ static int usb_stor_control_thread(void * __us)
return 0;
}
/* Set up the IRQ pipe and handler
/* Set up the URB, the usb_ctrlrequest, and the IRQ pipe and handler.
* ss->dev_semaphore should already be locked.
* Note that this function assumes that all the data in the us_data
* strucuture is current. This includes the ep_int field, which gives us
* the endpoint for the interrupt.
* Returns non-zero on failure, zero on success
*/
static int usb_stor_allocate_irq(struct us_data *ss)
static int usb_stor_allocate_urbs(struct us_data *ss)
{
unsigned int pipe;
int maxp;
int result;
US_DEBUGP("Allocating IRQ for CBI transport\n");
/* lock access to the data structure */
down(&(ss->irq_urb_sem));
/* allocate the URB */
ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ss->irq_urb) {
up(&(ss->irq_urb_sem));
US_DEBUGP("couldn't allocate interrupt URB");
/* allocate the URB we're going to use */
US_DEBUGP("Allocating URB\n");
ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ss->current_urb) {
US_DEBUGP("allocation failed\n");
return 1;
}
/* calculate the pipe and max packet size */
pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK);
maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
if (maxp > sizeof(ss->irqbuf))
maxp = sizeof(ss->irqbuf);
/* fill in the URB with our data */
FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp,
usb_stor_CBI_irq, ss, ss->ep_int->bInterval);
/* submit the URB for processing */
result = usb_submit_urb(ss->irq_urb, GFP_KERNEL);
US_DEBUGP("usb_submit_urb() returns %d\n", result);
if (result) {
usb_free_urb(ss->irq_urb);
up(&(ss->irq_urb_sem));
/* allocate the usb_ctrlrequest for control packets */
US_DEBUGP("Allocating usb_ctrlrequest\n");
ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!ss->dr) {
US_DEBUGP("allocation failed\n");
return 2;
}
/* unlock the data structure and return success */
/* allocate the IRQ URB, if it is needed */
if (ss->protocol == US_PR_CBI) {
US_DEBUGP("Allocating IRQ for CBI transport\n");
/* lock access to the data structure */
down(&(ss->irq_urb_sem));
/* allocate the URB */
ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ss->irq_urb) {
up(&(ss->irq_urb_sem));
US_DEBUGP("couldn't allocate interrupt URB");
return 3;
}
/* calculate the pipe and max packet size */
pipe = usb_rcvintpipe(ss->pusb_dev,
ss->ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
if (maxp > sizeof(ss->irqbuf))
maxp = sizeof(ss->irqbuf);
/* fill in the URB with our data */
FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf,
maxp, usb_stor_CBI_irq, ss, ss->ep_int->bInterval);
/* submit the URB for processing */
result = usb_submit_urb(ss->irq_urb, GFP_KERNEL);
US_DEBUGP("usb_submit_urb() returns %d\n", result);
if (result) {
up(&(ss->irq_urb_sem));
return 4;
}
/* unlock the data structure */
up(&(ss->irq_urb_sem));
} /* ss->protocol == US_PR_CBI */
return 0; /* success */
}
/* Deallocate the URB, the usb_ctrlrequest, and the IRQ pipe.
* ss->dev_semaphore must already be locked.
*/
static void usb_stor_deallocate_urbs(struct us_data *ss)
{
int result;
/* release the IRQ, if we have one */
down(&(ss->irq_urb_sem));
if (ss->irq_urb) {
US_DEBUGP("-- releasing irq URB\n");
result = usb_unlink_urb(ss->irq_urb);
US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
usb_free_urb(ss->irq_urb);
ss->irq_urb = NULL;
}
up(&(ss->irq_urb_sem));
return 0;
/* free the usb_ctrlrequest buffer */
if (ss->dr) {
kfree(ss->dr);
ss->dr = NULL;
}
/* free up the main URB for this device */
if (ss->current_urb) {
US_DEBUGP("-- releasing main URB\n");
result = usb_unlink_urb(ss->current_urb);
US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
usb_free_urb(ss->current_urb);
ss->current_urb = NULL;
}
/* mark the device as gone */
clear_bit(DEV_ATTACHED, &ss->bitflags);
usb_put_dev(ss->pusb_dev);
ss->pusb_dev = NULL;
}
/* Probe to see if a new device is actually a SCSI device */
......@@ -712,13 +750,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
USB_ENDPOINT_NUMBER_MASK;
ss->ep_int = ep_int;
/* allocate an IRQ callback if one is needed */
if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
goto BadDevice;
/* allocate the URB we're going to use */
ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ss->current_urb)
/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
if (usb_stor_allocate_urbs(ss))
goto BadDevice;
/* Re-Initialize the device if it needs it */
......@@ -741,11 +774,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
memset(ss, 0, sizeof(struct us_data));
new_device = 1;
/* allocate the URB we're going to use */
ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ss->current_urb)
goto BadDevice;
/* Initialize the mutexes only when the struct is new */
init_completion(&(ss->notify));
init_MUTEX_LOCKED(&(ss->ip_waitq));
......@@ -943,8 +971,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
}
US_DEBUGP("Protocol: %s\n", ss->protocol_name);
/* allocate an IRQ callback if one is needed */
if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
if (usb_stor_allocate_urbs(ss))
goto BadDevice;
/*
......@@ -1020,26 +1048,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* 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;
usb_stor_deallocate_urbs(ss);
if (new_device)
kfree(ss);
else
up(&ss->dev_semaphore);
usb_put_dev(dev);
return NULL;
}
......@@ -1047,7 +1060,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
static void storage_disconnect(struct usb_device *dev, void *ptr)
{
struct us_data *ss = ptr;
int result;
US_DEBUGP("storage_disconnect() called\n");
......@@ -1057,33 +1069,8 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
return;
}
/* lock access to the device data structure */
down(&(ss->dev_semaphore));
/* release the IRQ, if we have one */
down(&(ss->irq_urb_sem));
if (ss->irq_urb) {
US_DEBUGP("-- releasing irq URB\n");
result = usb_unlink_urb(ss->irq_urb);
US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
usb_free_urb(ss->irq_urb);
ss->irq_urb = NULL;
}
up(&(ss->irq_urb_sem));
/* free up the main URB for this device */
US_DEBUGP("-- releasing main URB\n");
result = usb_unlink_urb(ss->current_urb);
US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
usb_free_urb(ss->current_urb);
ss->current_urb = NULL;
/* mark the device as gone */
usb_put_dev(ss->pusb_dev);
ss->pusb_dev = NULL;
clear_bit(DEV_ATTACHED, &ss->bitflags);
/* unlock access to the device data structure */
usb_stor_deallocate_urbs(ss);
up(&(ss->dev_semaphore));
}
......
......@@ -185,6 +185,7 @@ struct us_data {
/* control and bulk communications data */
struct semaphore current_urb_sem; /* to protect irq_urb */
struct urb *current_urb; /* non-int USB requests */
struct usb_ctrlrequest *dr; /* control requests */
/* the semaphore for sleeping the control thread */
struct semaphore sema; /* to sleep thread on */
......
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