Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (235 commits)
  [NETFILTER]: Add H.323 conntrack/NAT helper
  [TG3]: Don't mark tg3_test_registers() as returning const.
  [IPV6]: Cleanups for net/ipv6/addrconf.c (kzalloc, early exit) v2
  [IPV6]: Nearly complete kzalloc cleanup for net/ipv6
  [IPV6]: Cleanup of net/ipv6/reassambly.c
  [BRIDGE]: Remove duplicate const from is_link_local() argument type.
  [DECNET]: net/decnet/dn_route.c: fix inconsequent NULL checking
  [TG3]: make drivers/net/tg3.c:tg3_request_irq() static
  [BRIDGE]: use LLC to send STP
  [LLC]: llc_mac_hdr_init const arguments
  [BRIDGE]: allow show/store of group multicast address
  [BRIDGE]: use llc for receiving STP packets
  [BRIDGE]: stp timer to jiffies cleanup
  [BRIDGE]: forwarding remove unneeded preempt and bh diasables
  [BRIDGE]: netfilter inline cleanup
  [BRIDGE]: netfilter VLAN macro cleanup
  [BRIDGE]: netfilter dont use __constant_htons
  [BRIDGE]: netfilter whitespace
  [BRIDGE]: optimize frame pass up
  [BRIDGE]: use kzalloc
  ...
