Commit 5e127e55 authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by Jeff Garzik

IrDA update 1/3:

	        <Following patch from Martin Diehl>
	o [CRITICA] Do all serial driver config change in process context
	o [CORRECT] Safe registration of dongle drivers
	o [FEATURE] Rework infrastructure of SIR drivers
	o [CORRECT] Port irtty driver to new SIR infrastructure
	o [CORRECT] Port esi/actisys/tekram driver to new SIR infrastructure
		<Note : there is still some more work to do around SIR drivers,
		 such as porting other drivers to the new infrastructure, but
		 this is functional and tested, and old irtty is broken>
parent 56c32f41
......@@ -9,7 +9,7 @@ config IRTTY_SIR
depends on IRDA
help
Say Y here if you want to build support for the IrTTY line
discipline. If you want to compile it as a module (irtty.o), say M
discipline. If you want to compile it as a module (irtty-sir.o), say M
here and read <file:Documentation/modules.txt>. IrTTY makes it
possible to use Linux's own serial driver for all IrDA ports that
are 16550 compatible. Most IrDA chips are 16550 compatible so you
......@@ -18,6 +18,69 @@ config IRTTY_SIR
If unsure, say Y.
comment "Dongle support"
config DONGLE
bool "Serial dongle support"
help
Say Y here if you have an infrared device that connects to your
computer's serial port. These devices are called dongles. Then say Y
or M to the driver for your particular dongle below.
Note that the answer to this question won't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about serial dongles.
config ESI_DONGLE
tristate "ESI JetEye PC dongle"
depends on DONGLE && IRDA
help
Say Y here if you want to build support for the Extended Systems
JetEye PC dongle. If you want to compile it as a module, say M here
and read <file:Documentation/modules.txt>. The ESI dongle attaches
to the normal 9-pin serial port connector, and can currently only be
used by IrTTY. To activate support for ESI dongles you will have to
start irattach like this: "irattach -d esi".
config ACTISYS_DONGLE
tristate "ACTiSYS IR-220L and IR220L+ dongle"
depends on DONGLE && IRDA
help
Say Y here if you want to build support for the ACTiSYS IR-220L and
IR220L+ dongles. If you want to compile it as a module, say M here
and read <file:Documentation/modules.txt>. The ACTiSYS dongles
attaches to the normal 9-pin serial port connector, and can
currently only be used by IrTTY. To activate support for ACTiSYS
dongles you will have to start irattach like this:
"irattach -d actisys" or "irattach -d actisys+".
config TEKRAM_DONGLE
tristate "Tekram IrMate 210B dongle"
depends on DONGLE && IRDA
help
Say Y here if you want to build support for the Tekram IrMate 210B
dongle. If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. The Tekram dongle attaches to the
normal 9-pin serial port connector, and can currently only be used
by IrTTY. To activate support for Tekram dongles you will have to
start irattach like this: "irattach -d tekram".
comment "Old SIR device drivers"
config IRTTY_OLD
tristate "Old IrTTY (broken)"
depends on IRDA
help
Say Y here if you want to build support for the IrTTY line
discipline. If you want to compile it as a module (irtty.o), say M
here and read <file:Documentation/modules.txt>. IrTTY makes it
possible to use Linux's own serial driver for all IrDA ports that
are 16550 compatible. Most IrDA chips are 16550 compatible so you
should probably say Y to this option. Using IrTTY will however
limit the speed of the connection to 115200 bps (IrDA SIR mode).
If unsure, say N.
config IRPORT_SIR
tristate "IrPORT (IrDA serial driver)"
depends on IRDA
......@@ -35,10 +98,10 @@ config IRPORT_SIR
If unsure, say Y.
comment "Dongle support"
comment "Old Serial dongle support"
config DONGLE
bool "Serial dongle support"
config DONGLE_OLD
bool "Old Serial dongle support"
help
Say Y here if you have an infrared device that connects to your
computer's serial port. These devices are called dongles. Then say Y
......@@ -48,9 +111,9 @@ config DONGLE
kernel: saying N will just cause the configurator to skip all
the questions about serial dongles.
config ESI_DONGLE
config ESI_DONGLE_OLD
tristate "ESI JetEye PC dongle"
depends on DONGLE && IRDA
depends on DONGLE_OLD && IRDA
help
Say Y here if you want to build support for the Extended Systems
JetEye PC dongle. If you want to compile it as a module, say M here
......@@ -59,9 +122,9 @@ config ESI_DONGLE
used by IrTTY. To activate support for ESI dongles you will have to
start irattach like this: "irattach -d esi".
config ACTISYS_DONGLE
config ACTISYS_DONGLE_OLD
tristate "ACTiSYS IR-220L and IR220L+ dongle"
depends on DONGLE && IRDA
depends on DONGLE_OLD && IRDA
help
Say Y here if you want to build support for the ACTiSYS IR-220L and
IR220L+ dongles. If you want to compile it as a module, say M here
......@@ -71,9 +134,9 @@ config ACTISYS_DONGLE
dongles you will have to start irattach like this:
"irattach -d actisys" or "irattach -d actisys+".
config TEKRAM_DONGLE
config TEKRAM_DONGLE_OLD
tristate "Tekram IrMate 210B dongle"
depends on DONGLE && IRDA
depends on DONGLE_OLD && IRDA
help
Say Y here if you want to build support for the Tekram IrMate 210B
dongle. If you want to compile it as a module, say M here and read
......@@ -84,7 +147,7 @@ config TEKRAM_DONGLE
config GIRBIL_DONGLE
tristate "Greenwich GIrBIL dongle"
depends on DONGLE && IRDA
depends on DONGLE_OLD && IRDA
help
Say Y here if you want to build support for the Greenwich GIrBIL
dongle. If you want to compile it as a module, say M here and read
......@@ -95,7 +158,7 @@ config GIRBIL_DONGLE
config LITELINK_DONGLE
tristate "Parallax LiteLink dongle"
depends on DONGLE && IRDA
depends on DONGLE_OLD && IRDA
help
Say Y here if you want to build support for the Parallax Litelink
dongle. If you want to compile it as a module, say M here and read
......@@ -106,7 +169,7 @@ config LITELINK_DONGLE
config MCP2120_DONGLE
tristate "Microchip MCP2120"
depends on DONGLE && IRDA
depends on DONGLE_OLD && IRDA
help
Say Y here if you want to build support for the Microchip MCP2120
dongle. If you want to compile it as a module, say M here and read
......@@ -120,7 +183,7 @@ config MCP2120_DONGLE
config OLD_BELKIN_DONGLE
tristate "Old Belkin dongle"
depends on DONGLE && IRDA
depends on DONGLE_OLD && IRDA
help
Say Y here if you want to build support for the Adaptec Airport 1000
and 2000 dongles. If you want to compile it as a module, say M here
......@@ -130,11 +193,11 @@ config OLD_BELKIN_DONGLE
config EP7211_IR
tristate "EP7211 I/R support"
depends on DONGLE && ARCH_EP7211 && IRDA
depends on DONGLE_OLD && ARCH_EP7211 && IRDA
config ACT200L_DONGLE
tristate "ACTiSYS IR-200L dongle (EXPERIMENTAL)"
depends on DONGLE && EXPERIMENTAL && IRDA
depends on DONGLE_OLD && EXPERIMENTAL && IRDA
help
Say Y here if you want to build support for the ACTiSYS IR-200L
dongle. If you want to compile it as a module, say M here and read
......@@ -145,7 +208,7 @@ config ACT200L_DONGLE
config MA600_DONGLE
tristate "Mobile Action MA600 dongle (EXPERIMENTAL)"
depends on DONGLE && EXPERIMENTAL && IRDA
depends on DONGLE_OLD && EXPERIMENTAL && IRDA
---help---
Say Y here if you want to build support for the Mobile Action MA600
dongle. If you want to compile it as a module, say M here and read
......
......@@ -5,10 +5,12 @@
# Rewritten to use lists instead of if-statements.
#
export-objs = irport.o
export-objs = irport.o sir_core.o
obj-$(CONFIG_IRTTY_SIR) += irtty.o
# Old SIR drivers (irtty is broken)
obj-$(CONFIG_IRTTY_OLD) += irtty.o
obj-$(CONFIG_IRPORT_SIR) += irport.o
# FIR drivers
obj-$(CONFIG_USB_IRDA) += irda-usb.o
obj-$(CONFIG_NSC_FIR) += nsc-ircc.o
obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o
......@@ -18,9 +20,10 @@ obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o
obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o
obj-$(CONFIG_ALI_FIR) += ali-ircc.o
obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o
obj-$(CONFIG_ESI_DONGLE) += esi.o
obj-$(CONFIG_TEKRAM_DONGLE) += tekram.o
obj-$(CONFIG_ACTISYS_DONGLE) += actisys.o
# Old dongle drivers for old SIR drivers
obj-$(CONFIG_ESI_OLD) += esi.o
obj-$(CONFIG_TEKRAM_OLD) += tekram.o
obj-$(CONFIG_ACTISYS_OLD) += actisys.o
obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o
obj-$(CONFIG_LITELINK_DONGLE) += litelink.o
obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o
......@@ -28,5 +31,14 @@ obj-$(CONFIG_EP7211_IR) += ep7211_ir.o
obj-$(CONFIG_MCP2120_DONGLE) += mcp2120.o
obj-$(CONFIG_ACT200L_DONGLE) += act200l.o
obj-$(CONFIG_MA600_DONGLE) += ma600.o
# New SIR drivers
obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o
# New dongles drivers for new SIR drivers
obj-$(CONFIG_ESI_DONGLE) += esi-sir.o
obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o
obj-$(CONFIG_ACTISYS_DONGLE) += actisys-sir.o
# The SIR helper module
sir-dev-objs := sir_core.o sir_dev.o sir_dongle.o sir_kthread.o
include $(TOPDIR)/Rules.make
/*********************************************************************
*
* Filename: actisys.c
* Version: 1.1
* Description: Implementation for the ACTiSYS IR-220L and IR-220L+
* dongles
* Status: Beta.
* Authors: Dag Brattli <dagb@cs.uit.no> (initially)
* Jean Tourrilhes <jt@hpl.hp.com> (new version)
* Martin Diehl <mad@mdiehl.de> (new version for sir_dev)
* Created at: Wed Oct 21 20:02:35 1998
* Modified at: Sun Oct 27 22:02:13 2002
* Modified by: Martin Diehl <mad@mdiehl.de>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
* Copyright (c) 1999 Jean Tourrilhes
* Copyright (c) 2002 Martin Diehl
*
* 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.
*
********************************************************************/
/*
* Changelog
*
* 0.8 -> 0.9999 - Jean
* o New initialisation procedure : much safer and correct
* o New procedure the change speed : much faster and simpler
* o Other cleanups & comments
* Thanks to Lichen Wang @ Actisys for his excellent help...
*
* 1.0 -> 1.1 - Martin Diehl
* modified for new sir infrastructure
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
/*
* Define the timing of the pulses we send to the dongle (to reset it, and
* to toggle speeds). Basically, the limit here is the propagation speed of
* the signals through the serial port, the dongle being much faster. Any
* serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can
* go through cleanly . If you are on the wild side, you can try to lower
* this value (Actisys recommended me 2 us, and 0 us work for me on a P233!)
*/
#define MIN_DELAY 10 /* 10 us to be on the conservative side */
static int actisys_open(struct sir_dev *);
static int actisys_close(struct sir_dev *);
static int actisys_change_speed(struct sir_dev *, unsigned);
static int actisys_reset(struct sir_dev *);
/* These are the baudrates supported, in the order available */
/* Note : the 220L doesn't support 38400, but we will fix that below */
static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
#define MAX_SPEEDS (sizeof(baud_rates)/sizeof(baud_rates[0]))
static struct dongle_driver act220l = {
.owner = THIS_MODULE,
.driver_name = "Actisys ACT-220L",
.type = IRDA_ACTISYS_DONGLE,
.open = actisys_open,
.close = actisys_close,
.reset = actisys_reset,
.set_speed = actisys_change_speed,
};
static struct dongle_driver act220l_plus = {
.owner = THIS_MODULE,
.driver_name = "Actisys ACT-220L+",
.type = IRDA_ACTISYS_PLUS_DONGLE,
.open = actisys_open,
.close = actisys_close,
.reset = actisys_reset,
.set_speed = actisys_change_speed,
};
int __init actisys_sir_init(void)
{
int ret;
/* First, register an Actisys 220L dongle */
ret = irda_register_dongle(&act220l);
if (ret < 0)
return ret;
/* Now, register an Actisys 220L+ dongle */
ret = irda_register_dongle(&act220l_plus);
if (ret < 0) {
irda_unregister_dongle(&act220l);
return ret;
}
return 0;
}
void __exit actisys_sir_cleanup(void)
{
/* We have to remove both dongles */
irda_unregister_dongle(&act220l_plus);
irda_unregister_dongle(&act220l);
}
static int actisys_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
dev->set_dtr_rts(dev, TRUE, TRUE);
/* Set the speeds we can accept */
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
/* Remove support for 38400 if this is not a 220L+ dongle */
if (dev->dongle_drv->type == IRDA_ACTISYS_DONGLE)
qos->baud_rate.bits &= ~IR_38400;
qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
irda_qos_bits_to_value(qos);
return 0;
}
static int actisys_close(struct sir_dev *dev)
{
/* Power off the dongle */
dev->set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function actisys_change_speed (task)
*
* Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles.
* To cycle through the available baud rates, pulse RTS low for a few us.
*
* First, we reset the dongle to always start from a known state.
* Then, we cycle through the speeds by pulsing RTS low and then up.
* The dongle allow us to pulse quite fast, se we can set speed in one go,
* which is must faster ( < 100 us) and less complex than what is found
* in some other dongle drivers...
* Note that even if the new speed is the same as the current speed,
* we reassert the speed. This make sure that things are all right,
* and it's fast anyway...
* By the way, this function will work for both type of dongles,
* because the additional speed is at the end of the sequence...
*/
static int actisys_change_speed(struct sir_dev *dev, unsigned speed)
{
int ret = 0;
int i = 0;
IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __FUNCTION__,
speed, dev->speed);
/* dongle was already resetted from irda_request state machine,
* we are in known state (dongle default)
*/
/*
* Now, we can set the speed requested. Send RTS pulses until we
* reach the target speed
*/
for (i=0; i<MAX_SPEEDS; i++) {
if (speed == baud_rates[i]) {
dev->speed = baud_rates[i];
break;
}
/* Set RTS low for 10 us */
dev->set_dtr_rts(dev, TRUE, FALSE);
udelay(MIN_DELAY);
/* Set RTS high for 10 us */
dev->set_dtr_rts(dev, TRUE, TRUE);
udelay(MIN_DELAY);
}
/* Check if life is sweet... */
if (i >= MAX_SPEEDS)
ret = -1; /* This should not happen */
/* Basta lavoro, on se casse d'ici... */
return ret;
}
/*
* Function actisys_reset (task)
*
* Reset the Actisys type dongle. Warning, this function must only be
* called with a process context!
*
* We need to do two things in this function :
* o first make sure that the dongle is in a state where it can operate
* o second put the dongle in a know state
*
* The dongle is powered of the RTS and DTR lines. In the dongle, there
* is a big capacitor to accomodate the current spikes. This capacitor
* takes a least 50 ms to be charged. In theory, the Bios set those lines
* up, so by the time we arrive here we should be set. It doesn't hurt
* to be on the conservative side, so we will wait...
* <Martin : move above comment to irda_config_fsm>
* Then, we set the speed to 9600 b/s to get in a known state (see in
* change_speed for details). It is needed because the IrDA stack
* has tried to set the speed immediately after our first return,
* so before we can be sure the dongle is up and running.
*/
static int actisys_reset(struct sir_dev *dev)
{
/* Reset the dongle : set DTR low for 10 us */
dev->set_dtr_rts(dev, FALSE, TRUE);
udelay(MIN_DELAY);
/* Go back to normal mode */
dev->set_dtr_rts(dev, TRUE, TRUE);
dev->speed = 9600; /* That's the default */
return 0;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>");
MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver");
MODULE_LICENSE("GPL");
module_init(actisys_sir_init);
module_exit(actisys_sir_cleanup);
/*********************************************************************
*
* Filename: esi.c
* Version: 1.6
* Description: Driver for the Extended Systems JetEye PC dongle
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Feb 21 18:54:38 1998
* Modified at: Sun Oct 27 22:01:04 2002
* Modified by: Martin Diehl <mad@mdiehl.de>
*
* Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>,
* Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
* Copyright (c) 2002 Martin Diehl, <mad@mdiehl.de>,
* 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.
*
* 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
*
********************************************************************/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
static int esi_open(struct sir_dev *);
static int esi_close(struct sir_dev *);
static int esi_change_speed(struct sir_dev *, unsigned);
static int esi_reset(struct sir_dev *);
static struct dongle_driver esi = {
.owner = THIS_MODULE,
.driver_name = "JetEye PC ESI-9680 PC",
.type = IRDA_ESI_DONGLE,
.open = esi_open,
.close = esi_close,
.reset = esi_reset,
.set_speed = esi_change_speed,
};
static int __init esi_sir_init(void)
{
return irda_register_dongle(&esi);
}
static void __exit esi_sir_cleanup(void)
{
irda_unregister_dongle(&esi);
}
static int esi_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
irda_qos_bits_to_value(qos);
/* shouldn't we do set_dtr_rts(FALSE, TRUE) here (power up at 9600)? */
return 0;
}
static int esi_close(struct sir_dev *dev)
{
/* Power off dongle */
dev->set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function esi_change_speed (task)
*
* Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle
*
*/
static int esi_change_speed(struct sir_dev *dev, unsigned speed)
{
int dtr, rts;
switch (speed) {
case 19200:
dtr = TRUE;
rts = FALSE;
break;
case 115200:
dtr = rts = TRUE;
break;
default:
speed = 9600;
/* fall through */
case 9600:
dtr = FALSE;
rts = TRUE;
break;
}
/* Change speed of dongle */
dev->set_dtr_rts(dev, dtr, rts);
dev->speed = speed;
/* do we need some delay for power stabilization? */
return 0;
}
/*
* Function esi_reset (task)
*
* Reset dongle;
*
*/
static int esi_reset(struct sir_dev *dev)
{
dev->set_dtr_rts(dev, FALSE, FALSE);
/* Hm, probably repower to 9600 and some delays? */
return 0;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
MODULE_LICENSE("GPL");
module_init(esi_sir_init);
module_exit(esi_sir_cleanup);
This diff is collapsed.
/*********************************************************************
*
* sir_tty.h: definitions for the irtty_sir client driver (former irtty)
*
* Copyright (c) 2002 Martin Diehl
*
* 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.
*
********************************************************************/
#ifndef IRTTYSIR_H
#define IRTTYSIR_H
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> // chipio_t
#define IRTTY_IOC_MAGIC 'e'
#define IRTTY_IOCTDONGLE _IO(IRTTY_IOC_MAGIC, 1)
#define IRTTY_IOCGET _IOR(IRTTY_IOC_MAGIC, 2, struct irtty_info)
#define IRTTY_IOC_MAXNR 2
struct sirtty_cb {
magic_t magic;
struct sir_dev *dev;
struct tty_struct *tty;
chipio_t io; /* IrDA controller information */
};
#endif
/*********************************************************************
*
* sir.h: include file for irda-sir device abstraction layer
*
* Copyright (c) 2002 Martin Diehl
*
* 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.
*
********************************************************************/
#ifndef IRDA_SIR_H
#define IRDA_SIR_H
#include <linux/netdevice.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> // iobuff_t
/* FIXME: unify irda_request with sir_fsm! */
struct irda_request {
struct list_head lh_request;
unsigned long pending;
void (*func)(void *);
void *data;
struct timer_list timer;
};
struct sir_fsm {
struct semaphore sem;
struct irda_request rq;
unsigned state, substate;
int param;
int result;
};
#define SIRDEV_STATE_WAIT_TX_COMPLETE 0x0100
/* substates for wait_tx_complete */
#define SIRDEV_STATE_WAIT_XMIT 0x0101
#define SIRDEV_STATE_WAIT_UNTIL_SENT 0x0102
#define SIRDEV_STATE_TX_DONE 0x0103
#define SIRDEV_STATE_DONGLE_OPEN 0x0300
/* 0x0301-0x03ff reserved for individual dongle substates */
#define SIRDEV_STATE_DONGLE_CLOSE 0x0400
/* 0x0401-0x04ff reserved for individual dongle substates */
#define SIRDEV_STATE_SET_DTR_RTS 0x0500
#define SIRDEV_STATE_SET_SPEED 0x0700
#define SIRDEV_STATE_DONGLE_CHECK 0x0800
#define SIRDEV_STATE_DONGLE_RESET 0x0900
/* 0x0901-0x09ff reserved for individual dongle substates */
#define SIRDEV_STATE_DONGLE_SPEED 0x0a00
/* 0x0a01-0x0aff reserved for individual dongle substates */
#define SIRDEV_STATE_PORT_SPEED 0x0b00
#define SIRDEV_STATE_DONE 0x0c00
#define SIRDEV_STATE_ERROR 0x0d00
#define SIRDEV_STATE_COMPLETE 0x0e00
#define SIRDEV_STATE_DEAD 0xffff
struct sir_dev;
struct dongle_driver {
struct module *owner;
const char *driver_name;
IRDA_DONGLE type;
int (*open)(struct sir_dev *dev);
int (*close)(struct sir_dev *dev);
int (*reset)(struct sir_dev *dev);
int (*set_speed)(struct sir_dev *dev, unsigned speed);
struct list_head dongle_list;
};
struct sir_driver {
struct module *owner;
const char *driver_name;
int qos_mtt_bits;
int (*chars_in_buffer)(struct sir_dev *dev);
void (*wait_until_sent)(struct sir_dev *dev);
int (*set_speed)(struct sir_dev *dev, unsigned speed);
int (*set_dtr_rts)(struct sir_dev *dev, int dtr, int rts);
int (*do_write)(struct sir_dev *dev, const unsigned char *ptr, size_t len);
int (*start_dev)(struct sir_dev *dev);
int (*stop_dev)(struct sir_dev *dev);
};
/* exported */
extern int irda_register_dongle(struct dongle_driver *new);
extern int irda_unregister_dongle(struct dongle_driver *drv);
extern struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name);
extern int sirdev_put_instance(struct sir_dev *self);
extern int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type);
extern void sirdev_write_complete(struct sir_dev *dev);
extern int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count);
/* not exported */
extern int sirdev_get_dongle(struct sir_dev *self, IRDA_DONGLE type);
extern int sirdev_put_dongle(struct sir_dev *self);
extern int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len);
extern int sirdev_raw_read(struct sir_dev *dev, char *buf, int len);
extern void sirdev_enable_rx(struct sir_dev *dev);
extern int sirdev_schedule_request(struct sir_dev *dev, int state, unsigned param);
extern int __init irda_thread_create(void);
extern void __exit irda_thread_join(void);
/* inline helpers */
static inline int sirdev_schedule_speed(struct sir_dev *dev, unsigned speed)
{
return sirdev_schedule_request(dev, SIRDEV_STATE_SET_SPEED, speed);
}
static inline int sirdev_schedule_dongle_open(struct sir_dev *dev, int dongle_id)
{
return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_OPEN, dongle_id);
}
static inline int sirdev_schedule_dongle_close(struct sir_dev *dev)
{
return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_CLOSE, 0);
}
static inline int sirdev_schedule_dtr_rts(struct sir_dev *dev, int dtr, int rts)
{
int dtrrts;
dtrrts = ((dtr) ? 0x02 : 0x00) | ((rts) ? 0x01 : 0x00);
return sirdev_schedule_request(dev, SIRDEV_STATE_SET_DTR_RTS, dtrrts);
}
#if 0
static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode)
{
return sirdev_schedule_request(dev, SIRDEV_STATE_SET_MODE, mode);
}
#endif
struct sir_dev {
struct net_device *netdev;
struct net_device_stats stats;
struct irlap_cb *irlap;
struct qos_info qos;
char hwname[32];
struct sir_fsm fsm;
atomic_t enable_rx;
spinlock_t tx_lock;
u32 new_speed;
u32 flags;
unsigned speed;
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
struct sk_buff *tx_skb;
const struct dongle_driver * dongle_drv;
const struct sir_driver * drv;
void *priv;
/* dongle callbacks to the SIR device */
int (*read)(struct sir_dev *, char *buf, int len);
int (*write)(struct sir_dev *, const char *buf, int len);
int (*set_dtr_rts)(struct sir_dev *, int dtr, int rts);
};
#endif /* IRDA_SIR_H */
/*********************************************************************
*
* sir_core.c: module core for irda-sir abstraction layer
*
* Copyright (c) 2002 Martin Diehl
*
* 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.
*
********************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
/***************************************************************************/
MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
MODULE_DESCRIPTION("IrDA SIR core");
MODULE_LICENSE("GPL");
/***************************************************************************/
EXPORT_SYMBOL(irda_register_dongle);
EXPORT_SYMBOL(irda_unregister_dongle);
EXPORT_SYMBOL(sirdev_get_instance);
EXPORT_SYMBOL(sirdev_put_instance);
EXPORT_SYMBOL(sirdev_set_dongle);
EXPORT_SYMBOL(sirdev_write_complete);
EXPORT_SYMBOL(sirdev_receive);
static int __init sir_core_init(void)
{
return irda_thread_create();
}
static void __exit sir_core_exit(void)
{
irda_thread_join();
}
module_init(sir_core_init);
module_exit(sir_core_exit);
This diff is collapsed.
/*********************************************************************
*
* sir_dongle.c: manager for serial dongle protocol drivers
*
* Copyright (c) 2002 Martin Diehl
*
* 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.
*
********************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/kmod.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
/**************************************************************************
*
* dongle registration and attachment
*
*/
static LIST_HEAD(dongle_list); /* list of registered dongle drivers */
static DECLARE_MUTEX(dongle_list_lock); /* protects the list */
int irda_register_dongle(struct dongle_driver *new)
{
struct list_head *entry;
struct dongle_driver *drv;
IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n",
__FUNCTION__, new->driver_name, new->type);
down(&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);
return -EEXIST;
}
}
list_add(&new->dongle_list, &dongle_list);
up(&dongle_list_lock);
return 0;
}
int irda_unregister_dongle(struct dongle_driver *drv)
{
down(&dongle_list_lock);
list_del(&drv->dongle_list);
up(&dongle_list_lock);
return 0;
}
int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
{
struct list_head *entry;
const struct dongle_driver *drv = NULL;
int err = -EINVAL;
#ifdef CONFIG_KMOD
char modname[30];
sprintf(modname, "irda-dongle-%d", type);
request_module(modname);
#endif
if (dev->dongle_drv != NULL)
return -EBUSY;
/* serialize access to the list of registered dongles */
down(&dongle_list_lock);
list_for_each(entry, &dongle_list) {
drv = list_entry(entry, struct dongle_driver, dongle_list);
if (drv->type == type)
break;
else
drv = NULL;
}
if (!drv) {
err = -ENODEV;
goto out_unlock; /* no such dongle */
}
/* handling of SMP races with dongle module removal - three cases:
* 1) dongle driver was already unregistered - then we haven't found the
* requested dongle above and are already out here
* 2) the module is already marked deleted but the driver is still
* registered - then the try_inc_mod_count() below will fail
* 3) the try_inc_mod_count() below succeeds before the module is marked
* deleted - then sys_delete_module() fails and prevents the removal
* because the module is in use.
*/
if (drv->owner && !try_inc_mod_count(drv->owner)) {
err = -ESTALE;
goto out_unlock; /* rmmod already pending */
}
/* Initialize dongle driver callbacks */
dev->read = sirdev_raw_read;
dev->write = sirdev_raw_write;
dev->set_dtr_rts = dev->drv->set_dtr_rts;
dev->dongle_drv = drv;
if (!drv->open || (err=drv->open(dev))!=0)
goto out_reject; /* failed to open driver */
up(&dongle_list_lock);
return 0;
out_reject:
dev->dongle_drv = NULL;
if (drv->owner)
__MOD_DEC_USE_COUNT(drv->owner);
out_unlock:
up(&dongle_list_lock);
return err;
}
int sirdev_put_dongle(struct sir_dev *dev)
{
const struct dongle_driver *drv = dev->dongle_drv;
if (drv) {
if (drv->close)
drv->close(dev); /* close this dongle instance */
dev->dongle_drv = NULL; /* unlink the dongle driver */
if (drv->owner)
__MOD_DEC_USE_COUNT(drv->owner);/* decrement driver's module refcount */
}
return 0;
}
This diff is collapsed.
/*********************************************************************
*
* Filename: tekram.c
* Version: 1.3
* Description: Implementation of the Tekram IrMate IR-210B dongle
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Wed Oct 21 20:02:35 1998
* Modified at: Sun Oct 27 22:02:38 2002
* Modified by: Martin Diehl <mad@mdiehl.de>
*
* 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.
*
********************************************************************/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
MODULE_PARM(tekram_delay, "i");
MODULE_PARM_DESC(tekram_delay, "tekram dongle write complete delay");
static int tekram_delay = 50; /* default is 50 ms */
static int tekram_open(struct sir_dev *);
static int tekram_close(struct sir_dev *);
static int tekram_change_speed(struct sir_dev *, unsigned);
static int tekram_reset(struct sir_dev *);
#define TEKRAM_115200 0x00
#define TEKRAM_57600 0x01
#define TEKRAM_38400 0x02
#define TEKRAM_19200 0x03
#define TEKRAM_9600 0x04
#define TEKRAM_PW 0x10 /* Pulse select bit */
static struct dongle_driver tekram = {
.owner = THIS_MODULE,
.driver_name = "Tekram IR-210B",
.type = IRDA_TEKRAM_DONGLE,
.open = tekram_open,
.close = tekram_close,
.reset = tekram_reset,
.set_speed = tekram_change_speed,
};
int __init tekram_sir_init(void)
{
if (tekram_delay < 1 || tekram_delay>500)
tekram_delay = 200;
return irda_register_dongle(&tekram);
}
void __exit tekram_sir_cleanup(void)
{
irda_unregister_dongle(&tekram);
}
#define TEKRAM_STATE_POWERED (SIRDEV_STATE_DONGLE_OPEN + 1)
static int tekram_open(struct sir_dev *dev)
{
unsigned delay = 0;
unsigned next_state = dev->fsm.substate;
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
switch(dev->fsm.substate) {
case SIRDEV_STATE_DONGLE_OPEN:
dev->set_dtr_rts(dev, TRUE, TRUE);
next_state = TEKRAM_STATE_POWERED;
delay = 50;
break;
case TEKRAM_STATE_POWERED:
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
irda_qos_bits_to_value(qos);
return 0;
default:
ERROR("%s - undefined state\n", __FUNCTION__);
return -EINVAL;
}
dev->fsm.substate = next_state;
return delay;
}
static int tekram_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
/* Power off dongle */
dev->set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function tekram_change_speed (dev, state, speed)
*
* Set the speed for the Tekram IRMate 210 type dongle. Warning, this
* function must be called with a process context!
*
* Algorithm
* 1. clear DTR
* 2. set RTS, and wait at least 7 us
* 3. send Control Byte to the IR-210 through TXD to set new baud rate
* wait until the stop bit of Control Byte is sent (for 9600 baud rate,
* it takes about 100 msec)
*
* [oops, why 100 msec? sending 1 byte (10 bits) takes 1.05 msec
* - is this probably to compensate for delays in tty layer?]
*
* 5. clear RTS (return to NORMAL Operation)
* 6. wait at least 50 us, new setting (baud rate, etc) takes effect here
* after
*/
#define TEKRAM_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1)
static int tekram_change_speed(struct sir_dev *dev, unsigned speed)
{
unsigned delay = 0;
unsigned next_state = dev->fsm.substate;
u8 byte;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
switch(dev->fsm.substate) {
case SIRDEV_STATE_DONGLE_SPEED:
switch (speed) {
default:
speed = 9600;
/* fall thru */
case 9600:
byte = TEKRAM_PW|TEKRAM_9600;
break;
case 19200:
byte = TEKRAM_PW|TEKRAM_19200;
break;
case 38400:
byte = TEKRAM_PW|TEKRAM_38400;
break;
case 57600:
byte = TEKRAM_PW|TEKRAM_57600;
break;
case 115200:
byte = TEKRAM_115200;
break;
}
/* Set DTR, Clear RTS */
dev->set_dtr_rts(dev, TRUE, FALSE);
/* Wait at least 7us */
udelay(14);
/* Write control byte */
dev->write(dev, &byte, 1);
dev->speed = speed;
next_state = TEKRAM_STATE_WAIT_SPEED;
delay = tekram_delay; /* default: 50 ms */
break;
case TEKRAM_STATE_WAIT_SPEED:
/* Set DTR, Set RTS */
dev->set_dtr_rts(dev, TRUE, TRUE);
udelay(50);
return 0;
default:
ERROR("%s - undefined state\n", __FUNCTION__);
return -EINVAL;
}
dev->fsm.substate = next_state;
return delay;
}
/*
* Function tekram_reset (driver)
*
* This function resets the tekram dongle. Warning, this function
* must be called with a process context!!
*
* Algorithm:
* 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 )
* 1. clear RTS
* 2. set DTR, and wait at least 1 ms
* 3. clear DTR to SPACE state, wait at least 50 us for further
* operation
*/
#define TEKRAM_STATE_WAIT_RESET (SIRDEV_STATE_DONGLE_RESET + 1)
static int tekram_reset(struct sir_dev *dev)
{
unsigned delay = 0;
unsigned next_state = dev->fsm.substate;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
switch(dev->fsm.substate) {
case SIRDEV_STATE_DONGLE_RESET:
/* Clear DTR, Set RTS */
dev->set_dtr_rts(dev, FALSE, TRUE);
next_state = TEKRAM_STATE_WAIT_RESET;
delay = 1; /* Should sleep 1 ms */
break;
case TEKRAM_STATE_WAIT_RESET:
/* Set DTR, Set RTS */
dev->set_dtr_rts(dev, TRUE, TRUE);
/* Wait at least 50 us */
udelay(75);
return 0;
default:
ERROR("%s - undefined state\n", __FUNCTION__);
return -EINVAL;
}
dev->fsm.substate = next_state;
return delay;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
MODULE_LICENSE("GPL");
module_init(tekram_sir_init);
module_exit(tekram_sir_cleanup);
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