* [PATCH] stir4200 update for 2.6.4-rc1
@ 2004-03-02 20:05 Stephen Hemminger
2004-03-04 8:07 ` David S. Miller
0 siblings, 1 reply; 2+ messages in thread
From: Stephen Hemminger @ 2004-03-02 20:05 UTC (permalink / raw)
To: David S. Miller; +Cc: Jean Tourrilhes, netdev, Irda Users
New revision of the Sigmatel irda driver. This version has much
better performance and doesn't drop frames in FIR mode.
Tested with both UHCI and EHCI/OHCI against nsc-ircc on laptop.
Thanks to Martin for additional testing and feedback.
* Receiver:
- changed from interrupt to bulk URB. Queue's one bulk
urb per USB tick (1ms).
- FIR unpack now uses get_unaligned and cpu32_le
instead of explicit shifts
- FIR unpack copies small frames
* Transmitter:
- pack data into io buffer. Since irda is half duplex
can use same buffer for transmit and receive.
- use xchange and wait_event for synchronization
* Other:
- use USB format messages rather than IRDA (ugly)
- clean up USB startup
- reset device on network open to clear up stuck state
- handle FIFO errors
- disconnect cleanup (from viro)
- don't DMA onto stack when reading fifo status
David, please apply. There maybe more small tweaks later as it gets
wider usage.
--- linux-2.6/drivers/net/irda/stir4200.c 2004-02-18 14:14:14.000000000 -0800
+++ test-2.6/drivers/net/irda/stir4200.c 2004-03-02 11:11:21.413890216 -0800
@@ -49,12 +49,14 @@
#include <linux/suspend.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/crc32.h>
#include <net/irda/irda.h>
#include <net/irda/irlap.h>
#include <net/irda/irda_device.h>
#include <net/irda/wrapper.h>
#include <net/irda/crc.h>
-#include <linux/crc32.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200");
@@ -72,15 +74,11 @@ static int tx_power = 0; /* 0 = highest
module_param(tx_power, int, 0);
MODULE_PARM_DESC(tx_power, "Set Transmitter power (0-3, 0 is highest power)");
-static int rx_interval = 5; /* milliseconds */
-module_param(rx_interval, int, 0);
-MODULE_PARM_DESC(rx_interval, "Receive polling interval (ms)");
-
#define STIR_IRDA_HEADER 4
#define CTRL_TIMEOUT 100 /* milliseconds */
#define TRANSMIT_TIMEOUT 200 /* milliseconds */
#define STIR_FIFO_SIZE 4096
-#define NUM_RX_URBS 2
+#define FIFO_REGS_SIZE 3
enum FirChars {
FIR_CE = 0x7d,
@@ -167,36 +165,26 @@ enum StirTestMask {
TEST_TSTOSC = 0x0F,
};
-enum StirState {
- STIR_STATE_RECEIVING=0,
- STIR_STATE_TXREADY,
-};
-
struct stir_cb {
struct usb_device *usbdev; /* init: probe_irda */
struct net_device *netdev; /* network layer */
struct irlap_cb *irlap; /* The link layer we are binded to */
struct net_device_stats stats; /* network statistics */
struct qos_info qos;
- unsigned long state;
unsigned speed; /* Current speed */
wait_queue_head_t thr_wait; /* transmit thread wakeup */
struct completion thr_exited;
pid_t thr_pid;
- unsigned int tx_bulkpipe;
- void *tx_data; /* wrapped data out */
- unsigned tx_len;
- unsigned tx_newspeed;
- unsigned tx_mtt;
+ struct sk_buff *tx_pending;
+ void *io_buf; /* transmit/receive buffer */
+ __u8 *fifo_status;
- unsigned int rx_intpipe;
iobuff_t rx_buff; /* receive unwrap state machine */
- struct timespec rx_time;
-
- struct urb *rx_urbs[NUM_RX_URBS];
- void *rx_data[NUM_RX_URBS];
+ struct timeval rx_time;
+ int receiving;
+ struct urb *rx_urb;
};
@@ -209,9 +197,6 @@ static struct usb_device_id dongles[] =
MODULE_DEVICE_TABLE(usb, dongles);
-static int fifo_txwait(struct stir_cb *stir, unsigned space);
-static void stir_usb_receive(struct urb *urb, struct pt_regs *regs);
-
/* Send control message to set dongle register */
static int write_reg(struct stir_cb *stir, __u16 reg, __u8 value)
{
@@ -239,6 +224,11 @@ static inline int read_reg(struct stir_c
MSECS_TO_JIFFIES(CTRL_TIMEOUT));
}
+static inline int isfir(u32 speed)
+{
+ return (speed == 4000000);
+}
+
/*
* Prepare a FIR IrDA frame for transmission to the USB dongle. The
* FIR transmit frame is documented in the datasheet. It consists of
@@ -333,8 +323,8 @@ static void fir_eof(struct stir_cb *stir
{
iobuff_t *rx_buff = &stir->rx_buff;
int len = rx_buff->len - 4;
+ struct sk_buff *skb, *nskb;
__u32 fcs;
- struct sk_buff *nskb;
if (unlikely(len <= 0)) {
pr_debug("%s: short frame len %d\n",
@@ -345,41 +335,46 @@ static void fir_eof(struct stir_cb *stir
return;
}
- fcs = rx_buff->data[len] |
- rx_buff->data[len+1] << 8 |
- rx_buff->data[len+2] << 16 |
- rx_buff->data[len+3] << 24;
-
- if (unlikely(fcs != ~(crc32_le(~0, rx_buff->data, len)))) {
- pr_debug("%s: crc error\n", stir->netdev->name);
- irda_device_set_media_busy(stir->netdev, TRUE);
+ fcs = ~(crc32_le(~0, rx_buff->data, len));
+ if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) {
+ pr_debug("crc error calc 0x%x len %d\n", fcs, len);
stir->stats.rx_errors++;
stir->stats.rx_crc_errors++;
return;
}
- /* If can't get new buffer, just drop and reuse */
- nskb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (unlikely(!nskb))
- ++stir->stats.rx_dropped;
- else {
- struct sk_buff *oskb = rx_buff->skb;
+ /* if frame is short then just copy it */
+ if (len < IRDA_RX_COPY_THRESHOLD) {
+ nskb = dev_alloc_skb(len + 1);
+ if (unlikely(!nskb)) {
+ ++stir->stats.rx_dropped;
+ return;
+ }
+ skb_reserve(nskb, 1);
+ skb = nskb;
+ memcpy(nskb->data, rx_buff->data, len);
+ } else {
+ nskb = dev_alloc_skb(rx_buff->truesize);
+ if (unlikely(!nskb)) {
+ ++stir->stats.rx_dropped;
+ return;
+ }
skb_reserve(nskb, 1);
+ skb = rx_buff->skb;
+ rx_buff->skb = nskb;
+ rx_buff->head = nskb->data;
+ }
- /* Set correct length in socket buffer */
- skb_put(oskb, len);
+ skb_put(skb, len);
- oskb->mac.raw = oskb->data;
- oskb->protocol = htons(ETH_P_IRDA);
- oskb->dev = stir->netdev;
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IRDA);
+ skb->dev = stir->netdev;
- netif_rx(oskb);
+ netif_rx(skb);
- stir->stats.rx_packets++;
- stir->stats.rx_bytes += len;
- rx_buff->skb = nskb;
- rx_buff->head = nskb->data;
- }
+ stir->stats.rx_packets++;
+ stir->stats.rx_bytes += len;
rx_buff->data = rx_buff->head;
rx_buff->len = 0;
@@ -402,7 +397,6 @@ static void stir_fir_chars(struct stir_c
continue;
/* Now receiving frame */
rx_buff->state = BEGIN_FRAME;
- rx_buff->in_frame = TRUE;
/* Time to initialize receive buffer */
rx_buff->data = rx_buff->head;
@@ -424,6 +418,7 @@ static void stir_fir_chars(struct stir_c
if (byte == FIR_EOF)
continue;
rx_buff->state = INSIDE_FRAME;
+ rx_buff->in_frame = TRUE;
/* fall through */
case INSIDE_FRAME:
@@ -461,7 +456,6 @@ static void stir_fir_chars(struct stir_c
error_recovery:
++stir->stats.rx_errors;
- irda_device_set_media_busy(stir->netdev, TRUE);
rx_buff->state = OUTSIDE_FRAME;
rx_buff->in_frame = FALSE;
}
@@ -478,11 +472,6 @@ static void stir_sir_chars(struct stir_c
&stir->rx_buff, bytes[i]);
}
-static inline int isfir(u32 speed)
-{
- return (speed == 4000000);
-}
-
static inline void unwrap_chars(struct stir_cb *stir,
const __u8 *bytes, int length)
{
@@ -519,25 +508,31 @@ static int change_speed(struct stir_cb *
int i, err;
__u8 mode;
- pr_debug("%s: change speed %d\n", stir->netdev->name, speed);
for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) {
if (speed == stir_modes[i].speed)
goto found;
}
- ERROR("%s: invalid speed %d\n", stir->netdev->name, speed);
+ warn("%s: invalid speed %d", stir->netdev->name, speed);
return -EINVAL;
found:
- pr_debug("%s: speed change from %d to %d\n",
- stir->netdev->name, stir->speed, speed);
+ pr_debug("speed change from %d to %d\n", stir->speed, speed);
+
+ /* sometimes needed to get chip out of stuck state */
+ err = usb_reset_device(stir->usbdev);
+ if (err)
+ goto out;
+
+ /* Reset modulator */
+ err = write_reg(stir, REG_CTRL1, CTRL1_SRESET);
+ if (err)
+ goto out;
- /* Make sure any previous Tx is really finished. This happens
- * when we answer an incomming request ; the ua:rsp and the
- * speed change are bundled together, so we need to wait until
- * the packet we just submitted has been sent. Jean II */
- if (fifo_txwait(stir, 0))
- return -EIO;
+ /* Undocumented magic to tweak the DPLL */
+ err = write_reg(stir, REG_DPLL, 0x15);
+ if (err)
+ goto out;
/* Set clock */
err = write_reg(stir, REG_PDCLK, stir_modes[i].pdclk);
@@ -564,33 +559,13 @@ static int change_speed(struct stir_cb *
goto out;
err = write_reg(stir, REG_CTRL1, (tx_power & 3) << 1);
-
- out:
- stir->speed = speed;
- return err;
-}
-
-static int stir_reset(struct stir_cb *stir)
-{
- int err;
-
- /* reset state */
- stir->rx_buff.in_frame = FALSE;
- stir->rx_buff.state = OUTSIDE_FRAME;
- stir->speed = -1;
-
- /* Undocumented magic to tweak the DPLL */
- err = write_reg(stir, REG_DPLL, 0x15);
if (err)
goto out;
/* Reset sensitivity */
err = write_reg(stir, REG_CTRL2, (rx_sensitivity & 7) << 5);
- if (err)
- goto out;
-
- err = change_speed(stir, 9600);
out:
+ stir->speed = speed;
return err;
}
@@ -606,48 +581,62 @@ static int stir_hard_xmit(struct sk_buff
/* the IRDA wrapping routines don't deal with non linear skb */
SKB_LINEAR_ASSERT(skb);
- if (unlikely(skb->len) == 0) /* speed change only */
- stir->tx_len = 0;
- else if (isfir(stir->speed))
- stir->tx_len = wrap_fir_skb(skb, stir->tx_data);
- else
- stir->tx_len = wrap_sir_skb(skb, stir->tx_data);
-
- stir->stats.tx_packets++;
- stir->stats.tx_bytes += skb->len;
-
- stir->tx_mtt = irda_get_mtt(skb);
- stir->tx_newspeed = irda_get_next_speed(skb);
-
- if (!test_and_set_bit(STIR_STATE_TXREADY, &stir->state))
- wake_up(&stir->thr_wait);
+ skb = xchg(&stir->tx_pending, skb);
+ wake_up(&stir->thr_wait);
+
+ /* this should never happen unless stop/wakeup problem */
+ if (unlikely(skb)) {
+ WARN_ON(1);
+ dev_kfree_skb(skb);
+ }
- dev_kfree_skb(skb);
return 0;
}
/*
* Wait for the transmit FIFO to have space for next data
+ *
+ * If space < 0 then wait till FIFO completely drains.
+ * FYI: can take up to 13 seconds at 2400baud.
*/
-static int fifo_txwait(struct stir_cb *stir, unsigned space)
+static int fifo_txwait(struct stir_cb *stir, int space)
{
int err;
- unsigned count;
- __u8 regs[3];
- unsigned long timeout = jiffies + HZ/10;
+ unsigned long count, status;
+ /* Read FIFO status and count */
for(;;) {
- /* Read FIFO status and count */
- err = read_reg(stir, REG_FIFOCTL, regs, 3);
- if (unlikely(err != 3)) {
- WARNING("%s: FIFO register read error: %d\n",
- stir->netdev->name, err);
+ err = read_reg(stir, REG_FIFOCTL, stir->fifo_status,
+ FIFO_REGS_SIZE);
+ if (unlikely(err != FIFO_REGS_SIZE)) {
+ warn("%s: FIFO register read error: %d",
+ stir->netdev->name, err);
+
return err;
}
+ status = stir->fifo_status[0];
+ count = (unsigned)(stir->fifo_status[2] & 0x1f) << 8
+ | stir->fifo_status[1];
+
+ pr_debug("fifo status 0x%lx count %lu\n", status, count);
+
+ /* error when receive/transmit fifo gets confused */
+ if (status & FIFOCTL_RXERR) {
+ stir->stats.rx_fifo_errors++;
+ stir->stats.rx_errors++;
+ break;
+ }
+
+ if (status & FIFOCTL_TXERR) {
+ stir->stats.tx_fifo_errors++;
+ stir->stats.tx_errors++;
+ break;
+ }
+
/* is fifo receiving already, or empty */
- if (!(regs[0] & FIFOCTL_DIR)
- || (regs[0] & FIFOCTL_EMPTY))
+ if (!(status & FIFOCTL_DIR)
+ || (status & FIFOCTL_EMPTY))
return 0;
if (signal_pending(current))
@@ -658,40 +647,37 @@ static int fifo_txwait(struct stir_cb *s
|| !netif_device_present(stir->netdev))
return -ESHUTDOWN;
- count = (unsigned)(regs[2] & 0x1f) << 8 | regs[1];
-
- pr_debug("%s: fifo status 0x%x count %u\n",
- stir->netdev->name, regs[0], count);
-
/* only waiting for some space */
- if (space && STIR_FIFO_SIZE - 4 > space + count)
+ if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count)
return 0;
- if (time_after(jiffies, timeout)) {
- WARNING("%s: transmit fifo timeout status=0x%x count=%d\n",
- stir->netdev->name, regs[0], count);
- ++stir->stats.tx_errors;
- irda_device_set_media_busy(stir->netdev, TRUE);
- return -ETIMEDOUT;
- }
-
/* estimate transfer time for remaining chars */
wait_ms((count * 8000) / stir->speed);
}
+
+ err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR);
+ if (err)
+ return err;
+ err = write_reg(stir, REG_FIFOCTL, 0);
+ if (err)
+ return err;
+
+ return 0;
}
/* Wait for turnaround delay before starting transmit. */
-static void turnaround_delay(long us, const struct timespec *last)
+static void turnaround_delay(const struct stir_cb *stir, long us)
{
long ticks;
- struct timespec now = CURRENT_TIME;
+ struct timeval now;
if (us <= 0)
return;
- us -= (now.tv_sec - last->tv_sec) * USEC_PER_SEC;
- us -= (now.tv_nsec - last->tv_nsec) / NSEC_PER_USEC;
+ do_gettimeofday(&now);
+ us -= (now.tv_sec - stir->rx_time.tv_sec) * USEC_PER_SEC;
+ us -= now.tv_usec - stir->rx_time.tv_usec;
if (us < 10)
return;
@@ -707,77 +693,60 @@ static void turnaround_delay(long us, co
* Start receiver by submitting a request to the receive pipe.
* If nothing is available it will return after rx_interval.
*/
-static void receive_start(struct stir_cb *stir)
+static int receive_start(struct stir_cb *stir)
{
- int i;
-
- if (test_and_set_bit(STIR_STATE_RECEIVING, &stir->state))
- return;
-
- if (fifo_txwait(stir, 0))
- return;
-
- for (i = 0; i < NUM_RX_URBS; i++) {
- struct urb *urb = stir->rx_urbs[i];
-
- usb_fill_int_urb(urb, stir->usbdev, stir->rx_intpipe,
- stir->rx_data[i], STIR_FIFO_SIZE,
- stir_usb_receive, stir, rx_interval);
-
- if (usb_submit_urb(urb, GFP_KERNEL))
- urb->status = -EINVAL;
- }
+ /* reset state */
+ stir->receiving = 1;
- if (i == 0) {
- /* if nothing got queued, then just retry next time */
- if (net_ratelimit())
- WARNING("%s: no receive buffers avaiable\n",
- stir->netdev->name);
+ stir->rx_buff.in_frame = FALSE;
+ stir->rx_buff.state = OUTSIDE_FRAME;
- clear_bit(STIR_STATE_RECEIVING, &stir->state);
- }
+ stir->rx_urb->status = 0;
+ return usb_submit_urb(stir->rx_urb, GFP_KERNEL);
}
/* Stop all pending receive Urb's */
static void receive_stop(struct stir_cb *stir)
{
- int i;
+ stir->receiving = 0;
+ usb_unlink_urb(stir->rx_urb);
- for (i = 0; i < NUM_RX_URBS; i++) {
- struct urb *urb = stir->rx_urbs[i];
- usb_unlink_urb(urb);
- }
+ if (stir->rx_buff.in_frame)
+ stir->stats.collisions++;
}
-
-/* Send wrapped data (in tx_data) to device */
-static void stir_send(struct stir_cb *stir)
+/*
+ * Wrap data in socket buffer and send it.
+ */
+static void stir_send(struct stir_cb *stir, struct sk_buff *skb)
{
- int rc;
+ unsigned wraplen;
+ int first_frame = 0;
- if (test_and_clear_bit(STIR_STATE_RECEIVING, &stir->state)) {
+ /* if receiving, need to turnaround */
+ if (stir->receiving) {
receive_stop(stir);
-
- turnaround_delay(stir->tx_mtt, &stir->rx_time);
-
- if (stir->rx_buff.in_frame)
- ++stir->stats.collisions;
+ turnaround_delay(stir, irda_get_mtt(skb));
+ first_frame = 1;
}
- else if (fifo_txwait(stir, stir->tx_len))
- return; /* shutdown or major errors */
+ if (isfir(stir->speed))
+ wraplen = wrap_fir_skb(skb, stir->io_buf);
+ else
+ wraplen = wrap_sir_skb(skb, stir->io_buf);
+
+ /* check for space available in fifo */
+ if (!first_frame)
+ fifo_txwait(stir, wraplen);
+
+ stir->stats.tx_packets++;
+ stir->stats.tx_bytes += skb->len;
stir->netdev->trans_start = jiffies;
+ pr_debug("send %d (%d)\n", skb->len, wraplen);
- pr_debug("%s: send %d\n", stir->netdev->name, stir->tx_len);
- rc = usb_bulk_msg(stir->usbdev,
- stir->tx_bulkpipe,
- stir->tx_data, stir->tx_len,
- NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT));
-
- if (unlikely(rc)) {
- WARNING("%s: usb bulk message failed %d\n",
- stir->netdev->name, rc);
+ if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),
+ stir->io_buf, wraplen,
+ NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT)))
stir->stats.tx_errors++;
- }
}
/*
@@ -787,7 +756,7 @@ static int stir_transmit_thread(void *ar
{
struct stir_cb *stir = arg;
struct net_device *dev = stir->netdev;
- DECLARE_WAITQUEUE(wait, current);
+ struct sk_buff *skb;
daemonize("%s", dev->name);
allow_signal(SIGTERM);
@@ -796,44 +765,58 @@ static int stir_transmit_thread(void *ar
&& netif_device_present(dev)
&& !signal_pending(current))
{
- /* make swsusp happy with our thread */
+ /* if suspending, then power off and wait */
if (current->flags & PF_FREEZE) {
- receive_stop(stir);
+ if (stir->receiving)
+ receive_stop(stir);
+ else
+ fifo_txwait(stir, -1);
write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);
refrigerator(PF_IOTHREAD);
- stir_reset(stir);
+ if (change_speed(stir, stir->speed))
+ break;
}
/* if something to send? */
- if (test_and_clear_bit(STIR_STATE_TXREADY, &stir->state)) {
- unsigned new_speed = stir->tx_newspeed;
-
- /* Note that we may both send a packet and
- * change speed in some cases. Jean II */
-
- if (stir->tx_len != 0)
- stir_send(stir);
-
- if (stir->speed != new_speed)
- change_speed(stir, new_speed);
-
- netif_wake_queue(stir->netdev);
+ skb = xchg(&stir->tx_pending, NULL);
+ if (skb) {
+ unsigned new_speed = irda_get_next_speed(skb);
+ netif_wake_queue(dev);
+
+ if (skb->len > 0)
+ stir_send(stir, skb);
+ dev_kfree_skb(skb);
+
+ if (stir->speed != new_speed) {
+ if (fifo_txwait(stir, -1) ||
+ change_speed(stir, new_speed))
+ break;
+ }
continue;
}
- if (irda_device_txqueue_empty(dev))
- receive_start(stir);
+ /* nothing to send? start receiving */
+ if (!stir->receiving
+ && irda_device_txqueue_empty(dev)) {
+ /* Wait otherwise chip gets confused. */
+ if (fifo_txwait(stir, -1))
+ break;
+
+ if (unlikely(receive_start(stir))) {
+ if (net_ratelimit())
+ info("%s: receive usb submit failed",
+ stir->netdev->name);
+ stir->receiving = 0;
+ wait_ms(10);
+ continue;
+ }
+ }
- set_task_state(current, TASK_INTERRUPTIBLE);
- add_wait_queue(&stir->thr_wait, &wait);
- if (test_bit(STIR_STATE_TXREADY, &stir->state))
- __set_task_state(current, TASK_RUNNING);
- else
- schedule_timeout(HZ/10);
- remove_wait_queue(&stir->thr_wait, &wait);
+ /* sleep if nothing to send */
+ wait_event_interruptible(stir->thr_wait, stir->tx_pending);
}
complete_and_exit (&stir->thr_exited, 0);
@@ -841,48 +824,34 @@ static int stir_transmit_thread(void *ar
/*
- * Receive wrapped data into rx_data buffer.
- * This chip doesn't block until data is available, we just have
- * to read the FIFO perodically (ugh).
+ * USB bulk receive completion callback.
+ * Wakes up every ms (usb round trip) with wrapped
+ * data.
*/
-static void stir_usb_receive(struct urb *urb, struct pt_regs *regs)
+static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs)
{
struct stir_cb *stir = urb->context;
int err;
+ /* in process of stopping, just drop data */
if (!netif_running(stir->netdev))
return;
- switch (urb->status) {
- case 0:
- if(urb->actual_length > 0) {
- pr_debug("%s: receive %d\n",
- stir->netdev->name, urb->actual_length);
- unwrap_chars(stir, urb->transfer_buffer,
- urb->actual_length);
-
- stir->netdev->last_rx = jiffies;
- stir->rx_time = CURRENT_TIME;
- }
- break;
-
- case -ECONNRESET: /* killed but pending */
- case -ENOENT: /* killed but not in use */
- case -ESHUTDOWN:
- /* These are normal errors when URB is cancelled */
- stir->rx_buff.in_frame = FALSE;
- stir->rx_buff.state = OUTSIDE_FRAME;
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0)
return;
- default:
- WARNING("%s: received status %d\n", stir->netdev->name,
- urb->status);
- stir->stats.rx_errors++;
- urb->status = 0;
+ if (urb->actual_length > 0) {
+ pr_debug("receive %d\n", urb->actual_length);
+ unwrap_chars(stir, urb->transfer_buffer,
+ urb->actual_length);
+
+ stir->netdev->last_rx = jiffies;
+ do_gettimeofday(&stir->rx_time);
}
/* kernel thread is stopping receiver don't resubmit */
- if (!test_bit(STIR_STATE_RECEIVING, &stir->state))
+ if (!stir->receiving)
return;
/* resubmit existing urb */
@@ -890,14 +859,13 @@ static void stir_usb_receive(struct urb
/* in case of error, the kernel thread will restart us */
if (err) {
- WARNING("%s: usb receive submit error: %d\n",
+ warn("%s: usb receive submit error: %d",
stir->netdev->name, err);
- urb->status = -ENOENT;
+ stir->receiving = 0;
wake_up(&stir->thr_wait);
}
}
-
/*
* Function stir_net_open (dev)
*
@@ -906,50 +874,50 @@ static void stir_usb_receive(struct urb
static int stir_net_open(struct net_device *netdev)
{
struct stir_cb *stir = netdev->priv;
- int i, err;
- char hwname[16];
+ int err;
+ char hwname[16];
- err = stir_reset(stir);
+ err = usb_clear_halt(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1));
+ if (err)
+ goto err_out1;
+ err = usb_clear_halt(stir->usbdev, usb_rcvbulkpipe(stir->usbdev, 2));
if (err)
goto err_out1;
- err = -ENOMEM;
-
- /* Note: Max SIR frame possible is 4273 */
- stir->tx_data = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);
- if (!stir->tx_data) {
- ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__);
+ err = change_speed(stir, 9600);
+ if (err)
goto err_out1;
- }
+
+ err = -ENOMEM;
/* Initialize for SIR/FIR to copy data directly into skb. */
+ stir->receiving = 0;
stir->rx_buff.truesize = IRDA_SKB_MAX_MTU;
stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
- if (!stir->rx_buff.skb) {
- ERROR("%s(), dev_alloc_skb() failed for rxbuf!\n",
- __FUNCTION__);
- goto err_out2;
- }
+ if (!stir->rx_buff.skb)
+ goto err_out1;
+
skb_reserve(stir->rx_buff.skb, 1);
stir->rx_buff.head = stir->rx_buff.skb->data;
- stir->rx_time = CURRENT_TIME;
+ do_gettimeofday(&stir->rx_time);
- /* Allocate N receive buffer's and urbs */
- for (i = 0; i < NUM_RX_URBS; i++) {
- stir->rx_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
- if (!stir->rx_urbs[i]){
- ERROR("%s(), usb_alloc_urb failed\n", __FUNCTION__);
- goto err_out3;
- }
+ stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!stir->rx_urb)
+ goto err_out2;
- stir->rx_data[i] = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);
- if (!stir->rx_data) {
- usb_free_urb(stir->rx_urbs[i]);
- ERROR("%s(), alloc failed for rxbuf!\n", __FUNCTION__);
- goto err_out3;
- }
- }
+ stir->io_buf = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL);
+ if (!stir->io_buf)
+ goto err_out3;
+ usb_fill_bulk_urb(stir->rx_urb, stir->usbdev,
+ usb_rcvbulkpipe(stir->usbdev, 2),
+ stir->io_buf, STIR_FIFO_SIZE,
+ stir_rcv_irq, stir);
+
+ stir->fifo_status = kmalloc(FIFO_REGS_SIZE, GFP_KERNEL);
+ if (!stir->fifo_status)
+ goto err_out4;
+
/*
* Now that everything should be initialized properly,
* Open new IrLAP layer instance to take care of us...
@@ -958,8 +926,8 @@ static int stir_net_open(struct net_devi
sprintf(hwname, "usb#%d", stir->usbdev->devnum);
stir->irlap = irlap_open(netdev, &stir->qos, hwname);
if (!stir->irlap) {
- ERROR("%s(): irlap_open failed\n", __FUNCTION__);
- goto err_out3;
+ err("irlap_open failed");
+ goto err_out5;
}
/** Start kernel thread for transmit. */
@@ -967,25 +935,24 @@ static int stir_net_open(struct net_devi
CLONE_FS|CLONE_FILES);
if (stir->thr_pid < 0) {
err = stir->thr_pid;
- WARNING("%s: unable to start kernel thread\n",
- stir->netdev->name);
- goto err_out4;
+ err("unable to start kernel thread");
+ goto err_out6;
}
netif_start_queue(netdev);
return 0;
- err_out4:
+ err_out6:
irlap_close(stir->irlap);
+ err_out5:
+ kfree(stir->fifo_status);
+ err_out4:
+ kfree(stir->io_buf);
err_out3:
- while(--i >= 0) {
- usb_free_urb(stir->rx_urbs[i]);
- kfree(stir->rx_data[i]);
- }
- kfree_skb(stir->rx_buff.skb);
+ usb_free_urb(stir->rx_urb);
err_out2:
- kfree(stir->tx_data);
+ kfree_skb(stir->rx_buff.skb);
err_out1:
return err;
}
@@ -999,7 +966,6 @@ static int stir_net_open(struct net_devi
static int stir_net_close(struct net_device *netdev)
{
struct stir_cb *stir = netdev->priv;
- int i;
/* Stop transmit processing */
netif_stop_queue(netdev);
@@ -1007,15 +973,13 @@ static int stir_net_close(struct net_dev
/* Kill transmit thread */
kill_proc(stir->thr_pid, SIGTERM, 1);
wait_for_completion(&stir->thr_exited);
- kfree(stir->tx_data);
-
- clear_bit(STIR_STATE_RECEIVING, &stir->state);
- receive_stop(stir);
+ kfree(stir->fifo_status);
- for (i = 0; i < NUM_RX_URBS; i++) {
- usb_free_urb(stir->rx_urbs[i]);
- kfree(stir->rx_data[i]);
- }
+ /* Mop up receive urb's */
+ usb_unlink_urb(stir->rx_urb);
+
+ kfree(stir->io_buf);
+ usb_free_urb(stir->rx_urb);
kfree_skb(stir->rx_buff.skb);
/* Stop and remove instance of IrLAP */
@@ -1057,7 +1021,7 @@ static int stir_net_ioctl(struct net_dev
case SIOCGRECEIVING:
/* Only approximately true */
- irq->ifr_receiving = test_bit(STIR_STATE_RECEIVING, &stir->state);
+ irq->ifr_receiving = stir->receiving;
break;
default:
@@ -1077,53 +1041,6 @@ static struct net_device_stats *stir_net
}
/*
- * Parse the various endpoints and find the one we need.
- *
- * The endpoint are the pipes used to communicate with the USB device.
- * The spec defines 2 endpoints of type bulk transfer, one in, and one out.
- * These are used to pass frames back and forth with the dongle.
- */
-static int stir_setup_usb(struct stir_cb *stir, struct usb_interface *intf)
-{
- struct usb_device *usbdev = interface_to_usbdev(intf);
- const struct usb_host_interface *interface
- = &intf->altsetting[intf->act_altsetting];
- const struct usb_endpoint_descriptor *ep_in = NULL;
- const struct usb_endpoint_descriptor *ep_out = NULL;
- int i;
-
- if (interface->desc.bNumEndpoints != 2) {
- WARNING("%s: expected two endpoints\n", __FUNCTION__);
- return -ENODEV;
- }
-
- for(i = 0; i < interface->desc.bNumEndpoints; i++) {
- const struct usb_endpoint_descriptor *ep
- = &interface->endpoint[i].desc;
-
- if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK) {
- /* We need to find an IN and an OUT */
- if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
- ep_in = ep;
- else
- ep_out = ep;
- } else
- WARNING("%s: unknown endpoint type 0x%x\n",
- __FUNCTION__, ep->bmAttributes);
- }
-
- if (!ep_in || !ep_out)
- return -EIO;
-
- stir->tx_bulkpipe = usb_sndbulkpipe(usbdev,
- ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
- stir->rx_intpipe = usb_rcvintpipe(usbdev,
- ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
- return 0;
-}
-
-/*
* This routine is called by the USB subsystem for each new device
* in the system. We need to check if the device is ours, and in
* this case start handling it.
@@ -1149,9 +1066,9 @@ static int stir_probe(struct usb_interfa
stir->netdev = net;
stir->usbdev = dev;
- ret = stir_setup_usb(stir, intf);
+ ret = usb_reset_configuration(dev);
if (ret != 0) {
- ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
+ err("usb reset configuration failed");
goto err_out2;
}
@@ -1180,10 +1097,6 @@ static int stir_probe(struct usb_interfa
net->get_stats = stir_net_get_stats;
net->do_ioctl = stir_net_ioctl;
- ret = stir_reset(stir);
- if (ret)
- goto err_out2;
-
ret = register_netdev(net);
if (ret != 0)
goto err_out2;
@@ -1206,23 +1119,14 @@ err_out1:
static void stir_disconnect(struct usb_interface *intf)
{
struct stir_cb *stir = usb_get_intfdata(intf);
- struct net_device *net;
- usb_set_intfdata(intf, NULL);
if (!stir)
return;
- /* Stop transmitter */
- net = stir->netdev;
- netif_device_detach(net);
-
- /* Remove netdevice */
- unregister_netdev(net);
-
- /* No longer attached to USB bus */
- stir->usbdev = NULL;
+ unregister_netdev(stir->netdev);
+ free_netdev(stir->netdev);
- free_netdev(net);
+ usb_set_intfdata(intf, NULL);
}
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] stir4200 update for 2.6.4-rc1
2004-03-02 20:05 [PATCH] stir4200 update for 2.6.4-rc1 Stephen Hemminger
@ 2004-03-04 8:07 ` David S. Miller
0 siblings, 0 replies; 2+ messages in thread
From: David S. Miller @ 2004-03-04 8:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: jt, netdev, irda-users
Applied, thanks everyone.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2004-03-04 8:07 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-03-02 20:05 [PATCH] stir4200 update for 2.6.4-rc1 Stephen Hemminger
2004-03-04 8:07 ` David S. Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).