This commit is contained in:
Linus Torvalds
2006-03-21 09:31:48 -08:00
349 changed files with 18958 additions and 7283 deletions
+3 -2
View File
@@ -69,10 +69,11 @@ Unregisters new callback with connector core.
struct cb_id *id - unique connector's user identifier.
void cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
int cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
Sends message to the specified groups. It can be safely called from
any context, but may silently fail under strong memory pressure.
softirq context, but may silently fail under strong memory pressure.
If there are no listeners for given group -ESRCH can be returned.
struct cn_msg * - message header(with attached data).
u32 __group - destination group.
+47 -2
View File
@@ -355,6 +355,13 @@ somaxconn - INTEGER
Defaults to 128. See also tcp_max_syn_backlog for additional tuning
for TCP sockets.
tcp_workaround_signed_windows - BOOLEAN
If set, assume no receipt of a window scaling option means the
remote TCP is broken and treats the window as a signed quantity.
If unset, assume the remote TCP is not broken even if we do
not receive a window scaling option from them.
Default: 0
IP Variables:
ip_local_port_range - 2 INTEGERS
@@ -619,6 +626,11 @@ arp_ignore - INTEGER
The max value from conf/{all,interface}/arp_ignore is used
when ARP request is received on the {interface}
arp_accept - BOOLEAN
Define behavior when gratuitous arp replies are received:
0 - drop gratuitous arp frames
1 - accept gratuitous arp frames
app_solicit - INTEGER
The maximum number of probes to send to the user space ARP daemon
via netlink before dropping back to multicast probes (see
@@ -717,6 +729,33 @@ accept_ra - BOOLEAN
Functional default: enabled if local forwarding is disabled.
disabled if local forwarding is enabled.
accept_ra_defrtr - BOOLEAN
Learn default router in Router Advertisement.
Functional default: enabled if accept_ra is enabled.
disabled if accept_ra is disabled.
accept_ra_pinfo - BOOLEAN
Learn Prefix Inforamtion in Router Advertisement.
Functional default: enabled if accept_ra is enabled.
disabled if accept_ra is disabled.
accept_ra_rt_info_max_plen - INTEGER
Maximum prefix length of Route Information in RA.
Route Information w/ prefix larger than or equal to this
variable shall be ignored.
Functional default: 0 if accept_ra_rtr_pref is enabled.
-1 if accept_ra_rtr_pref is disabled.
accept_ra_rtr_pref - BOOLEAN
Accept Router Preference in RA.
Functional default: enabled if accept_ra is enabled.
disabled if accept_ra is disabled.
accept_redirects - BOOLEAN
Accept Redirects.
@@ -727,8 +766,8 @@ autoconf - BOOLEAN
Autoconfigure addresses using Prefix Information in Router
Advertisements.
Functional default: enabled if accept_ra is enabled.
disabled if accept_ra is disabled.
Functional default: enabled if accept_ra_pinfo is enabled.
disabled if accept_ra_pinfo is disabled.
dad_transmits - INTEGER
The amount of Duplicate Address Detection probes to send.
@@ -771,6 +810,12 @@ mtu - INTEGER
Default Maximum Transfer Unit
Default: 1280 (IPv6 required minimum)
router_probe_interval - INTEGER
Minimum interval (in seconds) between Router Probing described
in RFC4191.
Default: 60
router_solicitation_delay - INTEGER
Number of seconds to wait after interface is brought up
before sending Router Solicitations.
+1 -1
View File
@@ -188,7 +188,7 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg)
case SONET_GETDIAG:
return get_diag(dev,arg);
case SONET_SETFRAMING:
if (arg != SONET_FRAME_SONET) return -EINVAL;
if ((int)(unsigned long)arg != SONET_FRAME_SONET) return -EINVAL;
return 0;
case SONET_GETFRAMING:
return put_user(SONET_FRAME_SONET,(int __user *)arg) ?
+4 -3
View File
@@ -97,6 +97,9 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
group = __group;
}
if (!netlink_has_listeners(dev->nls, group))
return -ESRCH;
size = NLMSG_SPACE(sizeof(*msg) + msg->len);
skb = alloc_skb(size, gfp_mask);
@@ -111,9 +114,7 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
NETLINK_CB(skb).dst_group = group;
netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
return 0;
return netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
nlmsg_failure:
kfree_skb(skb);
+1 -15
View File
@@ -253,7 +253,6 @@ static void path_free(struct net_device *dev, struct ipoib_path *path)
if (neigh->ah)
ipoib_put_ah(neigh->ah);
*to_ipoib_neigh(neigh->neighbour) = NULL;
neigh->neighbour->ops->destructor = NULL;
kfree(neigh);
}
@@ -531,7 +530,6 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
err:
*to_ipoib_neigh(skb->dst->neighbour) = NULL;
list_del(&neigh->list);
neigh->neighbour->ops->destructor = NULL;
kfree(neigh);
++priv->stats.tx_dropped;
@@ -770,21 +768,9 @@ static void ipoib_neigh_destructor(struct neighbour *n)
ipoib_put_ah(ah);
}
static int ipoib_neigh_setup(struct neighbour *neigh)
{
/*
* Is this kosher? I can't find anybody in the kernel that
* sets neigh->destructor, so we should be able to set it here
* without trouble.
*/
neigh->ops->destructor = ipoib_neigh_destructor;
return 0;
}
static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms)
{
parms->neigh_setup = ipoib_neigh_setup;
parms->neigh_destructor = ipoib_neigh_destructor;
return 0;
}
+1 -1
View File
@@ -1605,7 +1605,7 @@ static void rtl8139_thread (void *_data)
if (tp->watchdog_fired) {
tp->watchdog_fired = 0;
rtl8139_tx_timeout_task(_data);
} else if (rtnl_shlock_nowait() == 0) {
} else if (rtnl_trylock()) {
rtl8139_thread_iter (dev, tp, tp->mmio_addr);
rtnl_unlock ();
} else {
+172 -303
View File
File diff suppressed because it is too large Load Diff
+23 -14
View File
@@ -23,6 +23,7 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -3792,8 +3793,10 @@ struct l2_fhdr {
#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct tx_bd))
#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
#define MAX_RX_RINGS 4
#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct rx_bd))
#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
#define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS)
#define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) == \
(MAX_TX_DESC_CNT - 1)) ? \
@@ -3805,8 +3808,10 @@ struct l2_fhdr {
(MAX_RX_DESC_CNT - 1)) ? \
(x) + 2 : (x) + 1
#define RX_RING_IDX(x) ((x) & MAX_RX_DESC_CNT)
#define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> 8)
#define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
/* Context size. */
#define CTX_SHIFT 7
@@ -3903,6 +3908,15 @@ struct bnx2 {
struct status_block *status_blk;
u32 last_status_idx;
u32 flags;
#define PCIX_FLAG 1
#define PCI_32BIT_FLAG 2
#define ONE_TDMA_FLAG 4 /* no longer used */
#define NO_WOL_FLAG 8
#define USING_DAC_FLAG 0x10
#define USING_MSI_FLAG 0x20
#define ASF_ENABLE_FLAG 0x40
struct tx_bd *tx_desc_ring;
struct sw_bd *tx_buf_ring;
u32 tx_prod_bseq;
@@ -3920,19 +3934,22 @@ struct bnx2 {
u32 rx_offset;
u32 rx_buf_use_size; /* useable size */
u32 rx_buf_size; /* with alignment */
struct rx_bd *rx_desc_ring;
struct sw_bd *rx_buf_ring;
u32 rx_max_ring_idx;
u32 rx_prod_bseq;
u16 rx_prod;
u16 rx_cons;
u32 rx_csum;
struct sw_bd *rx_buf_ring;
struct rx_bd *rx_desc_ring[MAX_RX_RINGS];
/* Only used to synchronize netif_stop_queue/wake_queue when tx */
/* ring is full */
spinlock_t tx_lock;
/* End of fileds used in the performance code paths. */
/* End of fields used in the performance code paths. */
char *name;
@@ -3945,15 +3962,6 @@ struct bnx2 {
/* Used to synchronize phy accesses. */
spinlock_t phy_lock;
u32 flags;
#define PCIX_FLAG 1
#define PCI_32BIT_FLAG 2
#define ONE_TDMA_FLAG 4 /* no longer used */
#define NO_WOL_FLAG 8
#define USING_DAC_FLAG 0x10
#define USING_MSI_FLAG 0x20
#define ASF_ENABLE_FLAG 0x40
u32 phy_flags;
#define PHY_SERDES_FLAG 1
#define PHY_CRC_FIX_FLAG 2
@@ -4004,8 +4012,9 @@ struct bnx2 {
dma_addr_t tx_desc_mapping;
int rx_max_ring;
int rx_ring_size;
dma_addr_t rx_desc_mapping;
dma_addr_t rx_desc_mapping[MAX_RX_RINGS];
u16 tx_quick_cons_trip;
u16 tx_quick_cons_trip_int;
+20 -20
View File
@@ -91,6 +91,7 @@
#include <linux/mii.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/mutex.h>
#include <net/checksum.h>
@@ -3892,7 +3893,7 @@ static void cas_reset(struct cas *cp, int blkflag)
spin_unlock(&cp->stat_lock[N_TX_RINGS]);
}
/* Shut down the chip, must be called with pm_sem held. */
/* Shut down the chip, must be called with pm_mutex held. */
static void cas_shutdown(struct cas *cp)
{
unsigned long flags;
@@ -4311,11 +4312,11 @@ static int cas_open(struct net_device *dev)
int hw_was_up, err;
unsigned long flags;
down(&cp->pm_sem);
mutex_lock(&cp->pm_mutex);
hw_was_up = cp->hw_running;
/* The power-management semaphore protects the hw_running
/* The power-management mutex protects the hw_running
* etc. state so it is safe to do this bit without cp->lock
*/
if (!cp->hw_running) {
@@ -4364,7 +4365,7 @@ static int cas_open(struct net_device *dev)
cas_unlock_all_restore(cp, flags);
netif_start_queue(dev);
up(&cp->pm_sem);
mutex_unlock(&cp->pm_mutex);
return 0;
err_spare:
@@ -4372,7 +4373,7 @@ err_spare:
cas_free_rxds(cp);
err_tx_tiny:
cas_tx_tiny_free(cp);
up(&cp->pm_sem);
mutex_unlock(&cp->pm_mutex);
return err;
}
@@ -4382,7 +4383,7 @@ static int cas_close(struct net_device *dev)
struct cas *cp = netdev_priv(dev);
/* Make sure we don't get distracted by suspend/resume */
down(&cp->pm_sem);
mutex_lock(&cp->pm_mutex);
netif_stop_queue(dev);
@@ -4399,7 +4400,7 @@ static int cas_close(struct net_device *dev)
cas_spare_free(cp);
cas_free_rxds(cp);
cas_tx_tiny_free(cp);
up(&cp->pm_sem);
mutex_unlock(&cp->pm_mutex);
return 0;
}
@@ -4834,10 +4835,10 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
unsigned long flags;
int rc = -EOPNOTSUPP;
/* Hold the PM semaphore while doing ioctl's or we may collide
/* Hold the PM mutex while doing ioctl's or we may collide
* with open/close and power management and oops.
*/
down(&cp->pm_sem);
mutex_lock(&cp->pm_mutex);
switch (cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = cp->phy_addr;
@@ -4867,7 +4868,7 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
};
up(&cp->pm_sem);
mutex_unlock(&cp->pm_mutex);
return rc;
}
@@ -4994,7 +4995,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
spin_lock_init(&cp->tx_lock[i]);
}
spin_lock_init(&cp->stat_lock[N_TX_RINGS]);
init_MUTEX(&cp->pm_sem);
mutex_init(&cp->pm_mutex);
init_timer(&cp->link_timer);
cp->link_timer.function = cas_link_timer;
@@ -5116,10 +5117,10 @@ err_out_free_consistent:
cp->init_block, cp->block_dvma);
err_out_iounmap:
down(&cp->pm_sem);
mutex_lock(&cp->pm_mutex);
if (cp->hw_running)
cas_shutdown(cp);
up(&cp->pm_sem);
mutex_unlock(&cp->pm_mutex);
iounmap(cp->regs);
@@ -5152,11 +5153,11 @@ static void __devexit cas_remove_one(struct pci_dev *pdev)
cp = netdev_priv(dev);
unregister_netdev(dev);
down(&cp->pm_sem);
mutex_lock(&cp->pm_mutex);
flush_scheduled_work();
if (cp->hw_running)
cas_shutdown(cp);
up(&cp->pm_sem);
mutex_unlock(&cp->pm_mutex);
#if 1
if (cp->orig_cacheline_size) {
@@ -5183,10 +5184,7 @@ static int cas_suspend(struct pci_dev *pdev, pm_message_t state)
struct cas *cp = netdev_priv(dev);
unsigned long flags;
/* We hold the PM semaphore during entire driver
* sleep time
*/
down(&cp->pm_sem);
mutex_lock(&cp->pm_mutex);
/* If the driver is opened, we stop the DMA */
if (cp->opened) {
@@ -5206,6 +5204,7 @@ static int cas_suspend(struct pci_dev *pdev, pm_message_t state)
if (cp->hw_running)
cas_shutdown(cp);
mutex_unlock(&cp->pm_mutex);
return 0;
}
@@ -5217,6 +5216,7 @@ static int cas_resume(struct pci_dev *pdev)
printk(KERN_INFO "%s: resuming\n", dev->name);
mutex_lock(&cp->pm_mutex);
cas_hard_reset(cp);
if (cp->opened) {
unsigned long flags;
@@ -5229,7 +5229,7 @@ static int cas_resume(struct pci_dev *pdev)
netif_device_attach(dev);
}
up(&cp->pm_sem);
mutex_unlock(&cp->pm_mutex);
return 0;
}
#endif /* CONFIG_PM */
+1 -1
View File
@@ -4284,7 +4284,7 @@ struct cas {
* (ie. not power managed) */
int hw_running;
int opened;
struct semaphore pm_sem; /* open/close/suspend/resume */
struct mutex pm_mutex; /* open/close/suspend/resume */
struct cas_init_block *init_block;
struct cas_tx_desc *init_txds[MAX_TX_RINGS];
+1 -1
View File
@@ -920,7 +920,7 @@ e1000_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
#ifdef CONFIG_E1000_NAPI
for (i = 0; i < adapter->num_rx_queues; i++)
__dev_put(&adapter->polling_netdev[i]);
dev_put(&adapter->polling_netdev[i]);
#endif
if (!e1000_check_phy_reset_block(&adapter->hw))
+8
View File
@@ -64,6 +64,14 @@ config TEKRAM_DONGLE
dongles you will have to start irattach like this:
"irattach -d tekram".
config TOIM3232_DONGLE
tristate "TOIM3232 IrDa dongle"
depends on DONGLE && IRDA
help
Say Y here if you want to build support for the Vishay/Temic
TOIM3232 and TOIM4232 based dongles.
To compile it as a module, choose M here.
config LITELINK_DONGLE
tristate "Parallax LiteLink dongle"
depends on DONGLE && IRDA
+1
View File
@@ -43,6 +43,7 @@ obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin-sir.o
obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o
obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
# The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o
+1 -1
View File
@@ -1778,7 +1778,7 @@ static struct pci_driver donauboe_pci_driver = {
static int __init
donauboe_init (void)
{
return pci_module_init(&donauboe_pci_driver);
return pci_register_driver(&donauboe_pci_driver);
}
static void __exit
+7 -4
View File
@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h>
@@ -23,6 +24,8 @@ static void ep7211_ir_close(dongle_t *self);
static int ep7211_ir_change_speed(struct irda_task *task);
static int ep7211_ir_reset(struct irda_task *task);
static DEFINE_SPINLOCK(ep7211_lock);
static struct dongle_reg dongle = {
.type = IRDA_EP7211_IR,
.open = ep7211_ir_open,
@@ -36,7 +39,7 @@ static void ep7211_ir_open(dongle_t *self, struct qos_info *qos)
{
unsigned int syscon1, flags;
save_flags(flags); cli();
spin_lock_irqsave(&ep7211_lock, flags);
/* Turn on the SIR encoder. */
syscon1 = clps_readl(SYSCON1);
@@ -46,14 +49,14 @@ static void ep7211_ir_open(dongle_t *self, struct qos_info *qos)
/* XXX: We should disable modem status interrupts on the first
UART (interrupt #14). */
restore_flags(flags);
spin_unlock_irqrestore(&ep7211_lock, flags);
}
static void ep7211_ir_close(dongle_t *self)
{
unsigned int syscon1, flags;
save_flags(flags); cli();
spin_lock_irqsave(&ep7211_lock, flags);
/* Turn off the SIR encoder. */
syscon1 = clps_readl(SYSCON1);
@@ -63,7 +66,7 @@ static void ep7211_ir_close(dongle_t *self)
/* XXX: If we've disabled the modem status interrupts, we should
reset them back to their original state. */
restore_flags(flags);
spin_unlock_irqrestore(&ep7211_lock, flags);
}
/*
+10 -9
View File
@@ -33,6 +33,7 @@
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h>
@@ -338,7 +339,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
/*****************************************************************/
/* serialize ldisc open/close with sir_dev */
static DECLARE_MUTEX(irtty_sem);
static DEFINE_MUTEX(irtty_mutex);
/* notifier from sir_dev when irda% device gets opened (ifup) */
@@ -348,11 +349,11 @@ static int irtty_start_dev(struct sir_dev *dev)
struct tty_struct *tty;
/* serialize with ldisc open/close */
down(&irtty_sem);
mutex_lock(&irtty_mutex);
priv = dev->priv;
if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
up(&irtty_sem);
mutex_unlock(&irtty_mutex);
return -ESTALE;
}
@@ -363,7 +364,7 @@ static int irtty_start_dev(struct sir_dev *dev)
/* Make sure we can receive more data */
irtty_stop_receiver(tty, FALSE);
up(&irtty_sem);
mutex_unlock(&irtty_mutex);
return 0;
}
@@ -375,11 +376,11 @@ static int irtty_stop_dev(struct sir_dev *dev)
struct tty_struct *tty;
/* serialize with ldisc open/close */
down(&irtty_sem);
mutex_lock(&irtty_mutex);
priv = dev->priv;
if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
up(&irtty_sem);
mutex_unlock(&irtty_mutex);
return -ESTALE;
}
@@ -390,7 +391,7 @@ static int irtty_stop_dev(struct sir_dev *dev)
if (tty->driver->stop)
tty->driver->stop(tty);
up(&irtty_sem);
mutex_unlock(&irtty_mutex);
return 0;
}
@@ -514,13 +515,13 @@ static int irtty_open(struct tty_struct *tty)
priv->dev = dev;
/* serialize with start_dev - in case we were racing with ifup */
down(&irtty_sem);
mutex_lock(&irtty_mutex);
dev->priv = priv;
tty->disc_data = priv;
tty->receive_room = 65536;
up(&irtty_sem);
mutex_unlock(&irtty_mutex);
IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, tty->name);
+258 -76
View File
@@ -12,6 +12,7 @@
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
* Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
* Copyright (c) 1998 Actisys Corp., www.actisys.com
* Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or
@@ -53,14 +54,13 @@
#include <linux/init.h>
#include <linux/rtnetlink.h>
#include <linux/dma-mapping.h>
#include <linux/pnp.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <linux/pm.h>
#include <linux/pm_legacy.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h>
@@ -72,14 +72,27 @@
static char *driver_name = "nsc-ircc";
/* Power Management */
#define NSC_IRCC_DRIVER_NAME "nsc-ircc"
static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
static int nsc_ircc_resume(struct platform_device *dev);
static struct platform_driver nsc_ircc_driver = {
.suspend = nsc_ircc_suspend,
.resume = nsc_ircc_resume,
.driver = {
.name = NSC_IRCC_DRIVER_NAME,
},
};
/* Module parameters */
static int qos_mtt_bits = 0x07; /* 1 ms or more */
static int dongle_id;
/* Use BIOS settions by default, but user may supply module parameters */
static unsigned int io[] = { ~0, ~0, ~0, ~0 };
static unsigned int irq[] = { 0, 0, 0, 0, 0 };
static unsigned int dma[] = { 0, 0, 0, 0, 0 };
static unsigned int io[] = { ~0, ~0, ~0, ~0, ~0 };
static unsigned int irq[] = { 0, 0, 0, 0, 0 };
static unsigned int dma[] = { 0, 0, 0, 0, 0 };
static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
@@ -87,6 +100,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
/* These are the known NSC chips */
static nsc_chip_t chips[] = {
@@ -101,11 +115,12 @@ static nsc_chip_t chips[] = {
/* Contributed by Jan Frey - IBM A30/A31 */
{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x },
{ "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x },
{ NULL }
};
/* Max 4 instances for now */
static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
static char *dongle_types[] = {
"Differential serial interface",
@@ -126,8 +141,24 @@ static char *dongle_types[] = {
"No dongle connected",
};
/* PNP probing */
static chipio_t pnp_info;
static const struct pnp_device_id nsc_ircc_pnp_table[] = {
{ .id = "NSC6001", .driver_data = 0 },
{ .id = "IBM0071", .driver_data = 0 },
{ }
};
MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
static struct pnp_driver nsc_ircc_pnp_driver = {
.name = "nsc-ircc",
.id_table = nsc_ircc_pnp_table,
.probe = nsc_ircc_pnp_probe,
};
/* Some prototypes */
static int nsc_ircc_open(int i, chipio_t *info);
static int nsc_ircc_open(chipio_t *info);
static int nsc_ircc_close(struct nsc_ircc_cb *self);
static int nsc_ircc_setup(chipio_t *info);
static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
@@ -146,7 +177,10 @@ static int nsc_ircc_net_open(struct net_device *dev);
static int nsc_ircc_net_close(struct net_device *dev);
static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
/* Globals */
static int pnp_registered;
static int pnp_succeeded;
/*
* Function nsc_ircc_init ()
@@ -158,28 +192,36 @@ static int __init nsc_ircc_init(void)
{
chipio_t info;
nsc_chip_t *chip;
int ret = -ENODEV;
int ret;
int cfg_base;
int cfg, id;
int reg;
int i = 0;
ret = platform_driver_register(&nsc_ircc_driver);
if (ret) {
IRDA_ERROR("%s, Can't register driver!\n", driver_name);
return ret;
}
/* Register with PnP subsystem to detect disable ports */
ret = pnp_register_driver(&nsc_ircc_pnp_driver);
if (ret >= 0)
pnp_registered = 1;
ret = -ENODEV;
/* Probe for all the NSC chipsets we know about */
for (chip=chips; chip->name ; chip++) {
for (chip = chips; chip->name ; chip++) {
IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__,
chip->name);
/* Try all config registers for this chip */
for (cfg=0; cfg<3; cfg++) {
for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
cfg_base = chip->cfg[cfg];
if (!cfg_base)
continue;
memset(&info, 0, sizeof(chipio_t));
info.cfg_base = cfg_base;
info.fir_base = io[i];
info.dma = dma[i];
info.irq = irq[i];
/* Read index register */
reg = inb(cfg_base);
@@ -194,24 +236,65 @@ static int __init nsc_ircc_init(void)
if ((id & chip->cid_mask) == chip->cid_value) {
IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
__FUNCTION__, chip->name, id & ~chip->cid_mask);
/*
* If the user supplies the base address, then
* we init the chip, if not we probe the values
* set by the BIOS
*/
if (io[i] < 0x2000) {
chip->init(chip, &info);
} else
chip->probe(chip, &info);
if (nsc_ircc_open(i, &info) == 0)
ret = 0;
/*
* If we found a correct PnP setting,
* we first try it.
*/
if (pnp_succeeded) {
memset(&info, 0, sizeof(chipio_t));
info.cfg_base = cfg_base;
info.fir_base = pnp_info.fir_base;
info.dma = pnp_info.dma;
info.irq = pnp_info.irq;
if (info.fir_base < 0x2000) {
IRDA_MESSAGE("%s, chip->init\n", driver_name);
chip->init(chip, &info);
} else
chip->probe(chip, &info);
if (nsc_ircc_open(&info) >= 0)
ret = 0;
}
/*
* Opening based on PnP values failed.
* Let's fallback to user values, or probe
* the chip.
*/
if (ret) {
IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name);
memset(&info, 0, sizeof(chipio_t));
info.cfg_base = cfg_base;
info.fir_base = io[i];
info.dma = dma[i];
info.irq = irq[i];
/*
* If the user supplies the base address, then
* we init the chip, if not we probe the values
* set by the BIOS
*/
if (io[i] < 0x2000) {
chip->init(chip, &info);
} else
chip->probe(chip, &info);
if (nsc_ircc_open(&info) >= 0)
ret = 0;
}
i++;
} else {
IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id);
}
}
}
if (ret) {
platform_driver_unregister(&nsc_ircc_driver);
pnp_unregister_driver(&nsc_ircc_pnp_driver);
pnp_registered = 0;
}
return ret;
@@ -227,12 +310,17 @@ static void __exit nsc_ircc_cleanup(void)
{
int i;
pm_unregister_all(nsc_ircc_pmproc);
for (i=0; i < 4; i++) {
for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i])
nsc_ircc_close(dev_self[i]);
}
platform_driver_unregister(&nsc_ircc_driver);
if (pnp_registered)
pnp_unregister_driver(&nsc_ircc_pnp_driver);
pnp_registered = 0;
}
/*
@@ -241,16 +329,26 @@ static void __exit nsc_ircc_cleanup(void)
* Open driver instance
*
*/
static int __init nsc_ircc_open(int i, chipio_t *info)
static int __init nsc_ircc_open(chipio_t *info)
{
struct net_device *dev;
struct nsc_ircc_cb *self;
struct pm_dev *pmdev;
void *ret;
int err;
int err, chip_index;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
if (!dev_self[chip_index])
break;
}
if (chip_index == ARRAY_SIZE(dev_self)) {
IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__);
return -ENOMEM;
}
IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
info->cfg_base);
@@ -271,8 +369,8 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
spin_lock_init(&self->lock);
/* Need to store self somewhere */
dev_self[i] = self;
self->index = i;
dev_self[chip_index] = self;
self->index = chip_index;
/* Initialize IO */
self->io.cfg_base = info->cfg_base;
@@ -351,7 +449,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
/* Check if user has supplied a valid dongle id or not */
if ((dongle_id <= 0) ||
(dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) {
(dongle_id >= ARRAY_SIZE(dongle_types))) {
dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
@@ -364,11 +462,18 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
self->io.dongle_id = dongle_id;
nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc);
if (pmdev)
pmdev->data = self;
self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
self->index, NULL, 0);
if (IS_ERR(self->pldev)) {
err = PTR_ERR(self->pldev);
goto out5;
}
platform_set_drvdata(self->pldev, self);
return 0;
return chip_index;
out5:
unregister_netdev(dev);
out4:
dma_free_coherent(NULL, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
@@ -379,7 +484,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info)
release_region(self->io.fir_base, self->io.fir_ext);
out1:
free_netdev(dev);
dev_self[i] = NULL;
dev_self[chip_index] = NULL;
return err;
}
@@ -399,6 +504,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self)
iobase = self->io.fir_base;
platform_device_unregister(self->pldev);
/* Remove netdevice */
unregister_netdev(self->netdev);
@@ -806,6 +913,43 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
return 0;
}
/* PNP probing */
static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
{
memset(&pnp_info, 0, sizeof(chipio_t));
pnp_info.irq = -1;
pnp_info.dma = -1;
pnp_succeeded = 1;
/* There don't seem to be any way to get the cfg_base.
* On my box, cfg_base is in the PnP descriptor of the
* motherboard. Oh well... Jean II */
if (pnp_port_valid(dev, 0) &&
!(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED))
pnp_info.fir_base = pnp_port_start(dev, 0);
if (pnp_irq_valid(dev, 0) &&
!(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
pnp_info.irq = pnp_irq(dev, 0);
if (pnp_dma_valid(dev, 0) &&
!(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
pnp_info.dma = pnp_dma(dev, 0);
IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
__FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
if((pnp_info.fir_base == 0) ||
(pnp_info.irq == -1) || (pnp_info.dma == -1)) {
/* Returning an error will disable the device. Yuck ! */
//return -EINVAL;
pnp_succeeded = 0;
}
return 0;
}
/*
* Function nsc_ircc_setup (info)
*
@@ -2161,47 +2305,85 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
return &self->stats;
}
static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
{
IRDA_MESSAGE("%s, Suspending\n", driver_name);
struct nsc_ircc_cb *self = platform_get_drvdata(dev);
int bank;
unsigned long flags;
int iobase = self->io.fir_base;
if (self->io.suspended)
return;
return 0;
nsc_ircc_net_close(self->netdev);
IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
rtnl_lock();
if (netif_running(self->netdev)) {
netif_device_detach(self->netdev);
spin_lock_irqsave(&self->lock, flags);
/* Save current bank */
bank = inb(iobase+BSR);
/* Disable interrupts */
switch_bank(iobase, BANK0);
outb(0, iobase+IER);
/* Restore bank register */
outb(bank, iobase+BSR);
spin_unlock_irqrestore(&self->lock, flags);
free_irq(self->io.irq, self->netdev);
disable_dma(self->io.dma);
}
self->io.suspended = 1;
}
rtnl_unlock();
static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
{
if (!self->io.suspended)
return;
nsc_ircc_setup(&self->io);
nsc_ircc_net_open(self->netdev);
IRDA_MESSAGE("%s, Waking up\n", driver_name);
self->io.suspended = 0;
}
static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
{
struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data;
if (self) {
switch (rqst) {
case PM_SUSPEND:
nsc_ircc_suspend(self);
break;
case PM_RESUME:
nsc_ircc_wakeup(self);
break;
}
}
return 0;
}
static int nsc_ircc_resume(struct platform_device *dev)
{
struct nsc_ircc_cb *self = platform_get_drvdata(dev);
unsigned long flags;
if (!self->io.suspended)
return 0;
IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
rtnl_lock();
nsc_ircc_setup(&self->io);
nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id);
if (netif_running(self->netdev)) {
if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,
self->netdev->name, self->netdev)) {
IRDA_WARNING("%s, unable to allocate irq=%d\n",
driver_name, self->io.irq);
/*
* Don't fail resume process, just kill this
* network interface
*/
unregister_netdevice(self->netdev);
} else {
spin_lock_irqsave(&self->lock, flags);
nsc_ircc_change_speed(self, self->io.speed);
spin_unlock_irqrestore(&self->lock, flags);
netif_device_attach(self->netdev);
}
} else {
spin_lock_irqsave(&self->lock, flags);
nsc_ircc_change_speed(self, 9600);
spin_unlock_irqrestore(&self->lock, flags);
}
self->io.suspended = 0;
rtnl_unlock();
return 0;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("NSC IrDA Device Driver");
MODULE_LICENSE("GPL");
+1 -1
View File
@@ -269,7 +269,7 @@ struct nsc_ircc_cb {
__u32 new_speed;
int index; /* Instance index */
struct pm_dev *dev;
struct platform_device *pldev;
};
static inline void switch_bank(int iobase, int bank)
+10 -9
View File
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/kmod.h>
#include <linux/mutex.h>
#include <net/irda/irda.h>
@@ -28,7 +29,7 @@
*/
static LIST_HEAD(dongle_list); /* list of registered dongle drivers */
static DECLARE_MUTEX(dongle_list_lock); /* protects the list */
static DEFINE_MUTEX(dongle_list_lock); /* protects the list */
int irda_register_dongle(struct dongle_driver *new)
{
@@ -38,25 +39,25 @@ int irda_register_dongle(struct dongle_driver *new)
IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n",
__FUNCTION__, new->driver_name, new->type);
down(&dongle_list_lock);
mutex_lock(&dongle_list_lock);
list_for_each(entry, &dongle_list) {
drv = list_entry(entry, struct dongle_driver, dongle_list);
if (new->type == drv->type) {
up(&dongle_list_lock);
mutex_unlock(&dongle_list_lock);
return -EEXIST;
}
}
list_add(&new->dongle_list, &dongle_list);
up(&dongle_list_lock);
mutex_unlock(&dongle_list_lock);
return 0;
}
EXPORT_SYMBOL(irda_register_dongle);
int irda_unregister_dongle(struct dongle_driver *drv)
{
down(&dongle_list_lock);
mutex_lock(&dongle_list_lock);
list_del(&drv->dongle_list);
up(&dongle_list_lock);
mutex_unlock(&dongle_list_lock);
return 0;
}
EXPORT_SYMBOL(irda_unregister_dongle);
@@ -75,7 +76,7 @@ int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
return -EBUSY;
/* serialize access to the list of registered dongles */
down(&dongle_list_lock);
mutex_lock(&dongle_list_lock);
list_for_each(entry, &dongle_list) {
drv = list_entry(entry, struct dongle_driver, dongle_list);
@@ -109,14 +110,14 @@ int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
if (!drv->open || (err=drv->open(dev))!=0)
goto out_reject; /* failed to open driver */
up(&dongle_list_lock);
mutex_unlock(&dongle_list_lock);
return 0;
out_reject:
dev->dongle_drv = NULL;
module_put(drv->owner);
out_unlock:
up(&dongle_list_lock);
mutex_unlock(&dongle_list_lock);
return err;
}
+375
View File
@@ -0,0 +1,375 @@
/*********************************************************************
*
* Filename: toim3232-sir.c
* Version: 1.0
* Description: Implementation of dongles based on the Vishay/Temic
* TOIM3232 SIR Endec chipset. Currently only the
* IRWave IR320ST-2 is tested, although it should work
* with any TOIM3232 or TOIM4232 chipset based RS232
* dongle with minimal modification.
* Based heavily on the Tekram driver (tekram.c),
* with thanks to Dag Brattli and Martin Diehl.
* Status: Experimental.
* Author: David Basden <davidb-irda@rcpt.to>
* Created at: Thu Feb 09 23:47:32 2006
*
* Copyright (c) 2006 David Basden.
* Copyright (c) 1998-1999 Dag Brattli,
* Copyright (c) 2002 Martin Diehl,
* All Rights Reserved.
*
* 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.
*
* Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
********************************************************************/
/*
* This driver has currently only been tested on the IRWave IR320ST-2
*
* PROTOCOL:
*
* The protocol for talking to the TOIM3232 is quite easy, and is
* designed to interface with RS232 with only level convertors. The
* BR/~D line on the chip is brought high to signal 'command mode',
* where a command byte is sent to select the baudrate of the RS232
* interface and the pulse length of the IRDA output. When BR/~D
* is brought low, the dongle then changes to the selected baudrate,
* and the RS232 interface is used for data until BR/~D is brought
* high again. The initial speed for the TOIMx323 after RESET is
* 9600 baud. The baudrate for command-mode is the last selected
* baud-rate, or 9600 after a RESET.
*
* The dongle I have (below) adds some extra hardware on the front end,
* but this is mostly directed towards pariasitic power from the RS232
* line rather than changing very much about how to communicate with
* the TOIM3232.
*
* The protocol to talk to the TOIM4232 chipset seems to be almost
* identical to the TOIM3232 (and the 4232 datasheet is more detailed)
* so this code will probably work on that as well, although I haven't
* tested it on that hardware.
*
* Target dongle variations that might be common:
*
* DTR and RTS function:
* The data sheet for the 4232 has a sample implementation that hooks the
* DTR and RTS lines to the RESET and BaudRate/~Data lines of the
* chip (through line-converters). Given both DTR and RTS would have to
* be held low in normal operation, and the TOIMx232 requires +5V to
* signal ground, most dongle designers would almost certainly choose
* an implementation that kept at least one of DTR or RTS high in
* normal operation to provide power to the dongle, but will likely
* vary between designs.
*
* User specified command bits:
* There are two user-controllable output lines from the TOIMx232 that
* can be set low or high by setting the appropriate bits in the
* high-nibble of the command byte (when setting speed and pulse length).
* These might be used to switch on and off added hardware or extra
* dongle features.
*
*
* Target hardware: IRWave IR320ST-2
*
* The IRWave IR320ST-2 is a simple dongle based on the Vishay/Temic
* TOIM3232 SIR Endec and the Vishay/Temic TFDS4500 SIR IRDA transciever.
* It uses a hex inverter and some discrete components to buffer and
* line convert the RS232 down to 5V.
*
* The dongle is powered through a voltage regulator, fed by a large
* capacitor. To switch the dongle on, DTR is brought high to charge
* the capacitor and drive the voltage regulator. DTR isn't associated
* with any control lines on the TOIM3232. Parisitic power is also taken
* from the RTS, TD and RD lines when brought high, but through resistors.
* When DTR is low, the circuit might lose power even with RTS high.
*
* RTS is inverted and attached to the BR/~D input pin. When RTS
* is high, BR/~D is low, and the TOIM3232 is in the normal 'data' mode.
* RTS is brought low, BR/~D is high, and the TOIM3232 is in 'command
* mode'.
*
* For some unknown reason, the RESET line isn't actually connected
* to anything. This means to reset the dongle to get it to a known
* state (9600 baud) you must drop DTR and RTS low, wait for the power
* capacitor to discharge, and then bring DTR (and RTS for data mode)
* high again, and wait for the capacitor to charge, the power supply
* to stabilise, and the oscillator clock to stabilise.
*
* Fortunately, if the current baudrate is known, the chipset can
* easily change speed by entering command mode without having to
* reset the dongle first.
*
* Major Components:
*
* - Vishay/Temic TOIM3232 SIR Endec to change RS232 pulse timings
* to IRDA pulse timings
* - 3.6864MHz crystal to drive TOIM3232 clock oscillator
* - DM74lS04M Inverting Hex line buffer for RS232 input buffering
* and level conversion
* - PJ2951AC 150mA voltage regulator
* - Vishay/Temic TFDS4500 SIR IRDA front-end transceiver
*
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
static int toim3232delay = 150; /* default is 150 ms */
module_param(toim3232delay, int, 0);
MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay");
#if 0
static int toim3232flipdtr = 0; /* default is DTR high to reset */
module_param(toim3232flipdtr, int, 0);
MODULE_PARM_DESC(toim3232flipdtr, "toim3232 dongle invert DTR (Reset)");
static int toim3232fliprts = 0; /* default is RTS high for baud change */
module_param(toim3232fliptrs, int, 0);
MODULE_PARM_DESC(toim3232fliprts, "toim3232 dongle invert RTS (BR/D)");
#endif
static int toim3232_open(struct sir_dev *);
static int toim3232_close(struct sir_dev *);
static int toim3232_change_speed(struct sir_dev *, unsigned);
static int toim3232_reset(struct sir_dev *);
#define TOIM3232_115200 0x00
#define TOIM3232_57600 0x01
#define TOIM3232_38400 0x02
#define TOIM3232_19200 0x03
#define TOIM3232_9600 0x06
#define TOIM3232_2400 0x0A
#define TOIM3232_PW 0x10 /* Pulse select bit */
static struct dongle_driver toim3232 = {
.owner = THIS_MODULE,
.driver_name = "Vishay TOIM3232",
.type = IRDA_TOIM3232_DONGLE,
.open = toim3232_open,
.close = toim3232_close,
.reset = toim3232_reset,
.set_speed = toim3232_change_speed,
};
static int __init toim3232_sir_init(void)
{
if (toim3232delay < 1 || toim3232delay > 500)
toim3232delay = 200;
IRDA_DEBUG(1, "%s - using %d ms delay\n",
toim3232.driver_name, toim3232delay);
return irda_register_dongle(&toim3232);
}
static void __exit toim3232_sir_cleanup(void)
{
irda_unregister_dongle(&toim3232);
}
static int toim3232_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
/* Pull the lines high to start with.
*
* For the IR320ST-2, we need to charge the main supply capacitor to
* switch the device on. We keep DTR high throughout to do this.
* When RTS, TD and RD are high, they will also trickle-charge the
* cap. RTS is high for data transmission, and low for baud rate select.
* -- DGB
*/
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* The TOI3232 supports many speeds between 1200bps and 115000bps.
* We really only care about those supported by the IRDA spec, but
* 38400 seems to be implemented in many places */
qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
/* From the tekram driver. Not sure what a reasonable value is -- DGB */
qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
irda_qos_bits_to_value(qos);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int toim3232_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function toim3232change_speed (dev, state, speed)
*
* Set the speed for the TOIM3232 based dongle. Warning, this
* function must be called with a process context!
*
* Algorithm
* 1. keep DTR high but clear RTS to bring into baud programming mode
* 2. wait at least 7us to enter programming mode
* 3. send control word to set baud rate and timing
* 4. wait at least 1us
* 5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver)
* 6. should take effect immediately (although probably worth waiting)
*/
#define TOIM3232_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1)
static int toim3232_change_speed(struct sir_dev *dev, unsigned speed)
{
unsigned state = dev->fsm.substate;
unsigned delay = 0;
u8 byte;
static int ret = 0;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
switch(state) {
case SIRDEV_STATE_DONGLE_SPEED:
/* Figure out what we are going to send as a control byte */
switch (speed) {
case 2400:
byte = TOIM3232_PW|TOIM3232_2400;
break;
default:
speed = 9600;
ret = -EINVAL;
/* fall thru */
case 9600:
byte = TOIM3232_PW|TOIM3232_9600;
break;
case 19200:
byte = TOIM3232_PW|TOIM3232_19200;
break;
case 38400:
byte = TOIM3232_PW|TOIM3232_38400;
break;
case 57600:
byte = TOIM3232_PW|TOIM3232_57600;
break;
case 115200:
byte = TOIM3232_115200;
break;
}
/* Set DTR, Clear RTS: Go into baud programming mode */
sirdev_set_dtr_rts(dev, TRUE, FALSE);
/* Wait at least 7us */
udelay(14);
/* Write control byte */
sirdev_raw_write(dev, &byte, 1);
dev->speed = speed;
state = TOIM3232_STATE_WAIT_SPEED;
delay = toim3232delay;
break;
case TOIM3232_STATE_WAIT_SPEED:
/* Have transmitted control byte * Wait for 'at least 1us' */
udelay(14);
/* Set DTR, Set RTS: Go into normal data mode */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Wait (TODO: check this is needed) */
udelay(50);
break;
default:
printk(KERN_ERR "%s - undefined state %d\n", __FUNCTION__, state);
ret = -EINVAL;
break;
}
dev->fsm.substate = state;
return (delay > 0) ? delay : ret;
}
/*
* Function toim3232reset (driver)
*
* This function resets the toim3232 dongle. Warning, this function
* must be called with a process context!!
*
* What we should do is:
* 0. Pull RESET high
* 1. Wait for at least 7us
* 2. Pull RESET low
* 3. Wait for at least 7us
* 4. Pull BR/~D high
* 5. Wait for at least 7us
* 6. Send control byte to set baud rate
* 7. Wait at least 1us after stop bit
* 8. Pull BR/~D low
* 9. Should then be in data mode
*
* Because the IR320ST-2 doesn't have the RESET line connected for some reason,
* we'll have to do something else.
*
* The default speed after a RESET is 9600, so lets try just bringing it up in
* data mode after switching it off, waiting for the supply capacitor to
* discharge, and then switch it back on. This isn't actually pulling RESET
* high, but it seems to have the same effect.
*
* This behaviour will probably work on dongles that have the RESET line connected,
* but if not, add a flag for the IR320ST-2, and implment the above-listed proper
* behaviour.
*
* RTS is inverted and then fed to BR/~D, so to put it in programming mode, we
* need to have pull RTS low
*/
static int toim3232_reset(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
/* Switch off both DTR and RTS to switch off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
/* Should sleep a while. This might be evil doing it this way.*/
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(50));
/* Set DTR, Set RTS (data mode) */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Wait at least 10 ms for power to stabilize again */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(10));
/* Speed should now be 9600 */
dev->speed = 9600;
return 0;
}
MODULE_AUTHOR("David Basden <davidb-linux@rcpt.to>");
MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */
module_init(toim3232_sir_init);
module_exit(toim3232_sir_cleanup);

Some files were not shown because too many files have changed in this diff Show More