*
* 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.
+* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
#include <linux/time.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/suspend.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/usb.h>
#include <linux/crc32.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <net/irda/irda.h>
#include <net/irda/irlap.h>
#include <net/irda/irda_device.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
-MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
+MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200");
MODULE_LICENSE("GPL");
FIFOCTL_DIR = 0x10,
FIFOCTL_CLR = 0x08,
FIFOCTL_EMPTY = 0x04,
- FIFOCTL_RXERR = 0x02,
- FIFOCTL_TXERR = 0x01,
};
enum StirDiagMask {
struct qos_info qos;
unsigned speed; /* Current speed */
- wait_queue_head_t thr_wait; /* transmit thread wakeup */
- struct completion thr_exited;
- pid_t thr_pid;
+ struct task_struct *thread; /* transmit thread */
struct sk_buff *tx_pending;
void *io_buf; /* transmit/receive buffer */
REQ_WRITE_SINGLE,
USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
value, reg, NULL, 0,
- MSECS_TO_JIFFIES(CTRL_TIMEOUT));
+ CTRL_TIMEOUT);
}
/* Send control message to read multiple registers */
REQ_READ_REG,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, reg, data, count,
- MSECS_TO_JIFFIES(CTRL_TIMEOUT));
+ CTRL_TIMEOUT);
}
static inline int isfir(u32 speed)
found:
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)
*/
static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
{
- struct stir_cb *stir = netdev->priv;
+ struct stir_cb *stir = netdev_priv(netdev);
netif_stop_queue(netdev);
SKB_LINEAR_ASSERT(skb);
skb = xchg(&stir->tx_pending, skb);
- wake_up(&stir->thr_wait);
+ wake_up_process(stir->thread);
/* this should never happen unless stop/wakeup problem */
if (unlikely(skb)) {
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 (!(status & FIFOCTL_DIR)
|| (status & FIFOCTL_EMPTY))
return 0;
/* estimate transfer time for remaining chars */
- wait_ms((count * 8000) / stir->speed);
+ msleep((count * 8000) / stir->speed);
}
err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR);
return;
do_gettimeofday(&now);
- us -= (now.tv_sec - stir->rx_time.tv_sec) * USEC_PER_SEC;
+ if (now.tv_sec - stir->rx_time.tv_sec > 0)
+ us -= USEC_PER_SEC;
us -= now.tv_usec - stir->rx_time.tv_usec;
if (us < 10)
return;
ticks = us / (1000000 / HZ);
- if (ticks > 0) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1 + ticks);
- } else
+ if (ticks > 0)
+ schedule_timeout_interruptible(1 + ticks);
+ else
udelay(us);
}
static void receive_stop(struct stir_cb *stir)
{
stir->receiving = 0;
- usb_unlink_urb(stir->rx_urb);
+ usb_kill_urb(stir->rx_urb);
if (stir->rx_buff.in_frame)
stir->stats.collisions++;
if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),
stir->io_buf, wraplen,
- NULL, MSECS_TO_JIFFIES(TRANSMIT_TIMEOUT)))
+ NULL, TRANSMIT_TIMEOUT))
stir->stats.tx_errors++;
}
struct net_device *dev = stir->netdev;
struct sk_buff *skb;
- daemonize("%s", dev->name);
- allow_signal(SIGTERM);
-
- while (netif_running(dev)
- && netif_device_present(dev)
- && !signal_pending(current))
- {
+ while (!kthread_should_stop()) {
+#ifdef CONFIG_PM
/* if suspending, then power off and wait */
- if (current->flags & PF_FREEZE) {
+ if (unlikely(freezing(current))) {
if (stir->receiving)
receive_stop(stir);
else
write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);
- refrigerator(PF_FREEZE);
+ refrigerator();
if (change_speed(stir, stir->speed))
break;
}
+#endif
/* if something to send? */
skb = xchg(&stir->tx_pending, NULL);
stir_send(stir, skb);
dev_kfree_skb(skb);
- if (stir->speed != new_speed) {
+ if ((new_speed != -1) && (stir->speed != new_speed)) {
if (fifo_txwait(stir, -1) ||
change_speed(stir, new_speed))
break;
info("%s: receive usb submit failed",
stir->netdev->name);
stir->receiving = 0;
- wait_ms(10);
+ msleep(10);
continue;
}
}
/* sleep if nothing to send */
- wait_event_interruptible(stir->thr_wait, stir->tx_pending);
- }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
- complete_and_exit (&stir->thr_exited, 0);
+ }
+ return 0;
}
* Wakes up every ms (usb round trip) with wrapped
* data.
*/
-static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs)
+static void stir_rcv_irq(struct urb *urb)
{
struct stir_cb *stir = urb->context;
int err;
warn("%s: usb receive submit error: %d",
stir->netdev->name, err);
stir->receiving = 0;
- wake_up(&stir->thr_wait);
+ wake_up_process(stir->thread);
}
}
*/
static int stir_net_open(struct net_device *netdev)
{
- struct stir_cb *stir = netdev->priv;
+ struct stir_cb *stir = netdev_priv(netdev);
int err;
char hwname[16];
sprintf(hwname, "usb#%d", stir->usbdev->devnum);
stir->irlap = irlap_open(netdev, &stir->qos, hwname);
if (!stir->irlap) {
- err("irlap_open failed");
+ err("stir4200: irlap_open failed");
goto err_out5;
}
/** Start kernel thread for transmit. */
- stir->thr_pid = kernel_thread(stir_transmit_thread, stir,
- CLONE_FS|CLONE_FILES);
- if (stir->thr_pid < 0) {
- err = stir->thr_pid;
- err("unable to start kernel thread");
+ stir->thread = kthread_run(stir_transmit_thread, stir,
+ "%s", stir->netdev->name);
+ if (IS_ERR(stir->thread)) {
+ err = PTR_ERR(stir->thread);
+ err("stir4200: unable to start kernel thread");
goto err_out6;
}
*/
static int stir_net_close(struct net_device *netdev)
{
- struct stir_cb *stir = netdev->priv;
+ struct stir_cb *stir = netdev_priv(netdev);
/* Stop transmit processing */
netif_stop_queue(netdev);
/* Kill transmit thread */
- kill_proc(stir->thr_pid, SIGTERM, 1);
- wait_for_completion(&stir->thr_exited);
+ kthread_stop(stir->thread);
kfree(stir->fifo_status);
/* Mop up receive urb's */
- usb_unlink_urb(stir->rx_urb);
+ usb_kill_urb(stir->rx_urb);
kfree(stir->io_buf);
usb_free_urb(stir->rx_urb);
/*
* IOCTLs : Extra out-of-band network commands...
*/
-static int stir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *) rq;
- struct stir_cb *stir = dev->priv;
+ struct stir_cb *stir = netdev_priv(netdev);
int ret = 0;
switch (cmd) {
/*
* Get device stats (for /proc/net/dev and ifconfig)
*/
-static struct net_device_stats *stir_net_get_stats(struct net_device *dev)
+static struct net_device_stats *stir_net_get_stats(struct net_device *netdev)
{
- struct stir_cb *stir = dev->priv;
+ struct stir_cb *stir = netdev_priv(netdev);
return &stir->stats;
}
SET_MODULE_OWNER(net);
SET_NETDEV_DEV(net, &intf->dev);
- stir = net->priv;
+ stir = netdev_priv(net);
stir->netdev = net;
stir->usbdev = dev;
ret = usb_reset_configuration(dev);
if (ret != 0) {
- err("usb reset configuration failed");
+ err("stir4200: usb reset configuration failed");
goto err_out2;
}
printk(KERN_INFO "SigmaTel STIr4200 IRDA/USB found at address %d, "
"Vendor: %x, Product: %x\n",
- dev->devnum, dev->descriptor.idVendor,
- dev->descriptor.idProduct);
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&stir->qos);
stir->qos.min_turn_time.bits &= qos_mtt_bits;
irda_qos_bits_to_value(&stir->qos);
- init_completion (&stir->thr_exited);
- init_waitqueue_head (&stir->thr_wait);
-
/* Override the network functions we need to use */
net->hard_start_xmit = stir_hard_xmit;
net->open = stir_net_open;
if (ret != 0)
goto err_out2;
- MESSAGE("IrDA: Registered SigmaTel device %s\n", net->name);
+ info("IrDA: Registered SigmaTel device %s", net->name);
usb_set_intfdata(intf, stir);
usb_set_intfdata(intf, NULL);
}
-
-/* Power management suspend, so power off the transmitter/receiver */
-static int stir_suspend(struct usb_interface *intf, u32 state)
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int stir_suspend(struct usb_interface *intf, pm_message_t message)
{
struct stir_cb *stir = usb_get_intfdata(intf);
/* receiver restarted when send thread wakes up */
return 0;
}
+#endif
/*
* USB device callbacks
*/
static struct usb_driver irda_driver = {
- .owner = THIS_MODULE,
.name = "stir4200",
.probe = stir_probe,
.disconnect = stir_disconnect,
.id_table = dongles,
+#ifdef CONFIG_PM
.suspend = stir_suspend,
.resume = stir_resume,
+#endif
};
/*
*/
static int __init stir_init(void)
{
- if (usb_register(&irda_driver) < 0)
- return -1;
-
- MESSAGE("SigmaTel support registered\n");
- return 0;
+ return usb_register(&irda_driver);
}
module_init(stir_init);