Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

405
drivers/net/irda/Kconfig Normal file
View file

@ -0,0 +1,405 @@
menu "Infrared-port device drivers"
depends on IRDA!=n
comment "SIR device drivers"
config IRTTY_SIR
tristate "IrTTY (uses Linux serial driver)"
depends on IRDA && TTY
help
Say Y here if you want to build support for the IrTTY line
discipline. To compile it as a module, choose M here: the module
will be called irtty-sir. 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 Y.
config BFIN_SIR
tristate "Blackfin SIR on UART"
depends on BLACKFIN && IRDA
default n
help
Say Y here if your want to enable SIR function on Blackfin UART
devices.
To activate this driver you can start irattach like:
"irattach irda0 -s"
Saying M, it will be built as a module named bfin_sir.
Note that you need to turn off one of the serial drivers for SIR
to use that UART.
config BFIN_SIR0
bool "Blackfin SIR on UART0"
depends on BFIN_SIR && !SERIAL_BFIN_UART0
config BFIN_SIR1
bool "Blackfin SIR on UART1"
depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561)
config BFIN_SIR2
bool "Blackfin SIR on UART2"
depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539)
config BFIN_SIR3
bool "Blackfin SIR on UART3"
depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x)
choice
prompt "SIR Mode"
depends on BFIN_SIR
default SIR_BFIN_DMA
config SIR_BFIN_DMA
bool "DMA mode"
depends on !DMA_UNCACHED_NONE
config SIR_BFIN_PIO
bool "PIO mode"
endchoice
config SH_SIR
tristate "SuperH SIR on UART"
depends on IRDA && SUPERH && \
(CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \
CPU_SUBTYPE_SH7724)
default n
help
Say Y here if your want to enable SIR function on SuperH UART
devices.
comment "Dongle support"
config DONGLE
bool "Serial dongle support"
depends on IRTTY_SIR
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 IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Extended Systems
JetEye PC dongle. To compile it as a module, choose M here. 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 IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the ACTiSYS IR-220L and
IR220L+ dongles. To compile it as a module, choose M here. 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 IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Tekram IrMate 210B
dongle. To compile it as a module, choose M here. 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".
config TOIM3232_DONGLE
tristate "TOIM3232 IrDa dongle"
depends on IRTTY_SIR && 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 IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Parallax Litelink
dongle. To compile it as a module, choose M here. The Parallax
dongle attaches to the normal 9-pin serial port connector, and can
currently only be used by IrTTY. To activate support for Parallax
dongles you will have to start irattach like this:
"irattach -d litelink".
config MA600_DONGLE
tristate "Mobile Action MA600 dongle"
depends on IRTTY_SIR && DONGLE && IRDA
help
Say Y here if you want to build support for the Mobile Action MA600
dongle. To compile it as a module, choose M here. The MA600 dongle
attaches to the normal 9-pin serial port connector, and can
currently only be used by IrTTY. The driver should also support
the MA620 USB version of the dongle, if the integrated USB-to-RS232
converter is supported by usbserial. To activate support for
MA600 dongle you will have to start irattach like this:
"irattach -d ma600".
config GIRBIL_DONGLE
tristate "Greenwich GIrBIL dongle"
depends on IRTTY_SIR && DONGLE && 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, choose M here.
The Greenwich dongle attaches to the normal 9-pin serial port
connector, and can currently only be used by IrTTY. To activate
support for Greenwich dongles you will have to start irattach
like this: "irattach -d girbil".
config MCP2120_DONGLE
tristate "Microchip MCP2120"
depends on IRTTY_SIR && DONGLE && 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, choose M here.
The MCP2120 dongle attaches to the normal 9-pin serial port
connector, and can currently only be used by IrTTY. To activate
support for MCP2120 dongles you will have to start irattach
like this: "irattach -d mcp2120".
You must build this dongle yourself. For more information see:
<http://www.eyetap.org/~tangf/irda_sir_linux.html>
config OLD_BELKIN_DONGLE
tristate "Old Belkin dongle"
depends on IRTTY_SIR && DONGLE && 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, choose
M here. Some information is contained in the comments
at the top of <file:drivers/net/irda/old_belkin-sir.c>.
config ACT200L_DONGLE
tristate "ACTiSYS IR-200L dongle"
depends on IRTTY_SIR && DONGLE && 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, choose M here.
The ACTiSYS IR-200L dongle attaches to the normal 9-pin serial
port connector, and can currently only be used by IrTTY.
To activate support for ACTiSYS IR-200L dongle you will have to
start irattach like this: "irattach -d act200l".
config KINGSUN_DONGLE
tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
depends on IRDA && USB
help
Say Y or M here if you want to build support for the KingSun/DonShine
DS-620 IrDA-USB bridge device driver.
This USB bridge does not conform to the IrDA-USB device class
specification, and therefore needs its own specific driver. This
dongle supports SIR speed only (9600 bps).
To compile it as a module, choose M here: the module will be called
kingsun-sir.
config KSDAZZLE_DONGLE
tristate "KingSun Dazzle IrDA-USB dongle"
depends on IRDA && USB
help
Say Y or M here if you want to build support for the KingSun Dazzle
IrDA-USB bridge device driver.
This USB bridge does not conform to the IrDA-USB device class
specification, and therefore needs its own specific driver. This
dongle supports SIR speeds only (9600 through 115200 bps).
To compile it as a module, choose M here: the module will be called
ksdazzle-sir.
config KS959_DONGLE
tristate "KingSun KS-959 IrDA-USB dongle"
depends on IRDA && USB
help
Say Y or M here if you want to build support for the KingSun KS-959
IrDA-USB bridge device driver.
This USB bridge does not conform to the IrDA-USB device class
specification, and therefore needs its own specific driver. This
dongle supports SIR speeds only (9600 through 57600 bps).
To compile it as a module, choose M here: the module will be called
ks959-sir.
comment "FIR device drivers"
config USB_IRDA
tristate "IrDA USB dongles"
depends on IRDA && USB
select FW_LOADER
---help---
Say Y here if you want to build support for the USB IrDA FIR Dongle
device driver. To compile it as a module, choose M here: the module
will be called irda-usb. IrDA-USB support the various IrDA USB
dongles available and most of their peculiarities. Those dongles
plug in the USB port of your computer, are plug and play, and
support SIR and FIR (4Mbps) speeds. On the other hand, those
dongles tend to be less efficient than a FIR chipset.
Please note that the driver is still experimental. And of course,
you will need both USB and IrDA support in your kernel...
config SIGMATEL_FIR
tristate "SigmaTel STIr4200 bridge"
depends on IRDA && USB
select CRC32
---help---
Say Y here if you want to build support for the SigmaTel STIr4200
USB IrDA FIR bridge device driver.
USB bridge based on the SigmaTel STIr4200 don't conform to the
IrDA-USB device class specification, and therefore need their
own specific driver. Those dongles support SIR and FIR (4Mbps)
speeds.
To compile it as a module, choose M here: the module will be called
stir4200.
config NSC_FIR
tristate "NSC PC87108/PC87338"
depends on IRDA && ISA_DMA_API
help
Say Y here if you want to build support for the NSC PC87108 and
PC87338 IrDA chipsets. This driver supports SIR,
MIR and FIR (4Mbps) speeds.
To compile it as a module, choose M here: the module will be called
nsc-ircc.
config WINBOND_FIR
tristate "Winbond W83977AF (IR)"
depends on IRDA && ISA_DMA_API
help
Say Y here if you want to build IrDA support for the Winbond
W83977AF super-io chipset. This driver should be used for the IrDA
chipset in the Corel NetWinder. The driver supports SIR, MIR and
FIR (4Mbps) speeds.
To compile it as a module, choose M here: the module will be called
w83977af_ir.
config TOSHIBA_FIR
tristate "Toshiba Type-O IR Port"
depends on IRDA && PCI && !64BIT && VIRT_TO_BUS
help
Say Y here if you want to build support for the Toshiba Type-O IR
and Donau oboe chipsets. These chipsets are used by the Toshiba
Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops.
To compile it as a module, choose M here: the module will be called
donauboe.
config AU1000_FIR
tristate "Alchemy IrDA SIR/FIR"
depends on IRDA && MIPS_ALCHEMY
help
Say Y/M here to build support the IrDA peripheral on the
Alchemy Au1000 and Au1100 SoCs.
Say M to build a module; it will be called au1k_ir.ko
config SMC_IRCC_FIR
tristate "SMSC IrCC"
depends on IRDA && ISA_DMA_API
help
Say Y here if you want to build support for the SMC Infrared
Communications Controller. It is used in a wide variety of
laptops (Fujitsu, Sony, Compaq and some Toshiba).
To compile it as a module, choose M here: the module will be called
smsc-ircc2.o.
config ALI_FIR
tristate "ALi M5123 FIR"
depends on IRDA && ISA_DMA_API
help
Say Y here if you want to build support for the ALi M5123 FIR
Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C,
M1535, M1535D, M1535+, M1535D South Bridge. This driver supports
SIR, MIR and FIR (4Mbps) speeds.
To compile it as a module, choose M here: the module will be called
ali-ircc.
config VLSI_FIR
tristate "VLSI 82C147 SIR/MIR/FIR"
depends on IRDA && PCI
help
Say Y here if you want to build support for the VLSI 82C147
PCI-IrDA Controller. This controller is used by the HP OmniBook 800
and 5500 notebooks. The driver provides support for SIR, MIR and
FIR (4Mbps) speeds.
To compile it as a module, choose M here: the module will be called
vlsi_ir.
config SA1100_FIR
tristate "SA1100 Internal IR"
depends on ARCH_SA1100 && IRDA && DMA_SA11X0
config VIA_FIR
tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
depends on IRDA && ISA_DMA_API
help
Say Y here if you want to build support for the VIA VT8231
and VIA VT1211 IrDA controllers, found on the motherboards using
those VIA chipsets. To use this controller, you will need
to plug a specific 5 pins FIR IrDA dongle in the specific
motherboard connector. The driver provides support for SIR, MIR
and FIR (4Mbps) speeds.
You will need to specify the 'dongle_id' module parameter to
indicate the FIR dongle attached to the controller.
To compile it as a module, choose M here: the module will be called
via-ircc.
config PXA_FICP
tristate "Intel PXA2xx Internal FICP"
depends on ARCH_PXA && IRDA
help
Say Y or M here if you want to build support for the PXA2xx
built-in IRDA interface which can support both SIR and FIR.
This driver relies on platform specific helper routines so
available capabilities may vary from one PXA2xx target to
another.
config MCS_FIR
tristate "MosChip MCS7780 IrDA-USB dongle"
depends on IRDA && USB
select CRC32
help
Say Y or M here if you want to build support for the MosChip
MCS7780 IrDA-USB bridge device driver.
USB bridge based on the MosChip MCS7780 don't conform to the
IrDA-USB device class specification, and therefore need their
own specific driver. Those dongles support SIR and FIR (4Mbps)
speeds.
To compile it as a module, choose M here: the module will be called
mcs7780.
config SH_IRDA
tristate "SuperH IrDA driver"
depends on IRDA
depends on (ARCH_SHMOBILE || COMPILE_TEST) && HAS_IOMEM
help
Say Y here if your want to enable SuperH IrDA devices.
endmenu

43
drivers/net/irda/Makefile Normal file
View file

@ -0,0 +1,43 @@
#
# Makefile for the Linux IrDA infrared port device drivers.
#
# 9 Aug 2000, Christoph Hellwig <hch@infradead.org>
# Rewritten to use lists instead of if-statements.
#
# FIR drivers
obj-$(CONFIG_USB_IRDA) += irda-usb.o
obj-$(CONFIG_SIGMATEL_FIR) += stir4200.o
obj-$(CONFIG_NSC_FIR) += nsc-ircc.o
obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o
obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o
obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o
obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o
obj-$(CONFIG_ALI_FIR) += ali-ircc.o
obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o
obj-$(CONFIG_VIA_FIR) += via-ircc.o
obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o
obj-$(CONFIG_MCS_FIR) += mcs7780.o
obj-$(CONFIG_AU1000_FIR) += au1k_ir.o
obj-$(CONFIG_SH_IRDA) += sh_irda.o
# SIR drivers
obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o
obj-$(CONFIG_BFIN_SIR) += bfin_sir.o
obj-$(CONFIG_SH_SIR) += sh_sir.o
# dongle drivers for SIR drivers
obj-$(CONFIG_ESI_DONGLE) += esi-sir.o
obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o
obj-$(CONFIG_ACTISYS_DONGLE) += actisys-sir.o
obj-$(CONFIG_LITELINK_DONGLE) += litelink-sir.o
obj-$(CONFIG_GIRBIL_DONGLE) += girbil-sir.o
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
obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o
obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o
# The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o

View file

@ -0,0 +1,257 @@
/*********************************************************************
*
* Filename: act200l.c
* Version: 0.8
* Description: Implementation for the ACTiSYS ACT-IR200L dongle
* Status: Experimental.
* Author: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
* Created at: Fri Aug 3 17:35:42 2001
* Modified at: Fri Aug 17 10:22:40 2001
* Modified by: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
*
* Copyright (c) 2001 SHIMIZU Takuya, 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.
*
********************************************************************/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
static int act200l_reset(struct sir_dev *dev);
static int act200l_open(struct sir_dev *dev);
static int act200l_close(struct sir_dev *dev);
static int act200l_change_speed(struct sir_dev *dev, unsigned speed);
/* Regsiter 0: Control register #1 */
#define ACT200L_REG0 0x00
#define ACT200L_TXEN 0x01 /* Enable transmitter */
#define ACT200L_RXEN 0x02 /* Enable receiver */
/* Register 1: Control register #2 */
#define ACT200L_REG1 0x10
#define ACT200L_LODB 0x01 /* Load new baud rate count value */
#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */
/* Register 4: Output Power register */
#define ACT200L_REG4 0x40
#define ACT200L_OP0 0x01 /* Enable LED1C output */
#define ACT200L_OP1 0x02 /* Enable LED2C output */
#define ACT200L_BLKR 0x04
/* Register 5: Receive Mode register */
#define ACT200L_REG5 0x50
#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */
/* Register 6: Receive Sensitivity register #1 */
#define ACT200L_REG6 0x60
#define ACT200L_RS0 0x01 /* receive threshold bit 0 */
#define ACT200L_RS1 0x02 /* receive threshold bit 1 */
/* Register 7: Receive Sensitivity register #2 */
#define ACT200L_REG7 0x70
#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */
/* Register 8,9: Baud Rate Dvider register #1,#2 */
#define ACT200L_REG8 0x80
#define ACT200L_REG9 0x90
#define ACT200L_2400 0x5f
#define ACT200L_9600 0x17
#define ACT200L_19200 0x0b
#define ACT200L_38400 0x05
#define ACT200L_57600 0x03
#define ACT200L_115200 0x01
/* Register 13: Control register #3 */
#define ACT200L_REG13 0xd0
#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */
/* Register 15: Status register */
#define ACT200L_REG15 0xf0
/* Register 21: Control register #4 */
#define ACT200L_REG21 0x50
#define ACT200L_EXCK 0x02 /* Disable clock output driver */
#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */
static struct dongle_driver act200l = {
.owner = THIS_MODULE,
.driver_name = "ACTiSYS ACT-IR200L",
.type = IRDA_ACT200L_DONGLE,
.open = act200l_open,
.close = act200l_close,
.reset = act200l_reset,
.set_speed = act200l_change_speed,
};
static int __init act200l_sir_init(void)
{
return irda_register_dongle(&act200l);
}
static void __exit act200l_sir_cleanup(void)
{
irda_unregister_dongle(&act200l);
}
static int act200l_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __func__ );
/* Power on the dongle */
sirdev_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;
qos->min_turn_time.bits = 0x03;
irda_qos_bits_to_value(qos);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int act200l_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__ );
/* Power off the dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function act200l_change_speed (dev, speed)
*
* Set the speed for the ACTiSYS ACT-IR200L type dongle.
*
*/
static int act200l_change_speed(struct sir_dev *dev, unsigned speed)
{
u8 control[3];
int ret = 0;
IRDA_DEBUG(2, "%s()\n", __func__ );
/* Clear DTR and set RTS to enter command mode */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
switch (speed) {
default:
ret = -EINVAL;
/* fall through */
case 9600:
control[0] = ACT200L_REG8 | (ACT200L_9600 & 0x0f);
control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f);
break;
case 19200:
control[0] = ACT200L_REG8 | (ACT200L_19200 & 0x0f);
control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f);
break;
case 38400:
control[0] = ACT200L_REG8 | (ACT200L_38400 & 0x0f);
control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f);
break;
case 57600:
control[0] = ACT200L_REG8 | (ACT200L_57600 & 0x0f);
control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f);
break;
case 115200:
control[0] = ACT200L_REG8 | (ACT200L_115200 & 0x0f);
control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f);
break;
}
control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE;
/* Write control bytes */
sirdev_raw_write(dev, control, 3);
msleep(5);
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
dev->speed = speed;
return ret;
}
/*
* Function act200l_reset (driver)
*
* Reset the ACTiSYS ACT-IR200L type dongle.
*/
#define ACT200L_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1)
#define ACT200L_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2)
static int act200l_reset(struct sir_dev *dev)
{
unsigned state = dev->fsm.substate;
unsigned delay = 0;
static const u8 control[9] = {
ACT200L_REG15,
ACT200L_REG13 | ACT200L_SHDW,
ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
ACT200L_REG13,
ACT200L_REG7 | ACT200L_ENPOS,
ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1,
ACT200L_REG5 | ACT200L_RWIDL,
ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR,
ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN
};
int ret = 0;
IRDA_DEBUG(2, "%s()\n", __func__ );
switch (state) {
case SIRDEV_STATE_DONGLE_RESET:
/* Reset the dongle : set RTS low for 25 ms */
sirdev_set_dtr_rts(dev, TRUE, FALSE);
state = ACT200L_STATE_WAIT1_RESET;
delay = 50;
break;
case ACT200L_STATE_WAIT1_RESET:
/* Clear DTR and set RTS to enter command mode */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
udelay(25); /* better wait for some short while */
/* Write control bytes */
sirdev_raw_write(dev, control, sizeof(control));
state = ACT200L_STATE_WAIT2_RESET;
delay = 15;
break;
case ACT200L_STATE_WAIT2_RESET:
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
dev->speed = 9600;
break;
default:
IRDA_ERROR("%s(), unknown state %d\n", __func__, state);
ret = -1;
break;
}
dev->fsm.substate = state;
return (delay > 0) ? delay : ret;
}
MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>");
MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-10"); /* IRDA_ACT200L_DONGLE */
module_init(act200l_sir_init);
module_exit(act200l_sir_cleanup);

View file

@ -0,0 +1,246 @@
/*********************************************************************
*
* 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 unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
#define MAX_SPEEDS ARRAY_SIZE(baud_rates)
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,
};
static 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;
}
static 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;
sirdev_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);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int actisys_close(struct sir_dev *dev)
{
/* Power off the dongle */
sirdev_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", __func__,
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 = speed;
break;
}
/* Set RTS low for 10 us */
sirdev_set_dtr_rts(dev, TRUE, FALSE);
udelay(MIN_DELAY);
/* Set RTS high for 10 us */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
udelay(MIN_DELAY);
}
/* Check if life is sweet... */
if (i >= MAX_SPEEDS) {
actisys_reset(dev);
ret = -EINVAL; /* 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 accommodate 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 */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
udelay(MIN_DELAY);
/* Go back to normal mode */
sirdev_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_ALIAS("irda-dongle-2"); /* IRDA_ACTISYS_DONGLE */
MODULE_ALIAS("irda-dongle-3"); /* IRDA_ACTISYS_PLUS_DONGLE */
module_init(actisys_sir_init);
module_exit(actisys_sir_cleanup);

2271
drivers/net/irda/ali-ircc.c Normal file

File diff suppressed because it is too large Load diff

228
drivers/net/irda/ali-ircc.h Normal file
View file

@ -0,0 +1,228 @@
/*********************************************************************
*
* Filename: ali-ircc.h
* Version: 0.5
* Description: Driver for the ALI M1535D and M1543C FIR Controller
* Status: Experimental.
* Author: Benjamin Kong <benjamin_kong@ali.com.tw>
* Created at: 2000/10/16 03:46PM
* Modified at: 2001/1/3 02:56PM
* Modified by: Benjamin Kong <benjamin_kong@ali.com.tw>
*
* Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw>
* 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.
*
********************************************************************/
#ifndef ALI_IRCC_H
#define ALI_IRCC_H
#include <linux/time.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/types.h>
#include <asm/io.h>
/* SIR Register */
/* Usr definition of linux/serial_reg.h */
/* FIR Register */
#define BANK0 0x20
#define BANK1 0x21
#define BANK2 0x22
#define BANK3 0x23
#define FIR_MCR 0x07 /* Master Control Register */
/* Bank 0 */
#define FIR_DR 0x00 /* Alias 0, FIR Data Register (R/W) */
#define FIR_IER 0x01 /* Alias 1, FIR Interrupt Enable Register (R/W) */
#define FIR_IIR 0x02 /* Alias 2, FIR Interrupt Identification Register (Read only) */
#define FIR_LCR_A 0x03 /* Alias 3, FIR Line Control Register A (R/W) */
#define FIR_LCR_B 0x04 /* Alias 4, FIR Line Control Register B (R/W) */
#define FIR_LSR 0x05 /* Alias 5, FIR Line Status Register (R/W) */
#define FIR_BSR 0x06 /* Alias 6, FIR Bus Status Register (Read only) */
/* Alias 1 */
#define IER_FIFO 0x10 /* FIR FIFO Interrupt Enable */
#define IER_TIMER 0x20 /* Timer Interrupt Enable */
#define IER_EOM 0x40 /* End of Message Interrupt Enable */
#define IER_ACT 0x80 /* Active Frame Interrupt Enable */
/* Alias 2 */
#define IIR_FIFO 0x10 /* FIR FIFO Interrupt */
#define IIR_TIMER 0x20 /* Timer Interrupt */
#define IIR_EOM 0x40 /* End of Message Interrupt */
#define IIR_ACT 0x80 /* Active Frame Interrupt */
/* Alias 3 */
#define LCR_A_FIFO_RESET 0x80 /* FIFO Reset */
/* Alias 4 */
#define LCR_B_BW 0x10 /* Brick Wall */
#define LCR_B_SIP 0x20 /* SIP Enable */
#define LCR_B_TX_MODE 0x40 /* Transmit Mode */
#define LCR_B_RX_MODE 0x80 /* Receive Mode */
/* Alias 5 */
#define LSR_FIR_LSA 0x00 /* FIR Line Status Address */
#define LSR_FRAME_ABORT 0x08 /* Frame Abort */
#define LSR_CRC_ERROR 0x10 /* CRC Error */
#define LSR_SIZE_ERROR 0x20 /* Size Error */
#define LSR_FRAME_ERROR 0x40 /* Frame Error */
#define LSR_FIFO_UR 0x80 /* FIFO Underrun */
#define LSR_FIFO_OR 0x80 /* FIFO Overrun */
/* Alias 6 */
#define BSR_FIFO_NOT_EMPTY 0x80 /* FIFO Not Empty */
/* Bank 1 */
#define FIR_CR 0x00 /* Alias 0, FIR Configuration Register (R/W) */
#define FIR_FIFO_TR 0x01 /* Alias 1, FIR FIFO Threshold Register (R/W) */
#define FIR_DMA_TR 0x02 /* Alias 2, FIR DMA Threshold Register (R/W) */
#define FIR_TIMER_IIR 0x03 /* Alias 3, FIR Timer interrupt interval register (W/O) */
#define FIR_FIFO_FR 0x03 /* Alias 3, FIR FIFO Flag register (R/O) */
#define FIR_FIFO_RAR 0x04 /* Alias 4, FIR FIFO Read Address register (R/O) */
#define FIR_FIFO_WAR 0x05 /* Alias 5, FIR FIFO Write Address register (R/O) */
#define FIR_TR 0x06 /* Alias 6, Test REgister (W/O) */
/* Alias 0 */
#define CR_DMA_EN 0x01 /* DMA Enable */
#define CR_DMA_BURST 0x02 /* DMA Burst Mode */
#define CR_TIMER_EN 0x08 /* Timer Enable */
/* Alias 3 */
#define TIMER_IIR_500 0x00 /* 500 us */
#define TIMER_IIR_1ms 0x01 /* 1 ms */
#define TIMER_IIR_2ms 0x02 /* 2 ms */
#define TIMER_IIR_4ms 0x03 /* 4 ms */
/* Bank 2 */
#define FIR_IRDA_CR 0x00 /* Alias 0, IrDA Control Register (R/W) */
#define FIR_BOF_CR 0x01 /* Alias 1, BOF Count Register (R/W) */
#define FIR_BW_CR 0x02 /* Alias 2, Brick Wall Count Register (R/W) */
#define FIR_TX_DSR_HI 0x03 /* Alias 3, TX Data Size Register (high) (R/W) */
#define FIR_TX_DSR_LO 0x04 /* Alias 4, TX Data Size Register (low) (R/W) */
#define FIR_RX_DSR_HI 0x05 /* Alias 5, RX Data Size Register (high) (R/W) */
#define FIR_RX_DSR_LO 0x06 /* Alias 6, RX Data Size Register (low) (R/W) */
/* Alias 0 */
#define IRDA_CR_HDLC1152 0x80 /* 1.152Mbps HDLC Select */
#define IRDA_CR_CRC 0X40 /* CRC Select. */
#define IRDA_CR_HDLC 0x20 /* HDLC select. */
#define IRDA_CR_HP_MODE 0x10 /* HP mode (read only) */
#define IRDA_CR_SD_ST 0x08 /* SD/MODE State. */
#define IRDA_CR_FIR_SIN 0x04 /* FIR SIN Select. */
#define IRDA_CR_ITTX_0 0x02 /* SOUT State. IRTX force to 0 */
#define IRDA_CR_ITTX_1 0x03 /* SOUT State. IRTX force to 1 */
/* Bank 3 */
#define FIR_ID_VR 0x00 /* Alias 0, FIR ID Version Register (R/O) */
#define FIR_MODULE_CR 0x01 /* Alias 1, FIR Module Control Register (R/W) */
#define FIR_IO_BASE_HI 0x02 /* Alias 2, FIR Higher I/O Base Address Register (R/O) */
#define FIR_IO_BASE_LO 0x03 /* Alias 3, FIR Lower I/O Base Address Register (R/O) */
#define FIR_IRQ_CR 0x04 /* Alias 4, FIR IRQ Channel Register (R/O) */
#define FIR_DMA_CR 0x05 /* Alias 5, FIR DMA Channel Register (R/O) */
struct ali_chip {
char *name;
int cfg[2];
unsigned char entr1;
unsigned char entr2;
unsigned char cid_index;
unsigned char cid_value;
int (*probe)(struct ali_chip *chip, chipio_t *info);
int (*init)(struct ali_chip *chip, chipio_t *info);
};
typedef struct ali_chip ali_chip_t;
/* DMA modes needed */
#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
#define MAX_TX_WINDOW 7
#define MAX_RX_WINDOW 7
#define TX_FIFO_Threshold 8
#define RX_FIFO_Threshold 1
#define TX_DMA_Threshold 1
#define RX_DMA_Threshold 1
/* For storing entries in the status FIFO */
struct st_fifo_entry {
int status;
int len;
};
struct st_fifo {
struct st_fifo_entry entries[MAX_RX_WINDOW];
int pending_bytes;
int head;
int tail;
int len;
};
struct frame_cb {
void *start; /* Start of frame in DMA mem */
int len; /* Length of frame in DMA mem */
};
struct tx_fifo {
struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
int ptr; /* Currently being sent */
int len; /* Length of queue */
int free; /* Next free slot */
void *tail; /* Next free start in DMA mem */
};
/* Private data for each instance */
struct ali_ircc_cb {
struct st_fifo st_fifo; /* Info about received frames */
struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos; /* QoS capabilities for this device */
chipio_t io; /* IrDA controller information */
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
dma_addr_t tx_buff_dma;
dma_addr_t rx_buff_dma;
__u8 ier; /* Interrupt enable register */
__u8 InterruptID; /* Interrupt ID */
__u8 BusStatus; /* Bus Status */
__u8 LineStatus; /* Line Status */
unsigned char rcvFramesOverflow;
struct timeval stamp;
struct timeval now;
spinlock_t lock; /* For serializing operations */
__u32 new_speed;
int index; /* Instance index */
unsigned char fifo_opti_buf;
};
static inline void switch_bank(int iobase, int bank)
{
outb(bank, iobase+FIR_MCR);
}
#endif /* ALI_IRCC_H */

1001
drivers/net/irda/au1k_ir.c Normal file

File diff suppressed because it is too large Load diff

818
drivers/net/irda/bfin_sir.c Normal file
View file

@ -0,0 +1,818 @@
/*
* Blackfin Infra-red Driver
*
* Copyright 2006-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*
*/
#include "bfin_sir.h"
#ifdef CONFIG_SIR_BFIN_DMA
#define DMA_SIR_RX_XCNT 10
#define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT)
#define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250)
#endif
#if ANOMALY_05000447
static int max_rate = 57600;
#else
static int max_rate = 115200;
#endif
static void turnaround_delay(unsigned long last_jif, int mtt)
{
long ticks;
mtt = mtt < 10000 ? 10000 : mtt;
ticks = 1 + mtt / (USEC_PER_SEC / HZ);
schedule_timeout_uninterruptible(ticks);
}
static void bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev)
{
int i;
struct resource *res;
for (i = 0; i < pdev->num_resources; i++) {
res = &pdev->resource[i];
switch (res->flags) {
case IORESOURCE_MEM:
sp->membase = (void __iomem *)res->start;
break;
case IORESOURCE_IRQ:
sp->irq = res->start;
break;
case IORESOURCE_DMA:
sp->rx_dma_channel = res->start;
sp->tx_dma_channel = res->end;
break;
default:
break;
}
}
sp->clk = get_sclk();
#ifdef CONFIG_SIR_BFIN_DMA
sp->tx_done = 1;
init_timer(&(sp->rx_dma_timer));
#endif
}
static void bfin_sir_stop_tx(struct bfin_sir_port *port)
{
#ifdef CONFIG_SIR_BFIN_DMA
disable_dma(port->tx_dma_channel);
#endif
while (!(UART_GET_LSR(port) & THRE)) {
cpu_relax();
continue;
}
UART_CLEAR_IER(port, ETBEI);
}
static void bfin_sir_enable_tx(struct bfin_sir_port *port)
{
UART_SET_IER(port, ETBEI);
}
static void bfin_sir_stop_rx(struct bfin_sir_port *port)
{
UART_CLEAR_IER(port, ERBFI);
}
static void bfin_sir_enable_rx(struct bfin_sir_port *port)
{
UART_SET_IER(port, ERBFI);
}
static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
{
int ret = -EINVAL;
unsigned int quot;
unsigned short val, lsr, lcr;
static int utime;
int count = 10;
lcr = WLS(8);
switch (speed) {
case 9600:
case 19200:
case 38400:
case 57600:
case 115200:
/*
* IRDA is not affected by anomaly 05000230, so there is no
* need to tweak the divisor like he UART driver (which will
* slightly speed up the baud rate on us).
*/
quot = (port->clk + (8 * speed)) / (16 * speed);
do {
udelay(utime);
lsr = UART_GET_LSR(port);
} while (!(lsr & TEMT) && count--);
/* The useconds for 1 bits to transmit */
utime = 1000000 / speed + 1;
/* Clear UCEN bit to reset the UART state machine
* and control registers
*/
val = UART_GET_GCTL(port);
val &= ~UCEN;
UART_PUT_GCTL(port, val);
/* Set DLAB in LCR to Access THR RBR IER */
UART_SET_DLAB(port);
SSYNC();
UART_PUT_DLL(port, quot & 0xFF);
UART_PUT_DLH(port, (quot >> 8) & 0xFF);
SSYNC();
/* Clear DLAB in LCR */
UART_CLEAR_DLAB(port);
SSYNC();
UART_PUT_LCR(port, lcr);
val = UART_GET_GCTL(port);
val |= UCEN;
UART_PUT_GCTL(port, val);
ret = 0;
break;
default:
printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed);
break;
}
val = UART_GET_GCTL(port);
/* If not add the 'RPOLC', we can't catch the receive interrupt.
* It's related with the HW layout and the IR transiver.
*/
val |= UMOD_IRDA | RPOLC;
UART_PUT_GCTL(port, val);
return ret;
}
static int bfin_sir_is_receiving(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
if (!(UART_GET_IER(port) & ERBFI))
return 0;
return self->rx_buff.state != OUTSIDE_FRAME;
}
#ifdef CONFIG_SIR_BFIN_PIO
static void bfin_sir_tx_chars(struct net_device *dev)
{
unsigned int chr;
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
if (self->tx_buff.len != 0) {
chr = *(self->tx_buff.data);
UART_PUT_CHAR(port, chr);
self->tx_buff.data++;
self->tx_buff.len--;
} else {
self->stats.tx_packets++;
self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head;
if (self->newspeed) {
bfin_sir_set_speed(port, self->newspeed);
self->speed = self->newspeed;
self->newspeed = 0;
}
bfin_sir_stop_tx(port);
bfin_sir_enable_rx(port);
/* I'm hungry! */
netif_wake_queue(dev);
}
}
static void bfin_sir_rx_chars(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
unsigned char ch;
UART_CLEAR_LSR(port);
ch = UART_GET_CHAR(port);
async_unwrap_char(dev, &self->stats, &self->rx_buff, ch);
dev->last_rx = jiffies;
}
static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
spin_lock(&self->lock);
while ((UART_GET_LSR(port) & DR))
bfin_sir_rx_chars(dev);
spin_unlock(&self->lock);
return IRQ_HANDLED;
}
static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
spin_lock(&self->lock);
if (UART_GET_LSR(port) & THRE)
bfin_sir_tx_chars(dev);
spin_unlock(&self->lock);
return IRQ_HANDLED;
}
#endif /* CONFIG_SIR_BFIN_PIO */
#ifdef CONFIG_SIR_BFIN_DMA
static void bfin_sir_dma_tx_chars(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
if (!port->tx_done)
return;
port->tx_done = 0;
if (self->tx_buff.len == 0) {
self->stats.tx_packets++;
if (self->newspeed) {
bfin_sir_set_speed(port, self->newspeed);
self->speed = self->newspeed;
self->newspeed = 0;
}
bfin_sir_enable_rx(port);
port->tx_done = 1;
netif_wake_queue(dev);
return;
}
blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data),
(unsigned long)(self->tx_buff.data+self->tx_buff.len));
set_dma_config(port->tx_dma_channel,
set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8,
DMA_SYNC_RESTART));
set_dma_start_addr(port->tx_dma_channel,
(unsigned long)(self->tx_buff.data));
set_dma_x_count(port->tx_dma_channel, self->tx_buff.len);
set_dma_x_modify(port->tx_dma_channel, 1);
enable_dma(port->tx_dma_channel);
}
static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
spin_lock(&self->lock);
if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) {
clear_dma_irqstat(port->tx_dma_channel);
bfin_sir_stop_tx(port);
self->stats.tx_packets++;
self->stats.tx_bytes += self->tx_buff.len;
self->tx_buff.len = 0;
if (self->newspeed) {
bfin_sir_set_speed(port, self->newspeed);
self->speed = self->newspeed;
self->newspeed = 0;
}
bfin_sir_enable_rx(port);
/* I'm hungry! */
netif_wake_queue(dev);
port->tx_done = 1;
}
spin_unlock(&self->lock);
return IRQ_HANDLED;
}
static void bfin_sir_dma_rx_chars(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
int i;
UART_CLEAR_LSR(port);
for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++)
async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]);
}
void bfin_sir_rx_dma_timeout(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
int x_pos, pos;
unsigned long flags;
spin_lock_irqsave(&self->lock, flags);
x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel);
if (x_pos == DMA_SIR_RX_XCNT)
x_pos = 0;
pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos;
if (pos > port->rx_dma_buf.tail) {
port->rx_dma_buf.tail = pos;
bfin_sir_dma_rx_chars(dev);
port->rx_dma_buf.head = port->rx_dma_buf.tail;
}
spin_unlock_irqrestore(&self->lock, flags);
}
static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
unsigned short irqstat;
spin_lock(&self->lock);
port->rx_dma_nrows++;
port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows;
bfin_sir_dma_rx_chars(dev);
if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) {
port->rx_dma_nrows = 0;
port->rx_dma_buf.tail = 0;
}
port->rx_dma_buf.head = port->rx_dma_buf.tail;
irqstat = get_dma_curr_irqstat(port->rx_dma_channel);
clear_dma_irqstat(port->rx_dma_channel);
spin_unlock(&self->lock);
mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS);
return IRQ_HANDLED;
}
#endif /* CONFIG_SIR_BFIN_DMA */
static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev)
{
#ifdef CONFIG_SIR_BFIN_DMA
dma_addr_t dma_handle;
#endif /* CONFIG_SIR_BFIN_DMA */
if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) {
dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n");
return -EBUSY;
}
if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) {
dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n");
free_dma(port->rx_dma_channel);
return -EBUSY;
}
#ifdef CONFIG_SIR_BFIN_DMA
set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev);
set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev);
port->rx_dma_buf.buf = dma_alloc_coherent(NULL, PAGE_SIZE,
&dma_handle, GFP_DMA);
port->rx_dma_buf.head = 0;
port->rx_dma_buf.tail = 0;
port->rx_dma_nrows = 0;
set_dma_config(port->rx_dma_channel,
set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
INTR_ON_ROW, DIMENSION_2D,
DATA_SIZE_8, DMA_SYNC_RESTART));
set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT);
set_dma_x_modify(port->rx_dma_channel, 1);
set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT);
set_dma_y_modify(port->rx_dma_channel, 1);
set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf);
enable_dma(port->rx_dma_channel);
port->rx_dma_timer.data = (unsigned long)(dev);
port->rx_dma_timer.function = (void *)bfin_sir_rx_dma_timeout;
#else
if (request_irq(port->irq, bfin_sir_rx_int, 0, "BFIN_SIR_RX", dev)) {
dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n");
return -EBUSY;
}
if (request_irq(port->irq+1, bfin_sir_tx_int, 0, "BFIN_SIR_TX", dev)) {
dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n");
free_irq(port->irq, dev);
return -EBUSY;
}
#endif
return 0;
}
static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev)
{
unsigned short val;
bfin_sir_stop_rx(port);
val = UART_GET_GCTL(port);
val &= ~(UCEN | UMOD_MASK | RPOLC);
UART_PUT_GCTL(port, val);
#ifdef CONFIG_SIR_BFIN_DMA
disable_dma(port->tx_dma_channel);
disable_dma(port->rx_dma_channel);
del_timer(&(port->rx_dma_timer));
dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0);
#else
free_irq(port->irq+1, dev);
free_irq(port->irq, dev);
#endif
free_dma(port->tx_dma_channel);
free_dma(port->rx_dma_channel);
}
#ifdef CONFIG_PM
static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state)
{
struct bfin_sir_port *sir_port;
struct net_device *dev;
struct bfin_sir_self *self;
sir_port = platform_get_drvdata(pdev);
if (!sir_port)
return 0;
dev = sir_port->dev;
self = netdev_priv(dev);
if (self->open) {
flush_work(&self->work);
bfin_sir_shutdown(self->sir_port, dev);
netif_device_detach(dev);
}
return 0;
}
static int bfin_sir_resume(struct platform_device *pdev)
{
struct bfin_sir_port *sir_port;
struct net_device *dev;
struct bfin_sir_self *self;
struct bfin_sir_port *port;
sir_port = platform_get_drvdata(pdev);
if (!sir_port)
return 0;
dev = sir_port->dev;
self = netdev_priv(dev);
port = self->sir_port;
if (self->open) {
if (self->newspeed) {
self->speed = self->newspeed;
self->newspeed = 0;
}
bfin_sir_startup(port, dev);
bfin_sir_set_speed(port, 9600);
bfin_sir_enable_rx(port);
netif_device_attach(dev);
}
return 0;
}
#else
#define bfin_sir_suspend NULL
#define bfin_sir_resume NULL
#endif
static void bfin_sir_send_work(struct work_struct *work)
{
struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work);
struct net_device *dev = self->sir_port->dev;
struct bfin_sir_port *port = self->sir_port;
unsigned short val;
int tx_cnt = 10;
while (bfin_sir_is_receiving(dev) && --tx_cnt)
turnaround_delay(dev->last_rx, self->mtt);
bfin_sir_stop_rx(port);
/* To avoid losting RX interrupt, we reset IR function before
* sending data. We also can set the speed, which will
* reset all the UART.
*/
val = UART_GET_GCTL(port);
val &= ~(UMOD_MASK | RPOLC);
UART_PUT_GCTL(port, val);
SSYNC();
val |= UMOD_IRDA | RPOLC;
UART_PUT_GCTL(port, val);
SSYNC();
/* bfin_sir_set_speed(port, self->speed); */
#ifdef CONFIG_SIR_BFIN_DMA
bfin_sir_dma_tx_chars(dev);
#endif
bfin_sir_enable_tx(port);
dev->trans_start = jiffies;
}
static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
int speed = irda_get_next_speed(skb);
netif_stop_queue(dev);
self->mtt = irda_get_mtt(skb);
if (speed != self->speed && speed != -1)
self->newspeed = speed;
self->tx_buff.data = self->tx_buff.head;
if (skb->len == 0)
self->tx_buff.len = 0;
else
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize);
schedule_work(&self->work);
dev_kfree_skb(skb);
return 0;
}
static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
{
struct if_irda_req *rq = (struct if_irda_req *)ifreq;
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
int ret = 0;
switch (cmd) {
case SIOCSBANDWIDTH:
if (capable(CAP_NET_ADMIN)) {
if (self->open) {
ret = bfin_sir_set_speed(port, rq->ifr_baudrate);
bfin_sir_enable_rx(port);
} else {
dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n");
ret = 0;
}
}
break;
case SIOCSMEDIABUSY:
ret = -EPERM;
if (capable(CAP_NET_ADMIN)) {
irda_device_set_media_busy(dev, TRUE);
ret = 0;
}
break;
case SIOCGRECEIVING:
rq->ifr_receiving = bfin_sir_is_receiving(dev);
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static struct net_device_stats *bfin_sir_stats(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
return &self->stats;
}
static int bfin_sir_open(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
int err;
self->newspeed = 0;
self->speed = 9600;
spin_lock_init(&self->lock);
err = bfin_sir_startup(port, dev);
if (err)
goto err_startup;
bfin_sir_set_speed(port, 9600);
self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME);
if (!self->irlap) {
err = -ENOMEM;
goto err_irlap;
}
INIT_WORK(&self->work, bfin_sir_send_work);
/*
* Now enable the interrupt then start the queue
*/
self->open = 1;
bfin_sir_enable_rx(port);
netif_start_queue(dev);
return 0;
err_irlap:
self->open = 0;
bfin_sir_shutdown(port, dev);
err_startup:
return err;
}
static int bfin_sir_stop(struct net_device *dev)
{
struct bfin_sir_self *self = netdev_priv(dev);
flush_work(&self->work);
bfin_sir_shutdown(self->sir_port, dev);
if (self->rxskb) {
dev_kfree_skb(self->rxskb);
self->rxskb = NULL;
}
/* Stop IrLAP */
if (self->irlap) {
irlap_close(self->irlap);
self->irlap = NULL;
}
netif_stop_queue(dev);
self->open = 0;
return 0;
}
static int bfin_sir_init_iobuf(iobuff_t *io, int size)
{
io->head = kmalloc(size, GFP_KERNEL);
if (!io->head)
return -ENOMEM;
io->truesize = size;
io->in_frame = FALSE;
io->state = OUTSIDE_FRAME;
io->data = io->head;
return 0;
}
static const struct net_device_ops bfin_sir_ndo = {
.ndo_open = bfin_sir_open,
.ndo_stop = bfin_sir_stop,
.ndo_start_xmit = bfin_sir_hard_xmit,
.ndo_do_ioctl = bfin_sir_ioctl,
.ndo_get_stats = bfin_sir_stats,
};
static int bfin_sir_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct bfin_sir_self *self;
unsigned int baudrate_mask;
struct bfin_sir_port *sir_port;
int err;
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \
per[pdev->id][3] == pdev->id) {
err = peripheral_request_list(per[pdev->id], DRIVER_NAME);
if (err)
return err;
} else {
dev_err(&pdev->dev, "Invalid pdev id, please check board file\n");
return -ENODEV;
}
err = -ENOMEM;
sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL);
if (!sir_port)
goto err_mem_0;
bfin_sir_init_ports(sir_port, pdev);
dev = alloc_irdadev(sizeof(*self));
if (!dev)
goto err_mem_1;
self = netdev_priv(dev);
self->dev = &pdev->dev;
self->sir_port = sir_port;
sir_port->dev = dev;
err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU);
if (err)
goto err_mem_2;
err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME);
if (err)
goto err_mem_3;
dev->netdev_ops = &bfin_sir_ndo;
dev->irq = sir_port->irq;
irda_init_max_qos_capabilies(&self->qos);
baudrate_mask = IR_9600;
switch (max_rate) {
case 115200:
baudrate_mask |= IR_115200;
case 57600:
baudrate_mask |= IR_57600;
case 38400:
baudrate_mask |= IR_38400;
case 19200:
baudrate_mask |= IR_19200;
case 9600:
break;
default:
dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n");
}
self->qos.baud_rate.bits &= baudrate_mask;
self->qos.min_turn_time.bits = 1; /* 10 ms or more */
irda_qos_bits_to_value(&self->qos);
err = register_netdev(dev);
if (err) {
kfree(self->tx_buff.head);
err_mem_3:
kfree(self->rx_buff.head);
err_mem_2:
free_netdev(dev);
err_mem_1:
kfree(sir_port);
err_mem_0:
peripheral_free_list(per[pdev->id]);
} else
platform_set_drvdata(pdev, sir_port);
return err;
}
static int bfin_sir_remove(struct platform_device *pdev)
{
struct bfin_sir_port *sir_port;
struct net_device *dev = NULL;
struct bfin_sir_self *self;
sir_port = platform_get_drvdata(pdev);
if (!sir_port)
return 0;
dev = sir_port->dev;
self = netdev_priv(dev);
unregister_netdev(dev);
kfree(self->tx_buff.head);
kfree(self->rx_buff.head);
free_netdev(dev);
kfree(sir_port);
return 0;
}
static struct platform_driver bfin_ir_driver = {
.probe = bfin_sir_probe,
.remove = bfin_sir_remove,
.suspend = bfin_sir_suspend,
.resume = bfin_sir_resume,
.driver = {
.name = DRIVER_NAME,
},
};
module_platform_driver(bfin_ir_driver);
module_param(max_rate, int, 0);
MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)");
MODULE_AUTHOR("Graf Yang <graf.yang@analog.com>");
MODULE_DESCRIPTION("Blackfin IrDA driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,96 @@
/*
* Blackfin Infra-red Driver
*
* Copyright 2006-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*
*/
#include <linux/serial.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#include <asm/irq.h>
#include <asm/cacheflush.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#undef DRIVER_NAME
#ifdef CONFIG_SIR_BFIN_DMA
struct dma_rx_buf {
char *buf;
int head;
int tail;
};
#endif
struct bfin_sir_port {
unsigned char __iomem *membase;
unsigned int irq;
unsigned int lsr;
unsigned long clk;
struct net_device *dev;
#ifdef CONFIG_SIR_BFIN_DMA
int tx_done;
struct dma_rx_buf rx_dma_buf;
struct timer_list rx_dma_timer;
int rx_dma_nrows;
#endif
unsigned int tx_dma_channel;
unsigned int rx_dma_channel;
};
struct bfin_sir_port_res {
unsigned long base_addr;
int irq;
unsigned int rx_dma_channel;
unsigned int tx_dma_channel;
};
struct bfin_sir_self {
struct bfin_sir_port *sir_port;
spinlock_t lock;
unsigned int open;
int speed;
int newspeed;
struct sk_buff *txskb;
struct sk_buff *rxskb;
struct net_device_stats stats;
struct device *dev;
struct irlap_cb *irlap;
struct qos_info qos;
iobuff_t tx_buff;
iobuff_t rx_buff;
struct work_struct work;
int mtt;
};
#define DRIVER_NAME "bfin_sir"
#define port_membase(port) (((struct bfin_sir_port *)(port))->membase)
#define get_lsr_cache(port) (((struct bfin_sir_port *)(port))->lsr)
#define put_lsr_cache(port, v) (((struct bfin_sir_port *)(port))->lsr = (v))
#include <asm/bfin_serial.h>
static const unsigned short per[][4] = {
/* rx pin tx pin NULL uart_number */
{P_UART0_RX, P_UART0_TX, 0, 0},
{P_UART1_RX, P_UART1_TX, 0, 1},
{P_UART2_RX, P_UART2_TX, 0, 2},
{P_UART3_RX, P_UART3_TX, 0, 3},
};

1758
drivers/net/irda/donauboe.c Normal file

File diff suppressed because it is too large Load diff

362
drivers/net/irda/donauboe.h Normal file
View file

@ -0,0 +1,362 @@
/*********************************************************************
*
* Filename: toshoboe.h
* Version: 2.16
* Description: Driver for the Toshiba OBOE (or type-O or 701)
* FIR Chipset, also supports the DONAUOBOE (type-DO
* or d01) FIR chipset which as far as I know is
* register compatible.
* Status: Experimental.
* Author: James McKenzie <james@fishsoup.dhs.org>
* Created at: Sat May 8 12:35:27 1999
* Modified: 2.16 Martin Lucina <mato@kotelna.sk>
* Modified: 2.16 Sat Jun 22 18:54:29 2002 (sync headers)
* Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org>
* Modified: 2.17 jeu sep 12 08:50:20 2002 (add lock to be used by spinlocks)
*
* Copyright (c) 1999 James McKenzie, 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 James McKenzie nor Cambridge University admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
* Applicable Models : Libretto 100/110CT and many more.
* Toshiba refers to this chip as the type-O IR port,
* or the type-DO IR port.
*
* IrDA chip set list from Toshiba Computer Engineering Corp.
* model method maker controller Version
* Portege 320CT FIR,SIR Toshiba Oboe(Triangle)
* Portege 3010CT FIR,SIR Toshiba Oboe(Sydney)
* Portege 3015CT FIR,SIR Toshiba Oboe(Sydney)
* Portege 3020CT FIR,SIR Toshiba Oboe(Sydney)
* Portege 7020CT FIR,SIR ? ?
*
* Satell. 4090XCDT FIR,SIR ? ?
*
* Libretto 100CT FIR,SIR Toshiba Oboe
* Libretto 1000CT FIR,SIR Toshiba Oboe
*
* TECRA750DVD FIR,SIR Toshiba Oboe(Triangle) REV ID=14h
* TECRA780 FIR,SIR Toshiba Oboe(Sandlot) REV ID=32h,33h
* TECRA750CDT FIR,SIR Toshiba Oboe(Triangle) REV ID=13h,14h
* TECRA8000 FIR,SIR Toshiba Oboe(ISKUR) REV ID=23h
*
********************************************************************/
/* The documentation for this chip is allegedly released */
/* However I have not seen it, not have I managed to contact */
/* anyone who has. HOWEVER the chip bears a striking resemblance */
/* to the IrDA controller in the Toshiba RISC TMPR3922 chip */
/* the documentation for this is freely available at */
/* http://www.madingley.org/james/resources/toshoboe/TMPR3922.pdf */
/* The mapping between the registers in that document and the */
/* Registers in the 701 oboe chip are as follows */
/* 3922 reg 701 regs, by bit numbers */
/* 7- 0 15- 8 24-16 31-25 */
/* $28 0x0 0x1 */
/* $2c SEE NOTE 1 */
/* $30 0x6 0x7 */
/* $34 0x8 0x9 SEE NOTE 2 */
/* $38 0x10 0x11 */
/* $3C 0xe SEE NOTE 3 */
/* $40 0x12 0x13 */
/* $44 0x14 0x15 */
/* $48 0x16 0x17 */
/* $4c 0x18 0x19 */
/* $50 0x1a 0x1b */
/* FIXME: could be 0x1b 0x1a here */
/* $54 0x1d 0x1c */
/* $5C 0xf SEE NOTE 4 */
/* $130 SEE NOTE 5 */
/* $134 SEE NOTE 6 */
/* */
/* NOTES: */
/* 1. The pointer to ring is packed in most unceremoniusly */
/* 701 Register Address bits (A9-A0 must be zero) */
/* 0x4: A17 A16 A15 A14 A13 A12 A11 A10 */
/* 0x5: A25 A24 A23 A22 A21 A20 A19 A18 */
/* 0x2: 0 0 A31 A30 A29 A28 A27 A26 */
/* */
/* 2. The M$ drivers do a write 0x1 to 0x9, however the 3922 */
/* documentation would suggest that a write of 0x1 to 0x8 */
/* would be more appropriate. */
/* */
/* 3. This assignment is tenuous at best, register 0xe seems to */
/* have bits arranged 0 0 0 R/W R/W R/W R/W R/W */
/* if either of the lower two bits are set the chip seems to */
/* switch off */
/* */
/* 4. Bits 7-4 seem to be different 4 seems just to be generic */
/* receiver busy flag */
/* */
/* 5. and 6. The IER and ISR have a different bit assignment */
/* The lower three bits of both read back as ones */
/* ISR is register 0xc, IER is register 0xd */
/* 7 6 5 4 3 2 1 0 */
/* 0xc: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */
/* 0xd: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */
/* TxDone xmitt done (generated only if generate interrupt bit */
/* is set in the ring) */
/* RxDone recv completed (or other recv condition if you set it */
/* up */
/* TxUnder underflow in Transmit FIFO */
/* RxOver overflow in Recv FIFO */
/* SipRcv received serial gap (or other condition you set) */
/* Interrupts are enabled by writing a one to the IER register */
/* Interrupts are cleared by writing a one to the ISR register */
/* */
/* 6. The remaining registers: 0x6 and 0x3 appear to be */
/* reserved parts of 16 or 32 bit registersthe remainder */
/* 0xa 0xb 0x1e 0x1f could possibly be (by their behaviour) */
/* the Unicast Filter register at $58. */
/* */
/* 7. While the core obviously expects 32 bit accesses all the */
/* M$ drivers do 8 bit accesses, infact the Miniport ones */
/* write and read back the byte serveral times (why?) */
#ifndef TOSHOBOE_H
#define TOSHOBOE_H
/* Registers */
#define OBOE_IO_EXTENT 0x1f
/*Receive and transmit slot pointers */
#define OBOE_REG(i) (i+(self->base))
#define OBOE_RXSLOT OBOE_REG(0x0)
#define OBOE_TXSLOT OBOE_REG(0x1)
#define OBOE_SLOT_MASK 0x3f
#define OBOE_TXRING_OFFSET 0x200
#define OBOE_TXRING_OFFSET_IN_SLOTS 0x40
/*pointer to the ring */
#define OBOE_RING_BASE0 OBOE_REG(0x4)
#define OBOE_RING_BASE1 OBOE_REG(0x5)
#define OBOE_RING_BASE2 OBOE_REG(0x2)
#define OBOE_RING_BASE3 OBOE_REG(0x3)
/*Number of slots in the ring */
#define OBOE_RING_SIZE OBOE_REG(0x7)
#define OBOE_RING_SIZE_RX4 0x00
#define OBOE_RING_SIZE_RX8 0x01
#define OBOE_RING_SIZE_RX16 0x03
#define OBOE_RING_SIZE_RX32 0x07
#define OBOE_RING_SIZE_RX64 0x0f
#define OBOE_RING_SIZE_TX4 0x00
#define OBOE_RING_SIZE_TX8 0x10
#define OBOE_RING_SIZE_TX16 0x30
#define OBOE_RING_SIZE_TX32 0x70
#define OBOE_RING_SIZE_TX64 0xf0
#define OBOE_RING_MAX_SIZE 64
/*Causes the gubbins to re-examine the ring */
#define OBOE_PROMPT OBOE_REG(0x9)
#define OBOE_PROMPT_BIT 0x1
/* Interrupt Status Register */
#define OBOE_ISR OBOE_REG(0xc)
/* Interrupt Enable Register */
#define OBOE_IER OBOE_REG(0xd)
/* Interrupt bits for IER and ISR */
#define OBOE_INT_TXDONE 0x80
#define OBOE_INT_RXDONE 0x40
#define OBOE_INT_TXUNDER 0x20
#define OBOE_INT_RXOVER 0x10
#define OBOE_INT_SIP 0x08
#define OBOE_INT_MASK 0xf8
/*Reset Register */
#define OBOE_CONFIG1 OBOE_REG(0xe)
#define OBOE_CONFIG1_RST 0x01
#define OBOE_CONFIG1_DISABLE 0x02
#define OBOE_CONFIG1_4 0x08
#define OBOE_CONFIG1_8 0x08
#define OBOE_CONFIG1_ON 0x8
#define OBOE_CONFIG1_RESET 0xf
#define OBOE_CONFIG1_OFF 0xe
#define OBOE_STATUS OBOE_REG(0xf)
#define OBOE_STATUS_RXBUSY 0x10
#define OBOE_STATUS_FIRRX 0x04
#define OBOE_STATUS_MIRRX 0x02
#define OBOE_STATUS_SIRRX 0x01
/*Speed control registers */
#define OBOE_CONFIG0L OBOE_REG(0x10)
#define OBOE_CONFIG0H OBOE_REG(0x11)
#define OBOE_CONFIG0H_TXONLOOP 0x80 /*Transmit when looping (dangerous) */
#define OBOE_CONFIG0H_LOOP 0x40 /*Loopback Tx->Rx */
#define OBOE_CONFIG0H_ENTX 0x10 /*Enable Tx */
#define OBOE_CONFIG0H_ENRX 0x08 /*Enable Rx */
#define OBOE_CONFIG0H_ENDMAC 0x04 /*Enable/reset* the DMA controller */
#define OBOE_CONFIG0H_RCVANY 0x02 /*DMA mode 1=bytes, 0=dwords */
#define OBOE_CONFIG0L_CRC16 0x80 /*CRC 1=16 bit 0=32 bit */
#define OBOE_CONFIG0L_ENFIR 0x40 /*Enable FIR */
#define OBOE_CONFIG0L_ENMIR 0x20 /*Enable MIR */
#define OBOE_CONFIG0L_ENSIR 0x10 /*Enable SIR */
#define OBOE_CONFIG0L_ENSIRF 0x08 /*Enable SIR framer */
#define OBOE_CONFIG0L_SIRTEST 0x04 /*Enable SIR framer in MIR and FIR */
#define OBOE_CONFIG0L_INVERTTX 0x02 /*Invert Tx Line */
#define OBOE_CONFIG0L_INVERTRX 0x01 /*Invert Rx Line */
#define OBOE_BOF OBOE_REG(0x12)
#define OBOE_EOF OBOE_REG(0x13)
#define OBOE_ENABLEL OBOE_REG(0x14)
#define OBOE_ENABLEH OBOE_REG(0x15)
#define OBOE_ENABLEH_PHYANDCLOCK 0x80 /*Toggle low to copy config in */
#define OBOE_ENABLEH_CONFIGERR 0x40
#define OBOE_ENABLEH_FIRON 0x20
#define OBOE_ENABLEH_MIRON 0x10
#define OBOE_ENABLEH_SIRON 0x08
#define OBOE_ENABLEH_ENTX 0x04
#define OBOE_ENABLEH_ENRX 0x02
#define OBOE_ENABLEH_CRC16 0x01
#define OBOE_ENABLEL_BROADCAST 0x01
#define OBOE_CURR_PCONFIGL OBOE_REG(0x16) /*Current config */
#define OBOE_CURR_PCONFIGH OBOE_REG(0x17)
#define OBOE_NEW_PCONFIGL OBOE_REG(0x18)
#define OBOE_NEW_PCONFIGH OBOE_REG(0x19)
#define OBOE_PCONFIGH_BAUDMASK 0xfc
#define OBOE_PCONFIGH_WIDTHMASK 0x04
#define OBOE_PCONFIGL_WIDTHMASK 0xe0
#define OBOE_PCONFIGL_PREAMBLEMASK 0x1f
#define OBOE_PCONFIG_BAUDMASK 0xfc00
#define OBOE_PCONFIG_BAUDSHIFT 10
#define OBOE_PCONFIG_WIDTHMASK 0x04e0
#define OBOE_PCONFIG_WIDTHSHIFT 5
#define OBOE_PCONFIG_PREAMBLEMASK 0x001f
#define OBOE_PCONFIG_PREAMBLESHIFT 0
#define OBOE_MAXLENL OBOE_REG(0x1a)
#define OBOE_MAXLENH OBOE_REG(0x1b)
#define OBOE_RXCOUNTH OBOE_REG(0x1c) /*Reset on recipt */
#define OBOE_RXCOUNTL OBOE_REG(0x1d) /*of whole packet */
/* The PCI ID of the OBOE chip */
#ifndef PCI_DEVICE_ID_FIR701
#define PCI_DEVICE_ID_FIR701 0x0701
#endif
#ifndef PCI_DEVICE_ID_FIRD01
#define PCI_DEVICE_ID_FIRD01 0x0d01
#endif
struct OboeSlot
{
__u16 len; /*Tweleve bits of packet length */
__u8 unused;
__u8 control; /*Slot control/status see below */
__u32 address; /*Slot buffer address */
}
__packed;
#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS
struct OboeRing
{
struct OboeSlot rx[OBOE_NTASKS];
struct OboeSlot tx[OBOE_NTASKS];
};
#define OBOE_RING_LEN (sizeof(struct OboeRing))
#define OBOE_CTL_TX_HW_OWNS 0x80 /*W/R This slot owned by the hardware */
#define OBOE_CTL_TX_DISTX_CRC 0x40 /*W Disable CRC generation for [FM]IR */
#define OBOE_CTL_TX_BAD_CRC 0x20 /*W Generate bad CRC */
#define OBOE_CTL_TX_SIP 0x10 /*W Generate an SIP after xmittion */
#define OBOE_CTL_TX_MKUNDER 0x08 /*W Generate an underrun error */
#define OBOE_CTL_TX_RTCENTX 0x04 /*W Enable receiver and generate TXdone */
/* After this slot is processed */
#define OBOE_CTL_TX_UNDER 0x01 /*R Set by hardware to indicate underrun */
#define OBOE_CTL_RX_HW_OWNS 0x80 /*W/R This slot owned by hardware */
#define OBOE_CTL_RX_PHYERR 0x40 /*R Decoder error on receiption */
#define OBOE_CTL_RX_CRCERR 0x20 /*R CRC error only set for [FM]IR */
#define OBOE_CTL_RX_LENGTH 0x10 /*R Packet > max Rx length */
#define OBOE_CTL_RX_OVER 0x08 /*R set to indicate an overflow */
#define OBOE_CTL_RX_SIRBAD 0x04 /*R SIR had BOF in packet or ABORT sequence */
#define OBOE_CTL_RX_RXEOF 0x02 /*R Finished receiving on this slot */
struct toshoboe_cb
{
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct tty_driver ttydev;
struct irlap_cb *irlap; /* The link layer we are binded to */
chipio_t io; /* IrDA controller information */
struct qos_info qos; /* QoS capabilities for this device */
__u32 flags; /* Interface flags */
struct pci_dev *pdev; /*PCI device */
int base; /*IO base */
int txpending; /*how many tx's are pending */
int txs, rxs; /*Which slots are we at */
int irdad; /*Driver under control of netdev end */
int async; /*Driver under control of async end */
int stopped; /*Stopped by some or other APM stuff */
int filter; /*In SIR mode do we want to receive
frames or byte ranges */
void *ringbuf; /*The ring buffer */
struct OboeRing *ring; /*The ring */
void *tx_bufs[OBOE_RING_MAX_SIZE]; /*The buffers */
void *rx_bufs[OBOE_RING_MAX_SIZE];
int speed; /*Current setting of the speed */
int new_speed; /*Set to request a speed change */
/* The spinlock protect critical parts of the driver.
* Locking is done like this :
* spin_lock_irqsave(&self->spinlock, flags);
* Releasing the lock :
* spin_unlock_irqrestore(&self->spinlock, flags);
*/
spinlock_t spinlock;
/* Used for the probe and diagnostics code */
int int_rx;
int int_tx;
int int_txunder;
int int_rxover;
int int_sip;
};
#endif

157
drivers/net/irda/esi-sir.c Normal file
View file

@ -0,0 +1,157 @@
/*********************************************************************
*
* 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, see <http://www.gnu.org/licenses/>.
*
********************************************************************/
#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;
/* Power up and set dongle to 9600 baud */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
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);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int esi_close(struct sir_dev *dev)
{
/* Power off dongle */
sirdev_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
* Apparently (see old esi-driver) no delays are needed here...
*
*/
static int esi_change_speed(struct sir_dev *dev, unsigned speed)
{
int ret = 0;
int dtr, rts;
switch (speed) {
case 19200:
dtr = TRUE;
rts = FALSE;
break;
case 115200:
dtr = rts = TRUE;
break;
default:
ret = -EINVAL;
speed = 9600;
/* fall through */
case 9600:
dtr = FALSE;
rts = TRUE;
break;
}
/* Change speed of dongle */
sirdev_set_dtr_rts(dev, dtr, rts);
dev->speed = speed;
return ret;
}
/*
* Function esi_reset (task)
*
* Reset dongle;
*
*/
static int esi_reset(struct sir_dev *dev)
{
sirdev_set_dtr_rts(dev, FALSE, FALSE);
/* Hm, the old esi-driver left the dongle unpowered relying on
* the following speed change to repower. This might work for
* the esi because we only need the modem lines. However, now the
* general rule is reset must bring the dongle to some working
* well-known state because speed change might write to registers.
* The old esi-driver didn't any delay here - let's hope it' fine.
*/
sirdev_set_dtr_rts(dev, FALSE, TRUE);
dev->speed = 9600;
return 0;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-1"); /* IRDA_ESI_DONGLE */
module_init(esi_sir_init);
module_exit(esi_sir_cleanup);

View file

@ -0,0 +1,258 @@
/*********************************************************************
*
* Filename: girbil.c
* Version: 1.2
* Description: Implementation for the Greenwich GIrBIL dongle
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Feb 6 21:02:33 1999
* Modified at: Fri Dec 17 09:13:20 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, 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"
static int girbil_reset(struct sir_dev *dev);
static int girbil_open(struct sir_dev *dev);
static int girbil_close(struct sir_dev *dev);
static int girbil_change_speed(struct sir_dev *dev, unsigned speed);
/* Control register 1 */
#define GIRBIL_TXEN 0x01 /* Enable transmitter */
#define GIRBIL_RXEN 0x02 /* Enable receiver */
#define GIRBIL_ECAN 0x04 /* Cancel self emitted data */
#define GIRBIL_ECHO 0x08 /* Echo control characters */
/* LED Current Register (0x2) */
#define GIRBIL_HIGH 0x20
#define GIRBIL_MEDIUM 0x21
#define GIRBIL_LOW 0x22
/* Baud register (0x3) */
#define GIRBIL_2400 0x30
#define GIRBIL_4800 0x31
#define GIRBIL_9600 0x32
#define GIRBIL_19200 0x33
#define GIRBIL_38400 0x34
#define GIRBIL_57600 0x35
#define GIRBIL_115200 0x36
/* Mode register (0x4) */
#define GIRBIL_IRDA 0x40
#define GIRBIL_ASK 0x41
/* Control register 2 (0x5) */
#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */
static struct dongle_driver girbil = {
.owner = THIS_MODULE,
.driver_name = "Greenwich GIrBIL",
.type = IRDA_GIRBIL_DONGLE,
.open = girbil_open,
.close = girbil_close,
.reset = girbil_reset,
.set_speed = girbil_change_speed,
};
static int __init girbil_sir_init(void)
{
return irda_register_dongle(&girbil);
}
static void __exit girbil_sir_cleanup(void)
{
irda_unregister_dongle(&girbil);
}
static int girbil_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power on dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
qos->min_turn_time.bits = 0x03;
irda_qos_bits_to_value(qos);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int girbil_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function girbil_change_speed (dev, speed)
*
* Set the speed for the Girbil type dongle.
*
*/
#define GIRBIL_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1)
static int girbil_change_speed(struct sir_dev *dev, unsigned speed)
{
unsigned state = dev->fsm.substate;
unsigned delay = 0;
u8 control[2];
static int ret = 0;
IRDA_DEBUG(2, "%s()\n", __func__);
/* dongle alread reset - port and dongle at default speed */
switch(state) {
case SIRDEV_STATE_DONGLE_SPEED:
/* Set DTR and Clear RTS to enter command mode */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
udelay(25); /* better wait a little while */
ret = 0;
switch (speed) {
default:
ret = -EINVAL;
/* fall through */
case 9600:
control[0] = GIRBIL_9600;
break;
case 19200:
control[0] = GIRBIL_19200;
break;
case 34800:
control[0] = GIRBIL_38400;
break;
case 57600:
control[0] = GIRBIL_57600;
break;
case 115200:
control[0] = GIRBIL_115200;
break;
}
control[1] = GIRBIL_LOAD;
/* Write control bytes */
sirdev_raw_write(dev, control, 2);
dev->speed = speed;
state = GIRBIL_STATE_WAIT_SPEED;
delay = 100;
break;
case GIRBIL_STATE_WAIT_SPEED:
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
udelay(25); /* better wait a little while */
break;
default:
IRDA_ERROR("%s - undefined state %d\n", __func__, state);
ret = -EINVAL;
break;
}
dev->fsm.substate = state;
return (delay > 0) ? delay : ret;
}
/*
* Function girbil_reset (driver)
*
* This function resets the girbil dongle.
*
* Algorithm:
* 0. set RTS, and wait at least 5 ms
* 1. clear RTS
*/
#define GIRBIL_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET + 1)
#define GIRBIL_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET + 2)
#define GIRBIL_STATE_WAIT3_RESET (SIRDEV_STATE_DONGLE_RESET + 3)
static int girbil_reset(struct sir_dev *dev)
{
unsigned state = dev->fsm.substate;
unsigned delay = 0;
u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
int ret = 0;
IRDA_DEBUG(2, "%s()\n", __func__);
switch (state) {
case SIRDEV_STATE_DONGLE_RESET:
/* Reset dongle */
sirdev_set_dtr_rts(dev, TRUE, FALSE);
/* Sleep at least 5 ms */
delay = 20;
state = GIRBIL_STATE_WAIT1_RESET;
break;
case GIRBIL_STATE_WAIT1_RESET:
/* Set DTR and clear RTS to enter command mode */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
delay = 20;
state = GIRBIL_STATE_WAIT2_RESET;
break;
case GIRBIL_STATE_WAIT2_RESET:
/* Write control byte */
sirdev_raw_write(dev, &control, 1);
delay = 20;
state = GIRBIL_STATE_WAIT3_RESET;
break;
case GIRBIL_STATE_WAIT3_RESET:
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
dev->speed = 9600;
break;
default:
IRDA_ERROR("%s(), undefined state %d\n", __func__, state);
ret = -1;
break;
}
dev->fsm.substate = state;
return (delay > 0) ? delay : ret;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-4"); /* IRDA_GIRBIL_DONGLE */
module_init(girbil_sir_init);
module_exit(girbil_sir_cleanup);

1925
drivers/net/irda/irda-usb.c Normal file

File diff suppressed because it is too large Load diff

175
drivers/net/irda/irda-usb.h Normal file
View file

@ -0,0 +1,175 @@
/*****************************************************************************
*
* Filename: irda-usb.h
* Version: 0.10
* Description: IrDA-USB Driver
* Status: Experimental
* Author: Dag Brattli <dag@brattli.net>
*
* Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at>
* Copyright (C) 2000, Dag Brattli <dag@brattli.net>
* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
* Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com>
* Copyright (C) 2005, Milan Beno <beno@pobox.sk>
* Copyright (C) 2006, Nick FEdchik <nick@fedchik.org.ua>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*****************************************************************************/
#include <linux/time.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> /* struct irlap_cb */
#define RX_COPY_THRESHOLD 200
#define IRDA_USB_MAX_MTU 2051
#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */
/* Maximum number of active URB on the Rx path
* This is the amount of buffers the we keep between the USB harware and the
* IrDA stack.
*
* Note : the network layer does also queue the packets between us and the
* IrDA stack, and is actually pretty fast and efficient in doing that.
* Therefore, we don't need to have a large number of URBs, and we can
* perfectly live happy with only one. We certainly don't need to keep the
* full IrTTP window around here...
* I repeat for those who have trouble to understand : 1 URB is plenty
* good enough to handle back-to-back (brickwalled) frames. I tried it,
* it works (it's the hardware that has trouble doing it).
*
* Having 2 URBs would allow the USB stack to process one URB while we take
* care of the other and then swap the URBs...
* On the other hand, increasing the number of URB will have penalities
* in term of latency and will interact with the link management in IrLAP...
* Jean II */
#define IU_MAX_ACTIVE_RX_URBS 1 /* Don't touch !!! */
/* When a Rx URB is passed back to us, we can't reuse it immediately,
* because it may still be referenced by the USB layer. Therefore we
* need to keep one extra URB in the Rx path.
* Jean II */
#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1)
/* Various ugly stuff to try to workaround generic problems */
/* Send speed command in case of timeout, just for trying to get things sane */
#define IU_BUG_KICK_TIMEOUT
/* Show the USB class descriptor */
#undef IU_DUMP_CLASS_DESC
/* Assume a minimum round trip latency for USB transfer (in us)...
* USB transfer are done in the next USB slot if there is no traffic
* (1/19 msec) and is done at 12 Mb/s :
* Waiting for slot + tx = (53us + 16us) * 2 = 137us minimum.
* Rx notification will only be done at the end of the USB frame period :
* OHCI : frame period = 1ms
* UHCI : frame period = 1ms, but notification can take 2 or 3 ms :-(
* EHCI : frame period = 125us */
#define IU_USB_MIN_RTT 500 /* This should be safe in most cases */
/* Inbound header */
#define MEDIA_BUSY 0x80
#define SPEED_2400 0x01
#define SPEED_9600 0x02
#define SPEED_19200 0x03
#define SPEED_38400 0x04
#define SPEED_57600 0x05
#define SPEED_115200 0x06
#define SPEED_576000 0x07
#define SPEED_1152000 0x08
#define SPEED_4000000 0x09
#define SPEED_16000000 0x0a
/* Basic capabilities */
#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */
/* Main bugs */
#define IUC_SPEED_BUG 0x01 /* Device doesn't set speed after the frame */
#define IUC_NO_WINDOW 0x02 /* Device doesn't behave with big Rx window */
#define IUC_NO_TURN 0x04 /* Device doesn't do turnaround by itself */
/* Not currently used */
#define IUC_SIR_ONLY 0x08 /* Device doesn't behave at FIR speeds */
#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */
#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */
#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */
#define IUC_STIR421X 0x80 /* SigmaTel 4210/4220/4116 VFIR */
/* USB class definitions */
#define USB_IRDA_HEADER 0x01
#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
#define USB_DT_IRDA 0x21
#define USB_IRDA_STIR421X_HEADER 0x03
#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + \
USB_IRDA_STIR421X_HEADER)
struct irda_class_desc {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdSpecRevision;
__u8 bmDataSize;
__u8 bmWindowSize;
__u8 bmMinTurnaroundTime;
__le16 wBaudRate;
__u8 bmAdditionalBOFs;
__u8 bIrdaRateSniff;
__u8 bMaxUnicastList;
} __packed;
/* class specific interface request to get the IrDA-USB class descriptor
* (6.2.5, USB-IrDA class spec 1.0) */
#define IU_REQ_GET_CLASS_DESC 0x06
#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023
struct irda_usb_cb {
struct irda_class_desc *irda_desc;
struct usb_device *usbdev; /* init: probe_irda */
struct usb_interface *usbintf; /* init: probe_irda */
int netopen; /* Device is active for network */
int present; /* Device is present on the bus */
__u32 capability; /* Capability of the hardware */
__u8 bulk_in_ep; /* Rx Endpoint assignments */
__u8 bulk_out_ep; /* Tx Endpoint assignments */
__u16 bulk_out_mtu; /* Max Tx packet size in bytes */
__u8 bulk_int_ep; /* Interrupt Endpoint assignments */
__u8 max_rx_urb;
struct urb **rx_urb; /* URBs used to receive data frames */
struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */
struct urb *tx_urb; /* URB used to send data frames */
struct urb *speed_urb; /* URB used to send speed commands */
struct net_device *netdev; /* Yes! we are some kind of netdev. */
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos;
char *speed_buff; /* Buffer for speed changes */
char *tx_buff;
struct timeval stamp;
struct timeval now;
spinlock_t lock; /* For serializing Tx operations */
__u16 xbofs; /* Current xbofs setting */
__s16 new_xbofs; /* xbofs we need to set */
__u32 speed; /* Current speed */
__s32 new_speed; /* speed we need to set */
__u8 header_length; /* USB-IrDA frame header size */
int needspatch; /* device needs firmware patch */
struct timer_list rx_defer_timer; /* Wait for Rx error to clear */
};

View file

@ -0,0 +1,580 @@
/*********************************************************************
*
* Filename: irtty-sir.c
* Version: 2.0
* Description: IrDA line discipline implementation
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
* Modified at: Sun Oct 27 22:13:30 2002
* Modified by: Martin Diehl <mad@mdiehl.de>
* Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
* Copyright (c) 1998-2000 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/kernel.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h>
#include "sir-dev.h"
#include "irtty-sir.h"
static int qos_mtt_bits = 0x03; /* 5 ms or more */
module_param(qos_mtt_bits, int, 0);
MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
/* ------------------------------------------------------- */
/* device configuration callbacks always invoked with irda-thread context */
/* find out, how many chars we have in buffers below us
* this is allowed to lie, i.e. return less chars than we
* actually have. The returned value is used to determine
* how long the irdathread should wait before doing the
* real blocking wait_until_sent()
*/
static int irtty_chars_in_buffer(struct sir_dev *dev)
{
struct sirtty_cb *priv = dev->priv;
IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
return tty_chars_in_buffer(priv->tty);
}
/* Wait (sleep) until underlaying hardware finished transmission
* i.e. hardware buffers are drained
* this must block and not return before all characters are really sent
*
* If the tty sits on top of a 16550A-like uart, there are typically
* up to 16 bytes in the fifo - f.e. 9600 bps 8N1 needs 16.7 msec
*
* With usbserial the uart-fifo is basically replaced by the converter's
* outgoing endpoint buffer, which can usually hold 64 bytes (at least).
* With pl2303 it appears we are safe with 60msec here.
*
* I really wish all serial drivers would provide
* correct implementation of wait_until_sent()
*/
#define USBSERIAL_TX_DONE_DELAY 60
static void irtty_wait_until_sent(struct sir_dev *dev)
{
struct sirtty_cb *priv = dev->priv;
struct tty_struct *tty;
IRDA_ASSERT(priv != NULL, return;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
tty = priv->tty;
if (tty->ops->wait_until_sent) {
tty->ops->wait_until_sent(tty, msecs_to_jiffies(100));
}
else {
msleep(USBSERIAL_TX_DONE_DELAY);
}
}
/*
* Function irtty_change_speed (dev, speed)
*
* Change the speed of the serial port.
*
* This may sleep in set_termios (usbserial driver f.e.) and must
* not be called from interrupt/timer/tasklet therefore.
* All such invocations are deferred to kIrDAd now so we can sleep there.
*/
static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
{
struct sirtty_cb *priv = dev->priv;
struct tty_struct *tty;
struct ktermios old_termios;
int cflag;
IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
tty = priv->tty;
down_write(&tty->termios_rwsem);
old_termios = tty->termios;
cflag = tty->termios.c_cflag;
tty_encode_baud_rate(tty, speed, speed);
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
priv->io.speed = speed;
up_write(&tty->termios_rwsem);
return 0;
}
/*
* Function irtty_set_dtr_rts (dev, dtr, rts)
*
* This function can be used by dongles etc. to set or reset the status
* of the dtr and rts lines
*/
static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
{
struct sirtty_cb *priv = dev->priv;
int set = 0;
int clear = 0;
IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
if (rts)
set |= TIOCM_RTS;
else
clear |= TIOCM_RTS;
if (dtr)
set |= TIOCM_DTR;
else
clear |= TIOCM_DTR;
/*
* We can't use ioctl() because it expects a non-null file structure,
* and we don't have that here.
* This function is not yet defined for all tty driver, so
* let's be careful... Jean II
*/
IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;);
priv->tty->ops->tiocmset(priv->tty, set, clear);
return 0;
}
/* ------------------------------------------------------- */
/* called from sir_dev when there is more data to send
* context is either netdev->hard_xmit or some transmit-completion bh
* i.e. we are under spinlock here and must not sleep.
*/
static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t len)
{
struct sirtty_cb *priv = dev->priv;
struct tty_struct *tty;
int writelen;
IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
tty = priv->tty;
if (!tty->ops->write)
return 0;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
writelen = tty_write_room(tty);
if (writelen > len)
writelen = len;
return tty->ops->write(tty, ptr, writelen);
}
/* ------------------------------------------------------- */
/* irda line discipline callbacks */
/*
* Function irtty_receive_buf( tty, cp, count)
*
* Handle the 'receiver data ready' interrupt. This function is called
* by the 'tty_io' module in the kernel when a block of IrDA data has
* been received, which can now be decapsulated and delivered for
* further processing
*
* calling context depends on underlying driver and tty->port->low_latency!
* for example (low_latency: 1 / 0):
* serial.c: uart-interrupt / softint
* usbserial: urb-complete-interrupt / softint
*/
static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
struct sir_dev *dev;
struct sirtty_cb *priv = tty->disc_data;
int i;
IRDA_ASSERT(priv != NULL, return;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
if (unlikely(count==0)) /* yes, this happens */
return;
dev = priv->dev;
if (!dev) {
IRDA_WARNING("%s(), not ready yet!\n", __func__);
return;
}
for (i = 0; i < count; i++) {
/*
* Characters received with a parity error, etc?
*/
if (fp && *fp++) {
IRDA_DEBUG(0, "Framing or parity error!\n");
sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */
return;
}
}
sirdev_receive(dev, cp, count);
}
/*
* Function irtty_write_wakeup (tty)
*
* Called by the driver when there's room for more data. If we have
* more packets to send, we send them here.
*
*/
static void irtty_write_wakeup(struct tty_struct *tty)
{
struct sirtty_cb *priv = tty->disc_data;
IRDA_ASSERT(priv != NULL, return;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (priv->dev)
sirdev_write_complete(priv->dev);
}
/* ------------------------------------------------------- */
/*
* Function irtty_stop_receiver (tty, stop)
*
*/
static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
{
struct ktermios old_termios;
int cflag;
down_write(&tty->termios_rwsem);
old_termios = tty->termios;
cflag = tty->termios.c_cflag;
if (stop)
cflag &= ~CREAD;
else
cflag |= CREAD;
tty->termios.c_cflag = cflag;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
up_write(&tty->termios_rwsem);
}
/*****************************************************************/
/* serialize ldisc open/close with sir_dev */
static DEFINE_MUTEX(irtty_mutex);
/* notifier from sir_dev when irda% device gets opened (ifup) */
static int irtty_start_dev(struct sir_dev *dev)
{
struct sirtty_cb *priv;
struct tty_struct *tty;
/* serialize with ldisc open/close */
mutex_lock(&irtty_mutex);
priv = dev->priv;
if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
mutex_unlock(&irtty_mutex);
return -ESTALE;
}
tty = priv->tty;
if (tty->ops->start)
tty->ops->start(tty);
/* Make sure we can receive more data */
irtty_stop_receiver(tty, FALSE);
mutex_unlock(&irtty_mutex);
return 0;
}
/* notifier from sir_dev when irda% device gets closed (ifdown) */
static int irtty_stop_dev(struct sir_dev *dev)
{
struct sirtty_cb *priv;
struct tty_struct *tty;
/* serialize with ldisc open/close */
mutex_lock(&irtty_mutex);
priv = dev->priv;
if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
mutex_unlock(&irtty_mutex);
return -ESTALE;
}
tty = priv->tty;
/* Make sure we don't receive more data */
irtty_stop_receiver(tty, TRUE);
if (tty->ops->stop)
tty->ops->stop(tty);
mutex_unlock(&irtty_mutex);
return 0;
}
/* ------------------------------------------------------- */
static struct sir_driver sir_tty_drv = {
.owner = THIS_MODULE,
.driver_name = "sir_tty",
.start_dev = irtty_start_dev,
.stop_dev = irtty_stop_dev,
.do_write = irtty_do_write,
.chars_in_buffer = irtty_chars_in_buffer,
.wait_until_sent = irtty_wait_until_sent,
.set_speed = irtty_change_speed,
.set_dtr_rts = irtty_set_dtr_rts,
};
/* ------------------------------------------------------- */
/*
* Function irtty_ioctl (tty, file, cmd, arg)
*
* The Swiss army knife of system calls :-)
*
*/
static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
struct irtty_info { char name[6]; } info;
struct sir_dev *dev;
struct sirtty_cb *priv = tty->disc_data;
int err = 0;
IRDA_ASSERT(priv != NULL, return -ENODEV;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;);
IRDA_DEBUG(3, "%s(cmd=0x%X)\n", __func__, cmd);
dev = priv->dev;
IRDA_ASSERT(dev != NULL, return -1;);
switch (cmd) {
case IRTTY_IOCTDONGLE:
/* this call blocks for completion */
err = sirdev_set_dongle(dev, (IRDA_DONGLE) arg);
break;
case IRTTY_IOCGET:
IRDA_ASSERT(dev->netdev != NULL, return -1;);
memset(&info, 0, sizeof(info));
strncpy(info.name, dev->netdev->name, sizeof(info.name)-1);
if (copy_to_user((void __user *)arg, &info, sizeof(info)))
err = -EFAULT;
break;
default:
err = tty_mode_ioctl(tty, file, cmd, arg);
break;
}
return err;
}
/*
* Function irtty_open(tty)
*
* This function is called by the TTY module when the IrDA line
* discipline is called for. Because we are sure the tty line exists,
* we only have to link it to a free IrDA channel.
*/
static int irtty_open(struct tty_struct *tty)
{
struct sir_dev *dev;
struct sirtty_cb *priv;
int ret = 0;
/* Module stuff handled via irda_ldisc.owner - Jean II */
/* First make sure we're not already connected. */
if (tty->disc_data != NULL) {
priv = tty->disc_data;
if (priv && priv->magic == IRTTY_MAGIC) {
ret = -EEXIST;
goto out;
}
tty->disc_data = NULL; /* ### */
}
/* stop the underlying driver */
irtty_stop_receiver(tty, TRUE);
if (tty->ops->stop)
tty->ops->stop(tty);
tty_driver_flush_buffer(tty);
/* apply mtt override */
sir_tty_drv.qos_mtt_bits = qos_mtt_bits;
/* get a sir device instance for this driver */
dev = sirdev_get_instance(&sir_tty_drv, tty->name);
if (!dev) {
ret = -ENODEV;
goto out;
}
/* allocate private device info block */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto out_put;
}
priv->magic = IRTTY_MAGIC;
priv->tty = tty;
priv->dev = dev;
/* serialize with start_dev - in case we were racing with ifup */
mutex_lock(&irtty_mutex);
dev->priv = priv;
tty->disc_data = priv;
tty->receive_room = 65536;
mutex_unlock(&irtty_mutex);
IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __func__, tty->name);
return 0;
out_put:
sirdev_put_instance(dev);
out:
return ret;
}
/*
* Function irtty_close (tty)
*
* Close down a IrDA channel. This means flushing out any pending queues,
* and then restoring the TTY line discipline to what it was before it got
* hooked to IrDA (which usually is TTY again).
*/
static void irtty_close(struct tty_struct *tty)
{
struct sirtty_cb *priv = tty->disc_data;
IRDA_ASSERT(priv != NULL, return;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
/* Hm, with a dongle attached the dongle driver wants
* to close the dongle - which requires the use of
* some tty write and/or termios or ioctl operations.
* Are we allowed to call those when already requested
* to shutdown the ldisc?
* If not, we should somehow mark the dev being staled.
* Question remains, how to close the dongle in this case...
* For now let's assume we are granted to issue tty driver calls
* until we return here from the ldisc close. I'm just wondering
* how this behaves with hotpluggable serial hardware like
* rs232-pcmcia card or usb-serial...
*
* priv->tty = NULL?;
*/
/* we are dead now */
tty->disc_data = NULL;
sirdev_put_instance(priv->dev);
/* Stop tty */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
if (tty->ops->stop)
tty->ops->stop(tty);
kfree(priv);
IRDA_DEBUG(0, "%s - %s: irda line discipline closed\n", __func__, tty->name);
}
/* ------------------------------------------------------- */
static struct tty_ldisc_ops irda_ldisc = {
.magic = TTY_LDISC_MAGIC,
.name = "irda",
.flags = 0,
.open = irtty_open,
.close = irtty_close,
.read = NULL,
.write = NULL,
.ioctl = irtty_ioctl,
.poll = NULL,
.receive_buf = irtty_receive_buf,
.write_wakeup = irtty_write_wakeup,
.owner = THIS_MODULE,
};
/* ------------------------------------------------------- */
static int __init irtty_sir_init(void)
{
int err;
if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)
IRDA_ERROR("IrDA: can't register line discipline (err = %d)\n",
err);
return err;
}
static void __exit irtty_sir_cleanup(void)
{
int err;
if ((err = tty_unregister_ldisc(N_IRDA))) {
IRDA_ERROR("%s(), can't unregister line discipline (err = %d)\n",
__func__, err);
}
}
module_init(irtty_sir_init);
module_exit(irtty_sir_cleanup);
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("IrDA TTY device driver");
MODULE_ALIAS_LDISC(N_IRDA);
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,34 @@
/*********************************************************************
*
* 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

View file

@ -0,0 +1,637 @@
/*****************************************************************************
*
* Filename: kingsun-sir.c
* Version: 0.1.1
* Description: Irda KingSun/DonShine USB Dongle
* Status: Experimental
* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
*
* Based on stir4200 and mcs7780 drivers, with (strange?) differences
*
* 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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*****************************************************************************/
/*
* This is my current (2007-04-25) understanding of how this dongle is supposed
* to work. This is based on reverse-engineering and examination of the packet
* data sent and received by the WinXP driver using USBSnoopy. Feel free to
* update here as more of this dongle is known:
*
* General: Unlike the other USB IrDA dongles, this particular dongle exposes,
* not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
* like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
* order to receive data.
* Transmission: Just like stir4200, this dongle uses a raw stream of data,
* which needs to be wrapped and escaped in a similar way as in stir4200.c.
* Reception: Poll-based, as in stir4200. Each read returns the contents of a
* 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
* (1-7) of valid data contained within the remaining 7 bytes. For example, if
* the buffer had the following contents:
* 06 ff ff ff c0 01 04 aa
* This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
* end is garbage (left over from a previous reception) and is discarded.
* If a read returns an "impossible" value as the length of valid data (such as
* 0x36) in the first byte, then the buffer is uninitialized (as is the case of
* first plug-in) and its contents should be discarded. There is currently no
* evidence that the top 5 bits of the 1st byte of the buffer can have values
* other than 0 once reception begins.
* Once valid bytes are collected, the assembled stream is a sequence of
* wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
* BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
* a successful read from the host, which means that in absence of further
* reception, repeated reads from the dongle will return the exact same
* contents repeatedly. Attempts to be smart and cache a previous read seem
* to result in corrupted packets, so this driver depends on the unwrap logic
* to sort out any repeated reads.
* Speed change: no commands observed so far to change speed, assumed fixed
* 9600bps (SIR).
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/device.h>
#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/crc.h>
/*
* According to lsusb, 0x07c0 is assigned to
* "Code Mercenaries Hard- und Software GmbH"
*/
#define KING_VENDOR_ID 0x07c0
#define KING_PRODUCT_ID 0x4200
/* These are the currently known USB ids */
static struct usb_device_id dongles[] = {
/* KingSun Co,Ltd IrDA/USB Bridge */
{ USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
{ }
};
MODULE_DEVICE_TABLE(usb, dongles);
#define KINGSUN_MTT 0x07
#define KINGSUN_FIFO_SIZE 4096
#define KINGSUN_EP_IN 0
#define KINGSUN_EP_OUT 1
struct kingsun_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 qos_info qos;
__u8 *in_buf; /* receive buffer */
__u8 *out_buf; /* transmit buffer */
__u8 max_rx; /* max. atomic read from dongle
(usually 8), also size of in_buf */
__u8 max_tx; /* max. atomic write to dongle
(usually 8) */
iobuff_t rx_buff; /* receive unwrap state machine */
struct timeval rx_time;
spinlock_t lock;
int receiving;
__u8 ep_in;
__u8 ep_out;
struct urb *tx_urb;
struct urb *rx_urb;
};
/* Callback transmission routine */
static void kingsun_send_irq(struct urb *urb)
{
struct kingsun_cb *kingsun = urb->context;
struct net_device *netdev = kingsun->netdev;
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
dev_err(&kingsun->usbdev->dev,
"kingsun_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
dev_err(&kingsun->usbdev->dev,
"kingsun_send_irq: urb asynchronously failed - %d\n",
urb->status);
}
netif_wake_queue(netdev);
}
/*
* Called from net/core when new frame is available.
*/
static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct kingsun_cb *kingsun;
int wraplen;
int ret = 0;
netif_stop_queue(netdev);
/* the IRDA wrapping routines don't deal with non linear skb */
SKB_LINEAR_ASSERT(skb);
kingsun = netdev_priv(netdev);
spin_lock(&kingsun->lock);
/* Append data to the end of whatever data remains to be transmitted */
wraplen = async_wrap_skb(skb,
kingsun->out_buf,
KINGSUN_FIFO_SIZE);
/* Calculate how much data can be transmitted in this urb */
usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
kingsun->out_buf, wraplen, kingsun_send_irq,
kingsun, 1);
if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
dev_err(&kingsun->usbdev->dev,
"kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
break;
default:
netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
} else {
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
spin_unlock(&kingsun->lock);
return NETDEV_TX_OK;
}
/* Receive callback function */
static void kingsun_rcv_irq(struct urb *urb)
{
struct kingsun_cb *kingsun = urb->context;
int ret;
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
kingsun->receiving = 0;
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
dev_err(&kingsun->usbdev->dev,
"kingsun_rcv_irq: urb asynchronously failed - %d\n",
urb->status);
kingsun->receiving = 0;
return;
}
if (urb->actual_length == kingsun->max_rx) {
__u8 *bytes = urb->transfer_buffer;
int i;
/* The very first byte in the buffer indicates the length of
valid data in the read. This byte must be in the range
1..kingsun->max_rx -1 . Values outside this range indicate
an uninitialized Rx buffer when the dongle has just been
plugged in. */
if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
for (i = 1; i <= bytes[0]; i++) {
async_unwrap_char(kingsun->netdev,
&kingsun->netdev->stats,
&kingsun->rx_buff, bytes[i]);
}
do_gettimeofday(&kingsun->rx_time);
kingsun->receiving =
(kingsun->rx_buff.state != OUTSIDE_FRAME)
? 1 : 0;
}
} else if (urb->actual_length > 0) {
dev_err(&kingsun->usbdev->dev,
"%s(): Unexpected response length, expected %d got %d\n",
__func__, kingsun->max_rx, urb->actual_length);
}
/* This urb has already been filled in kingsun_net_open */
ret = usb_submit_urb(urb, GFP_ATOMIC);
}
/*
* Function kingsun_net_open (dev)
*
* Network device is taken up. Usually this is done by "ifconfig irda0 up"
*/
static int kingsun_net_open(struct net_device *netdev)
{
struct kingsun_cb *kingsun = netdev_priv(netdev);
int err = -ENOMEM;
char hwname[16];
/* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
kingsun->receiving = 0;
/* Initialize for SIR to copy data directly into skb. */
kingsun->rx_buff.in_frame = FALSE;
kingsun->rx_buff.state = OUTSIDE_FRAME;
kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
if (!kingsun->rx_buff.skb)
goto free_mem;
skb_reserve(kingsun->rx_buff.skb, 1);
kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
do_gettimeofday(&kingsun->rx_time);
kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->rx_urb)
goto free_mem;
kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->tx_urb)
goto free_mem;
/*
* Now that everything should be initialized properly,
* Open new IrLAP layer instance to take care of us...
*/
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
/* Start first reception */
usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
kingsun->in_buf, kingsun->max_rx,
kingsun_rcv_irq, kingsun, 1);
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
dev_err(&kingsun->usbdev->dev,
"first urb-submit failed: %d\n", err);
goto close_irlap;
}
netif_start_queue(netdev);
/* Situation at this point:
- all work buffers allocated
- urbs allocated and ready to fill
- max rx packet known (in max_rx)
- unwrap state machine initialized, in state outside of any frame
- receive request in progress
- IrLAP layer started, about to hand over packets to send
*/
return 0;
close_irlap:
irlap_close(kingsun->irlap);
free_mem:
if (kingsun->tx_urb) {
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
}
if (kingsun->rx_urb) {
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
}
if (kingsun->rx_buff.skb) {
kfree_skb(kingsun->rx_buff.skb);
kingsun->rx_buff.skb = NULL;
kingsun->rx_buff.head = NULL;
}
return err;
}
/*
* Function kingsun_net_close (kingsun)
*
* Network device is taken down. Usually this is done by
* "ifconfig irda0 down"
*/
static int kingsun_net_close(struct net_device *netdev)
{
struct kingsun_cb *kingsun = netdev_priv(netdev);
/* Stop transmit processing */
netif_stop_queue(netdev);
/* Mop up receive && transmit urb's */
usb_kill_urb(kingsun->tx_urb);
usb_kill_urb(kingsun->rx_urb);
usb_free_urb(kingsun->tx_urb);
usb_free_urb(kingsun->rx_urb);
kingsun->tx_urb = NULL;
kingsun->rx_urb = NULL;
kfree_skb(kingsun->rx_buff.skb);
kingsun->rx_buff.skb = NULL;
kingsun->rx_buff.head = NULL;
kingsun->rx_buff.in_frame = FALSE;
kingsun->rx_buff.state = OUTSIDE_FRAME;
kingsun->receiving = 0;
/* Stop and remove instance of IrLAP */
if (kingsun->irlap)
irlap_close(kingsun->irlap);
kingsun->irlap = NULL;
return 0;
}
/*
* IOCTLs : Extra out-of-band network commands...
*/
static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *) rq;
struct kingsun_cb *kingsun = netdev_priv(netdev);
int ret = 0;
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Check if the device is still there */
if (netif_device_present(kingsun->netdev))
/* No observed commands for speed change */
ret = -EOPNOTSUPP;
break;
case SIOCSMEDIABUSY: /* Set media busy */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Check if the IrDA stack is still there */
if (netif_running(kingsun->netdev))
irda_device_set_media_busy(kingsun->netdev, TRUE);
break;
case SIOCGRECEIVING:
/* Only approximately true */
irq->ifr_receiving = kingsun->receiving;
break;
default:
ret = -EOPNOTSUPP;
}
return ret;
}
static const struct net_device_ops kingsun_ops = {
.ndo_start_xmit = kingsun_hard_xmit,
.ndo_open = kingsun_net_open,
.ndo_stop = kingsun_net_close,
.ndo_do_ioctl = kingsun_net_ioctl,
};
/*
* 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.
*/
static int kingsun_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *dev = interface_to_usbdev(intf);
struct kingsun_cb *kingsun = NULL;
struct net_device *net = NULL;
int ret = -ENOMEM;
int pipe, maxp_in, maxp_out;
__u8 ep_in;
__u8 ep_out;
/* Check that there really are two interrupt endpoints.
Check based on the one in drivers/usb/input/usbmouse.c
*/
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2) {
dev_err(&intf->dev,
"kingsun-sir: expected 2 endpoints, found %d\n",
interface->desc.bNumEndpoints);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
if (!usb_endpoint_is_int_in(endpoint)) {
dev_err(&intf->dev,
"kingsun-sir: endpoint 0 is not interrupt IN\n");
return -ENODEV;
}
ep_in = endpoint->bEndpointAddress;
pipe = usb_rcvintpipe(dev, ep_in);
maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp_in > 255 || maxp_in <= 1) {
dev_err(&intf->dev,
"endpoint 0 has max packet size %d not in range\n",
maxp_in);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
if (!usb_endpoint_is_int_out(endpoint)) {
dev_err(&intf->dev,
"kingsun-sir: endpoint 1 is not interrupt OUT\n");
return -ENODEV;
}
ep_out = endpoint->bEndpointAddress;
pipe = usb_sndintpipe(dev, ep_out);
maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
/* Allocate network device container. */
net = alloc_irdadev(sizeof(*kingsun));
if(!net)
goto err_out1;
SET_NETDEV_DEV(net, &intf->dev);
kingsun = netdev_priv(net);
kingsun->irlap = NULL;
kingsun->tx_urb = NULL;
kingsun->rx_urb = NULL;
kingsun->ep_in = ep_in;
kingsun->ep_out = ep_out;
kingsun->in_buf = NULL;
kingsun->out_buf = NULL;
kingsun->max_rx = (__u8)maxp_in;
kingsun->max_tx = (__u8)maxp_out;
kingsun->netdev = net;
kingsun->usbdev = dev;
kingsun->rx_buff.in_frame = FALSE;
kingsun->rx_buff.state = OUTSIDE_FRAME;
kingsun->rx_buff.skb = NULL;
kingsun->receiving = 0;
spin_lock_init(&kingsun->lock);
/* Allocate input buffer */
kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL);
if (!kingsun->in_buf)
goto free_mem;
/* Allocate output buffer */
kingsun->out_buf = kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
if (!kingsun->out_buf)
goto free_mem;
printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
"Vendor: %x, Product: %x\n",
dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&kingsun->qos);
/* That's the Rx capability. */
kingsun->qos.baud_rate.bits &= IR_9600;
kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
irda_qos_bits_to_value(&kingsun->qos);
/* Override the network functions we need to use */
net->netdev_ops = &kingsun_ops;
ret = register_netdev(net);
if (ret != 0)
goto free_mem;
dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n",
net->name);
usb_set_intfdata(intf, kingsun);
/* Situation at this point:
- all work buffers allocated
- urbs not allocated, set to NULL
- max rx packet known (in max_rx)
- unwrap state machine (partially) initialized, but skb == NULL
*/
return 0;
free_mem:
kfree(kingsun->out_buf);
kfree(kingsun->in_buf);
free_netdev(net);
err_out1:
return ret;
}
/*
* The current device is removed, the USB layer tell us to shut it down...
*/
static void kingsun_disconnect(struct usb_interface *intf)
{
struct kingsun_cb *kingsun = usb_get_intfdata(intf);
if (!kingsun)
return;
unregister_netdev(kingsun->netdev);
/* Mop up receive && transmit urb's */
if (kingsun->tx_urb != NULL) {
usb_kill_urb(kingsun->tx_urb);
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
}
if (kingsun->rx_urb != NULL) {
usb_kill_urb(kingsun->rx_urb);
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
}
kfree(kingsun->out_buf);
kfree(kingsun->in_buf);
free_netdev(kingsun->netdev);
usb_set_intfdata(intf, NULL);
}
#ifdef CONFIG_PM
/* USB suspend, so power off the transmitter/receiver */
static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
{
struct kingsun_cb *kingsun = usb_get_intfdata(intf);
netif_device_detach(kingsun->netdev);
if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
return 0;
}
/* Coming out of suspend, so reset hardware */
static int kingsun_resume(struct usb_interface *intf)
{
struct kingsun_cb *kingsun = usb_get_intfdata(intf);
if (kingsun->rx_urb != NULL)
usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
netif_device_attach(kingsun->netdev);
return 0;
}
#endif
/*
* USB device callbacks
*/
static struct usb_driver irda_driver = {
.name = "kingsun-sir",
.probe = kingsun_probe,
.disconnect = kingsun_disconnect,
.id_table = dongles,
#ifdef CONFIG_PM
.suspend = kingsun_suspend,
.resume = kingsun_resume,
#endif
};
module_usb_driver(irda_driver);
MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,915 @@
/*****************************************************************************
*
* Filename: ks959-sir.c
* Version: 0.1.2
* Description: Irda KingSun KS-959 USB Dongle
* Status: Experimental
* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
* with help from Domen Puncer <domen@coderock.org>
*
* Based on stir4200, mcs7780, kingsun-sir drivers.
*
* 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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*****************************************************************************/
/*
* Following is my most current (2007-07-17) understanding of how the Kingsun
* KS-959 dongle is supposed to work. This information was deduced by
* reverse-engineering and examining the USB traffic captured with USBSnoopy
* from the WinXP driver. Feel free to update here as more of the dongle is
* known.
*
* My most sincere thanks must go to Domen Puncer <domen@coderock.org> for
* invaluable help in cracking the obfuscation and padding required for this
* dongle.
*
* General: This dongle exposes one interface with one interrupt IN endpoint.
* However, the interrupt endpoint is NOT used at all for this dongle. Instead,
* this dongle uses control transfers for everything, including sending and
* receiving the IrDA frame data. Apparently the interrupt endpoint is just a
* dummy to ensure the dongle has a valid interface to present to the PC.And I
* thought the DonShine dongle was weird... In addition, this dongle uses
* obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent
* and received, from the dongle. I call it obfuscation because the XOR keying
* and padding required to produce an USB traffic acceptable for the dongle can
* not be explained by any other technical requirement.
*
* Transmission: To transmit an IrDA frame, the driver must prepare a control
* URB with the following as a setup packet:
* bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
* bRequest 0x09
* wValue <length of valid data before padding, little endian>
* wIndex 0x0000
* wLength <length of padded data>
* The payload packet must be manually wrapped and escaped (as in stir4200.c),
* then padded and obfuscated before being sent. Both padding and obfuscation
* are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the
* designer/programmer of the dongle used his name as a source for the
* obfuscation. WTF?!
* Apparently the dongle cannot handle payloads larger than 256 bytes. The
* driver has to perform fragmentation in order to send anything larger than
* this limit.
*
* Reception: To receive data, the driver must poll the dongle regularly (like
* kingsun-sir.c) with control URBs and the following as a setup packet:
* bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE
* bRequest 0x01
* wValue 0x0200
* wIndex 0x0000
* wLength 0x0800 (size of available buffer)
* If there is data to be read, it will be returned as the response payload.
* This data is (apparently) not padded, but it is obfuscated. To de-obfuscate
* it, the driver must XOR every byte, in sequence, with a value that starts at
* 1 and is incremented with each byte processed, and then with 0x55. The value
* incremented with each byte processed overflows as an unsigned char. The
* resulting bytes form a wrapped SIR frame that is unwrapped and unescaped
* as in stir4200.c The incremented value is NOT reset with each frame, but is
* kept across the entire session with the dongle. Also, the dongle inserts an
* extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which
* must be skipped.
*
* Speed change: To change the speed of the dongle, the driver prepares a
* control URB with the following as a setup packet:
* bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
* bRequest 0x09
* wValue 0x0200
* wIndex 0x0001
* wLength 0x0008 (length of the payload)
* The payload is a 8-byte record, apparently identical to the one used in
* drivers/usb/serial/cypress_m8.c to change speed:
* __u32 baudSpeed;
* unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
* unsigned int : 1;
* unsigned int stopBits : 1;
* unsigned int parityEnable : 1;
* unsigned int parityType : 1;
* unsigned int : 1;
* unsigned int reset : 1;
* unsigned char reserved[3]; // set to 0
*
* For now only SIR speeds have been observed with this dongle. Therefore,
* nothing is known on what changes (if any) must be done to frame wrapping /
* unwrapping for higher than SIR speeds. This driver assumes no change is
* necessary and announces support for all the way to 57600 bps. Although the
* package announces support for up to 4MBps, tests with a Sony Ericcson K300
* phone show corruption when receiving large frames at 115200 bps, the highest
* speed announced by the phone. However, transmission at 115200 bps is OK. Go
* figure. Since I don't know whether the phone or the dongle is at fault, max
* announced speed is 57600 bps until someone produces a device that can run
* at higher speeds with this dongle.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/device.h>
#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/crc.h>
#define KS959_VENDOR_ID 0x07d0
#define KS959_PRODUCT_ID 0x4959
/* These are the currently known USB ids */
static struct usb_device_id dongles[] = {
/* KingSun Co,Ltd IrDA/USB Bridge */
{USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)},
{}
};
MODULE_DEVICE_TABLE(usb, dongles);
#define KINGSUN_MTT 0x07
#define KINGSUN_REQ_RECV 0x01
#define KINGSUN_REQ_SEND 0x09
#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */
#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */
struct ks959_speedparams {
__le32 baudrate; /* baud rate, little endian */
__u8 flags;
__u8 reserved[3];
} __packed;
#define KS_DATA_5_BITS 0x00
#define KS_DATA_6_BITS 0x01
#define KS_DATA_7_BITS 0x02
#define KS_DATA_8_BITS 0x03
#define KS_STOP_BITS_1 0x00
#define KS_STOP_BITS_2 0x08
#define KS_PAR_DISABLE 0x00
#define KS_PAR_EVEN 0x10
#define KS_PAR_ODD 0x30
#define KS_RESET 0x80
struct ks959_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 qos_info qos;
struct usb_ctrlrequest *tx_setuprequest;
struct urb *tx_urb;
__u8 *tx_buf_clear;
unsigned int tx_buf_clear_used;
unsigned int tx_buf_clear_sent;
__u8 *tx_buf_xored;
struct usb_ctrlrequest *rx_setuprequest;
struct urb *rx_urb;
__u8 *rx_buf;
__u8 rx_variable_xormask;
iobuff_t rx_unwrap_buff;
struct timeval rx_time;
struct usb_ctrlrequest *speed_setuprequest;
struct urb *speed_urb;
struct ks959_speedparams speedparams;
unsigned int new_speed;
spinlock_t lock;
int receiving;
};
/* Procedure to perform the obfuscation/padding expected by the dongle
*
* buf_cleartext (IN) Cleartext version of the IrDA frame to transmit
* len_cleartext (IN) Length of the cleartext version of IrDA frame
* buf_xoredtext (OUT) Obfuscated version of frame built by proc
* len_maxbuf (OUT) Maximum space available at buf_xoredtext
*
* (return) length of obfuscated frame with padding
*
* If not enough space (as indicated by len_maxbuf vs. required padding),
* zero is returned
*
* The value of lookup_string is actually a required portion of the algorithm.
* Seems the designer of the dongle wanted to state who exactly is responsible
* for implementing obfuscation. Send your best (or other) wishes to him ]:-)
*/
static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext,
unsigned int len_cleartext,
__u8 * buf_xoredtext,
unsigned int len_maxbuf)
{
unsigned int len_xoredtext;
/* Calculate required length with padding, check for necessary space */
len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10;
if (len_xoredtext <= len_maxbuf) {
static const __u8 lookup_string[] = "wangshuofei19710";
__u8 xor_mask;
/* Unlike the WinXP driver, we *do* clear out the padding */
memset(buf_xoredtext, 0, len_xoredtext);
xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55;
while (len_cleartext-- > 0) {
*buf_xoredtext++ = *buf_cleartext++ ^ xor_mask;
}
} else {
len_xoredtext = 0;
}
return len_xoredtext;
}
/* Callback transmission routine */
static void ks959_speed_irq(struct urb *urb)
{
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
dev_err(&urb->dev->dev,
"ks959_speed_irq: urb asynchronously failed - %d\n",
urb->status);
}
}
/* Send a control request to change speed of the dongle */
static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed)
{
static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
57600, 115200, 576000, 1152000, 4000000, 0
};
int err;
unsigned int i;
if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
return -ENOMEM;
/* Check that requested speed is among the supported ones */
for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
if (supported_speeds[i] == 0)
return -EOPNOTSUPP;
memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams));
kingsun->speedparams.baudrate = cpu_to_le32(speed);
kingsun->speedparams.flags = KS_DATA_8_BITS;
/* speed_setuprequest pre-filled in ks959_probe */
usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
usb_sndctrlpipe(kingsun->usbdev, 0),
(unsigned char *)kingsun->speed_setuprequest,
&(kingsun->speedparams),
sizeof(struct ks959_speedparams), ks959_speed_irq,
kingsun);
kingsun->speed_urb->status = 0;
err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
return err;
}
/* Submit one fragment of an IrDA frame to the dongle */
static void ks959_send_irq(struct urb *urb);
static int ks959_submit_tx_fragment(struct ks959_cb *kingsun)
{
unsigned int padlen;
unsigned int wraplen;
int ret;
/* Check whether current plaintext can produce a padded buffer that fits
within the range handled by the dongle */
wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10;
if (wraplen > kingsun->tx_buf_clear_used)
wraplen = kingsun->tx_buf_clear_used;
/* Perform dongle obfuscation. Also remove the portion of the frame that
was just obfuscated and will now be sent to the dongle. */
padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen,
kingsun->tx_buf_xored,
KINGSUN_SND_PACKET_SIZE);
/* Calculate how much data can be transmitted in this urb */
kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen);
kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen);
/* Rest of the fields were filled in ks959_probe */
usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev,
usb_sndctrlpipe(kingsun->usbdev, 0),
(unsigned char *)kingsun->tx_setuprequest,
kingsun->tx_buf_xored, padlen,
ks959_send_irq, kingsun);
kingsun->tx_urb->status = 0;
ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
/* Remember how much data was sent, in order to update at callback */
kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
return ret;
}
/* Callback transmission routine */
static void ks959_send_irq(struct urb *urb)
{
struct ks959_cb *kingsun = urb->context;
struct net_device *netdev = kingsun->netdev;
int ret = 0;
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
dev_err(&kingsun->usbdev->dev,
"ks959_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
dev_err(&kingsun->usbdev->dev,
"ks959_send_irq: urb asynchronously failed - %d\n",
urb->status);
return;
}
if (kingsun->tx_buf_clear_used > 0) {
/* Update data remaining to be sent */
if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
memmove(kingsun->tx_buf_clear,
kingsun->tx_buf_clear +
kingsun->tx_buf_clear_sent,
kingsun->tx_buf_clear_used -
kingsun->tx_buf_clear_sent);
}
kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
kingsun->tx_buf_clear_sent = 0;
if (kingsun->tx_buf_clear_used > 0) {
/* There is more data to be sent */
if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
dev_err(&kingsun->usbdev->dev,
"ks959_send_irq: failed tx_urb submit: %d\n",
ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
break;
default:
netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
}
} else {
/* All data sent, send next speed && wake network queue */
if (kingsun->new_speed != -1 &&
cpu_to_le32(kingsun->new_speed) !=
kingsun->speedparams.baudrate)
ks959_change_speed(kingsun, kingsun->new_speed);
netif_wake_queue(netdev);
}
}
}
/*
* Called from net/core when new frame is available.
*/
static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct ks959_cb *kingsun;
unsigned int wraplen;
int ret = 0;
netif_stop_queue(netdev);
/* the IRDA wrapping routines don't deal with non linear skb */
SKB_LINEAR_ASSERT(skb);
kingsun = netdev_priv(netdev);
spin_lock(&kingsun->lock);
kingsun->new_speed = irda_get_next_speed(skb);
/* Append data to the end of whatever data remains to be transmitted */
wraplen =
async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
kingsun->tx_buf_clear_used = wraplen;
if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
dev_err(&kingsun->usbdev->dev,
"ks959_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
break;
default:
netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
} else {
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
spin_unlock(&kingsun->lock);
return NETDEV_TX_OK;
}
/* Receive callback function */
static void ks959_rcv_irq(struct urb *urb)
{
struct ks959_cb *kingsun = urb->context;
int ret;
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
kingsun->receiving = 0;
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
dev_err(&kingsun->usbdev->dev,
"kingsun_rcv_irq: urb asynchronously failed - %d\n",
urb->status);
kingsun->receiving = 0;
return;
}
if (urb->actual_length > 0) {
__u8 *bytes = urb->transfer_buffer;
unsigned int i;
for (i = 0; i < urb->actual_length; i++) {
/* De-obfuscation implemented here: variable portion of
xormask is incremented, and then used with the encoded
byte for the XOR. The result of the operation is used
to unwrap the SIR frame. */
kingsun->rx_variable_xormask++;
bytes[i] =
bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u;
/* rx_variable_xormask doubles as an index counter so we
can skip the byte at 0xff (wrapped around to 0).
*/
if (kingsun->rx_variable_xormask != 0) {
async_unwrap_char(kingsun->netdev,
&kingsun->netdev->stats,
&kingsun->rx_unwrap_buff,
bytes[i]);
}
}
do_gettimeofday(&kingsun->rx_time);
kingsun->receiving =
(kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
}
/* This urb has already been filled in kingsun_net_open. Setup
packet must be re-filled, but it is assumed that urb keeps the
pointer to the initial setup packet, as well as the payload buffer.
Setup packet is already pre-filled at ks959_probe.
*/
urb->status = 0;
ret = usb_submit_urb(urb, GFP_ATOMIC);
}
/*
* Function kingsun_net_open (dev)
*
* Network device is taken up. Usually this is done by "ifconfig irda0 up"
*/
static int ks959_net_open(struct net_device *netdev)
{
struct ks959_cb *kingsun = netdev_priv(netdev);
int err = -ENOMEM;
char hwname[16];
/* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
kingsun->receiving = 0;
/* Initialize for SIR to copy data directly into skb. */
kingsun->rx_unwrap_buff.in_frame = FALSE;
kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
if (!kingsun->rx_unwrap_buff.skb)
goto free_mem;
skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
do_gettimeofday(&kingsun->rx_time);
kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->rx_urb)
goto free_mem;
kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->tx_urb)
goto free_mem;
kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->speed_urb)
goto free_mem;
/* Initialize speed for dongle */
kingsun->new_speed = 9600;
err = ks959_change_speed(kingsun, 9600);
if (err < 0)
goto free_mem;
/*
* Now that everything should be initialized properly,
* Open new IrLAP layer instance to take care of us...
*/
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
err = -ENOMEM;
dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
/* Start reception. Setup request already pre-filled in ks959_probe */
usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev,
usb_rcvctrlpipe(kingsun->usbdev, 0),
(unsigned char *)kingsun->rx_setuprequest,
kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE,
ks959_rcv_irq, kingsun);
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
dev_err(&kingsun->usbdev->dev,
"first urb-submit failed: %d\n", err);
goto close_irlap;
}
netif_start_queue(netdev);
/* Situation at this point:
- all work buffers allocated
- urbs allocated and ready to fill
- max rx packet known (in max_rx)
- unwrap state machine initialized, in state outside of any frame
- receive request in progress
- IrLAP layer started, about to hand over packets to send
*/
return 0;
close_irlap:
irlap_close(kingsun->irlap);
free_mem:
usb_free_urb(kingsun->speed_urb);
kingsun->speed_urb = NULL;
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
if (kingsun->rx_unwrap_buff.skb) {
kfree_skb(kingsun->rx_unwrap_buff.skb);
kingsun->rx_unwrap_buff.skb = NULL;
kingsun->rx_unwrap_buff.head = NULL;
}
return err;
}
/*
* Function kingsun_net_close (kingsun)
*
* Network device is taken down. Usually this is done by
* "ifconfig irda0 down"
*/
static int ks959_net_close(struct net_device *netdev)
{
struct ks959_cb *kingsun = netdev_priv(netdev);
/* Stop transmit processing */
netif_stop_queue(netdev);
/* Mop up receive && transmit urb's */
usb_kill_urb(kingsun->tx_urb);
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
usb_kill_urb(kingsun->speed_urb);
usb_free_urb(kingsun->speed_urb);
kingsun->speed_urb = NULL;
usb_kill_urb(kingsun->rx_urb);
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
kfree_skb(kingsun->rx_unwrap_buff.skb);
kingsun->rx_unwrap_buff.skb = NULL;
kingsun->rx_unwrap_buff.head = NULL;
kingsun->rx_unwrap_buff.in_frame = FALSE;
kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
kingsun->receiving = 0;
/* Stop and remove instance of IrLAP */
if (kingsun->irlap)
irlap_close(kingsun->irlap);
kingsun->irlap = NULL;
return 0;
}
/*
* IOCTLs : Extra out-of-band network commands...
*/
static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *)rq;
struct ks959_cb *kingsun = netdev_priv(netdev);
int ret = 0;
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Check if the device is still there */
if (netif_device_present(kingsun->netdev))
return ks959_change_speed(kingsun, irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Check if the IrDA stack is still there */
if (netif_running(kingsun->netdev))
irda_device_set_media_busy(kingsun->netdev, TRUE);
break;
case SIOCGRECEIVING:
/* Only approximately true */
irq->ifr_receiving = kingsun->receiving;
break;
default:
ret = -EOPNOTSUPP;
}
return ret;
}
static const struct net_device_ops ks959_ops = {
.ndo_start_xmit = ks959_hard_xmit,
.ndo_open = ks959_net_open,
.ndo_stop = ks959_net_close,
.ndo_do_ioctl = ks959_net_ioctl,
};
/*
* 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.
*/
static int ks959_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct ks959_cb *kingsun = NULL;
struct net_device *net = NULL;
int ret = -ENOMEM;
/* Allocate network device container. */
net = alloc_irdadev(sizeof(*kingsun));
if (!net)
goto err_out1;
SET_NETDEV_DEV(net, &intf->dev);
kingsun = netdev_priv(net);
kingsun->netdev = net;
kingsun->usbdev = dev;
kingsun->irlap = NULL;
kingsun->tx_setuprequest = NULL;
kingsun->tx_urb = NULL;
kingsun->tx_buf_clear = NULL;
kingsun->tx_buf_xored = NULL;
kingsun->tx_buf_clear_used = 0;
kingsun->tx_buf_clear_sent = 0;
kingsun->rx_setuprequest = NULL;
kingsun->rx_urb = NULL;
kingsun->rx_buf = NULL;
kingsun->rx_variable_xormask = 0;
kingsun->rx_unwrap_buff.in_frame = FALSE;
kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
kingsun->rx_unwrap_buff.skb = NULL;
kingsun->receiving = 0;
spin_lock_init(&kingsun->lock);
kingsun->speed_setuprequest = NULL;
kingsun->speed_urb = NULL;
kingsun->speedparams.baudrate = 0;
/* Allocate input buffer */
kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL);
if (!kingsun->rx_buf)
goto free_mem;
/* Allocate input setup packet */
kingsun->rx_setuprequest =
kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!kingsun->rx_setuprequest)
goto free_mem;
kingsun->rx_setuprequest->bRequestType =
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV;
kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200);
kingsun->rx_setuprequest->wIndex = 0;
kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE);
/* Allocate output buffer */
kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
if (!kingsun->tx_buf_clear)
goto free_mem;
kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL);
if (!kingsun->tx_buf_xored)
goto free_mem;
/* Allocate and initialize output setup packet */
kingsun->tx_setuprequest =
kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!kingsun->tx_setuprequest)
goto free_mem;
kingsun->tx_setuprequest->bRequestType =
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND;
kingsun->tx_setuprequest->wValue = 0;
kingsun->tx_setuprequest->wIndex = 0;
kingsun->tx_setuprequest->wLength = 0;
/* Allocate and initialize speed setup packet */
kingsun->speed_setuprequest =
kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!kingsun->speed_setuprequest)
goto free_mem;
kingsun->speed_setuprequest->bRequestType =
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
kingsun->speed_setuprequest->wLength =
cpu_to_le16(sizeof(struct ks959_speedparams));
printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, "
"Vendor: %x, Product: %x\n",
dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&kingsun->qos);
/* Baud rates known to be supported. Please uncomment if devices (other
than a SonyEriccson K300 phone) can be shown to support higher speed
with this dongle.
*/
kingsun->qos.baud_rate.bits =
IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600;
kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
irda_qos_bits_to_value(&kingsun->qos);
/* Override the network functions we need to use */
net->netdev_ops = &ks959_ops;
ret = register_netdev(net);
if (ret != 0)
goto free_mem;
dev_info(&net->dev, "IrDA: Registered KingSun KS-959 device %s\n",
net->name);
usb_set_intfdata(intf, kingsun);
/* Situation at this point:
- all work buffers allocated
- setup requests pre-filled
- urbs not allocated, set to NULL
- max rx packet known (is KINGSUN_FIFO_SIZE)
- unwrap state machine (partially) initialized, but skb == NULL
*/
return 0;
free_mem:
kfree(kingsun->speed_setuprequest);
kfree(kingsun->tx_setuprequest);
kfree(kingsun->tx_buf_xored);
kfree(kingsun->tx_buf_clear);
kfree(kingsun->rx_setuprequest);
kfree(kingsun->rx_buf);
free_netdev(net);
err_out1:
return ret;
}
/*
* The current device is removed, the USB layer tell us to shut it down...
*/
static void ks959_disconnect(struct usb_interface *intf)
{
struct ks959_cb *kingsun = usb_get_intfdata(intf);
if (!kingsun)
return;
unregister_netdev(kingsun->netdev);
/* Mop up receive && transmit urb's */
if (kingsun->speed_urb != NULL) {
usb_kill_urb(kingsun->speed_urb);
usb_free_urb(kingsun->speed_urb);
kingsun->speed_urb = NULL;
}
if (kingsun->tx_urb != NULL) {
usb_kill_urb(kingsun->tx_urb);
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
}
if (kingsun->rx_urb != NULL) {
usb_kill_urb(kingsun->rx_urb);
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
}
kfree(kingsun->speed_setuprequest);
kfree(kingsun->tx_setuprequest);
kfree(kingsun->tx_buf_xored);
kfree(kingsun->tx_buf_clear);
kfree(kingsun->rx_setuprequest);
kfree(kingsun->rx_buf);
free_netdev(kingsun->netdev);
usb_set_intfdata(intf, NULL);
}
#ifdef CONFIG_PM
/* USB suspend, so power off the transmitter/receiver */
static int ks959_suspend(struct usb_interface *intf, pm_message_t message)
{
struct ks959_cb *kingsun = usb_get_intfdata(intf);
netif_device_detach(kingsun->netdev);
if (kingsun->speed_urb != NULL)
usb_kill_urb(kingsun->speed_urb);
if (kingsun->tx_urb != NULL)
usb_kill_urb(kingsun->tx_urb);
if (kingsun->rx_urb != NULL)
usb_kill_urb(kingsun->rx_urb);
return 0;
}
/* Coming out of suspend, so reset hardware */
static int ks959_resume(struct usb_interface *intf)
{
struct ks959_cb *kingsun = usb_get_intfdata(intf);
if (kingsun->rx_urb != NULL) {
/* Setup request already filled in ks959_probe */
usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
}
netif_device_attach(kingsun->netdev);
return 0;
}
#endif
/*
* USB device callbacks
*/
static struct usb_driver irda_driver = {
.name = "ks959-sir",
.probe = ks959_probe,
.disconnect = ks959_disconnect,
.id_table = dongles,
#ifdef CONFIG_PM
.suspend = ks959_suspend,
.resume = ks959_resume,
#endif
};
module_usb_driver(irda_driver);
MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,813 @@
/*****************************************************************************
*
* Filename: ksdazzle.c
* Version: 0.1.2
* Description: Irda KingSun Dazzle USB Dongle
* Status: Experimental
* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
*
* Based on stir4200, mcs7780, kingsun-sir drivers.
*
* 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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*****************************************************************************/
/*
* Following is my most current (2007-07-26) understanding of how the Kingsun
* 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This
* information was deduced by examining the USB traffic captured with USBSnoopy
* from the WinXP driver. Feel free to update here as more of the dongle is
* known.
*
* General: This dongle exposes one interface with two interrupt endpoints, one
* IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine
* dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and
* unwrapped manually as in stir4200, kingsun-sir, and ks959-sir.
*
* Transmission: To transmit an IrDA frame, it is necessary to wrap it, then
* split it into multiple segments of up to 7 bytes each, and transmit each in
* sequence. It seems that sending a single big block (like kingsun-sir does)
* won't work with this dongle. Each segment needs to be prefixed with a value
* equal to (unsigned char)0xF8 + <number of bytes in segment>, inside a payload
* of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9,
* and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the
* payload, not considered by the prefix, are ignored (set to 0 by this
* implementation).
*
* Reception: To receive data, the driver must poll the dongle regularly (like
* kingsun-sir.c) with interrupt URBs. If data is available, it will be returned
* in payloads from 0 to 8 bytes long. When concatenated, these payloads form
* a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir
*
* Speed change: To change the speed of the dongle, the driver prepares a
* control URB with the following as a setup packet:
* bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
* bRequest 0x09
* wValue 0x0200
* wIndex 0x0001
* wLength 0x0008 (length of the payload)
* The payload is a 8-byte record, apparently identical to the one used in
* drivers/usb/serial/cypress_m8.c to change speed:
* __u32 baudSpeed;
* unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
* unsigned int : 1;
* unsigned int stopBits : 1;
* unsigned int parityEnable : 1;
* unsigned int parityType : 1;
* unsigned int : 1;
* unsigned int reset : 1;
* unsigned char reserved[3]; // set to 0
*
* For now only SIR speeds have been observed with this dongle. Therefore,
* nothing is known on what changes (if any) must be done to frame wrapping /
* unwrapping for higher than SIR speeds. This driver assumes no change is
* necessary and announces support for all the way to 115200 bps.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/device.h>
#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/crc.h>
#define KSDAZZLE_VENDOR_ID 0x07d0
#define KSDAZZLE_PRODUCT_ID 0x4100
/* These are the currently known USB ids */
static struct usb_device_id dongles[] = {
/* KingSun Co,Ltd IrDA/USB Bridge */
{USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)},
{}
};
MODULE_DEVICE_TABLE(usb, dongles);
#define KINGSUN_MTT 0x07
#define KINGSUN_REQ_RECV 0x01
#define KINGSUN_REQ_SEND 0x09
#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */
struct ksdazzle_speedparams {
__le32 baudrate; /* baud rate, little endian */
__u8 flags;
__u8 reserved[3];
} __packed;
#define KS_DATA_5_BITS 0x00
#define KS_DATA_6_BITS 0x01
#define KS_DATA_7_BITS 0x02
#define KS_DATA_8_BITS 0x03
#define KS_STOP_BITS_1 0x00
#define KS_STOP_BITS_2 0x08
#define KS_PAR_DISABLE 0x00
#define KS_PAR_EVEN 0x10
#define KS_PAR_ODD 0x30
#define KS_RESET 0x80
#define KINGSUN_EP_IN 0
#define KINGSUN_EP_OUT 1
struct ksdazzle_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 qos_info qos;
struct urb *tx_urb;
__u8 *tx_buf_clear;
unsigned int tx_buf_clear_used;
unsigned int tx_buf_clear_sent;
__u8 tx_payload[8];
struct urb *rx_urb;
__u8 *rx_buf;
iobuff_t rx_unwrap_buff;
struct usb_ctrlrequest *speed_setuprequest;
struct urb *speed_urb;
struct ksdazzle_speedparams speedparams;
unsigned int new_speed;
__u8 ep_in;
__u8 ep_out;
spinlock_t lock;
int receiving;
};
/* Callback transmission routine */
static void ksdazzle_speed_irq(struct urb *urb)
{
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0)
dev_err(&urb->dev->dev,
"ksdazzle_speed_irq: urb asynchronously failed - %d\n",
urb->status);
}
/* Send a control request to change speed of the dongle */
static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed)
{
static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
57600, 115200, 576000, 1152000, 4000000, 0
};
int err;
unsigned int i;
if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
return -ENOMEM;
/* Check that requested speed is among the supported ones */
for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
if (supported_speeds[i] == 0)
return -EOPNOTSUPP;
memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams));
kingsun->speedparams.baudrate = cpu_to_le32(speed);
kingsun->speedparams.flags = KS_DATA_8_BITS;
/* speed_setuprequest pre-filled in ksdazzle_probe */
usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
usb_sndctrlpipe(kingsun->usbdev, 0),
(unsigned char *)kingsun->speed_setuprequest,
&(kingsun->speedparams),
sizeof(struct ksdazzle_speedparams),
ksdazzle_speed_irq, kingsun);
kingsun->speed_urb->status = 0;
err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
return err;
}
/* Submit one fragment of an IrDA frame to the dongle */
static void ksdazzle_send_irq(struct urb *urb);
static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun)
{
unsigned int wraplen;
int ret;
/* We can send at most 7 bytes of payload at a time */
wraplen = 7;
if (wraplen > kingsun->tx_buf_clear_used)
wraplen = kingsun->tx_buf_clear_used;
/* Prepare payload prefix with used length */
memset(kingsun->tx_payload, 0, 8);
kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen;
memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen);
usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1);
kingsun->tx_urb->status = 0;
ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
/* Remember how much data was sent, in order to update at callback */
kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
return ret;
}
/* Callback transmission routine */
static void ksdazzle_send_irq(struct urb *urb)
{
struct ksdazzle_cb *kingsun = urb->context;
struct net_device *netdev = kingsun->netdev;
int ret = 0;
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
dev_err(&kingsun->usbdev->dev,
"ksdazzle_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
dev_err(&kingsun->usbdev->dev,
"ksdazzle_send_irq: urb asynchronously failed - %d\n",
urb->status);
return;
}
if (kingsun->tx_buf_clear_used > 0) {
/* Update data remaining to be sent */
if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
memmove(kingsun->tx_buf_clear,
kingsun->tx_buf_clear +
kingsun->tx_buf_clear_sent,
kingsun->tx_buf_clear_used -
kingsun->tx_buf_clear_sent);
}
kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
kingsun->tx_buf_clear_sent = 0;
if (kingsun->tx_buf_clear_used > 0) {
/* There is more data to be sent */
if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
dev_err(&kingsun->usbdev->dev,
"ksdazzle_send_irq: failed tx_urb submit: %d\n",
ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
break;
default:
netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
}
} else {
/* All data sent, send next speed && wake network queue */
if (kingsun->new_speed != -1 &&
cpu_to_le32(kingsun->new_speed) !=
kingsun->speedparams.baudrate)
ksdazzle_change_speed(kingsun,
kingsun->new_speed);
netif_wake_queue(netdev);
}
}
}
/*
* Called from net/core when new frame is available.
*/
static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct ksdazzle_cb *kingsun;
unsigned int wraplen;
int ret = 0;
netif_stop_queue(netdev);
/* the IRDA wrapping routines don't deal with non linear skb */
SKB_LINEAR_ASSERT(skb);
kingsun = netdev_priv(netdev);
spin_lock(&kingsun->lock);
kingsun->new_speed = irda_get_next_speed(skb);
/* Append data to the end of whatever data remains to be transmitted */
wraplen =
async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
kingsun->tx_buf_clear_used = wraplen;
if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
dev_err(&kingsun->usbdev->dev,
"ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
break;
default:
netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
} else {
netdev->stats.tx_packets++;
netdev->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
spin_unlock(&kingsun->lock);
return NETDEV_TX_OK;
}
/* Receive callback function */
static void ksdazzle_rcv_irq(struct urb *urb)
{
struct ksdazzle_cb *kingsun = urb->context;
struct net_device *netdev = kingsun->netdev;
/* in process of stopping, just drop data */
if (!netif_running(netdev)) {
kingsun->receiving = 0;
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
dev_err(&kingsun->usbdev->dev,
"ksdazzle_rcv_irq: urb asynchronously failed - %d\n",
urb->status);
kingsun->receiving = 0;
return;
}
if (urb->actual_length > 0) {
__u8 *bytes = urb->transfer_buffer;
unsigned int i;
for (i = 0; i < urb->actual_length; i++) {
async_unwrap_char(netdev, &netdev->stats,
&kingsun->rx_unwrap_buff, bytes[i]);
}
kingsun->receiving =
(kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
}
/* This urb has already been filled in ksdazzle_net_open. It is assumed that
urb keeps the pointer to the payload buffer.
*/
urb->status = 0;
usb_submit_urb(urb, GFP_ATOMIC);
}
/*
* Function ksdazzle_net_open (dev)
*
* Network device is taken up. Usually this is done by "ifconfig irda0 up"
*/
static int ksdazzle_net_open(struct net_device *netdev)
{
struct ksdazzle_cb *kingsun = netdev_priv(netdev);
int err = -ENOMEM;
char hwname[16];
/* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */
kingsun->receiving = 0;
/* Initialize for SIR to copy data directly into skb. */
kingsun->rx_unwrap_buff.in_frame = FALSE;
kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
if (!kingsun->rx_unwrap_buff.skb)
goto free_mem;
skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->rx_urb)
goto free_mem;
kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->tx_urb)
goto free_mem;
kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->speed_urb)
goto free_mem;
/* Initialize speed for dongle */
kingsun->new_speed = 9600;
err = ksdazzle_change_speed(kingsun, 9600);
if (err < 0)
goto free_mem;
/*
* Now that everything should be initialized properly,
* Open new IrLAP layer instance to take care of us...
*/
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
err = -ENOMEM;
dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
/* Start reception. */
usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq,
kingsun, 1);
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err);
goto close_irlap;
}
netif_start_queue(netdev);
/* Situation at this point:
- all work buffers allocated
- urbs allocated and ready to fill
- max rx packet known (in max_rx)
- unwrap state machine initialized, in state outside of any frame
- receive request in progress
- IrLAP layer started, about to hand over packets to send
*/
return 0;
close_irlap:
irlap_close(kingsun->irlap);
free_mem:
usb_free_urb(kingsun->speed_urb);
kingsun->speed_urb = NULL;
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
if (kingsun->rx_unwrap_buff.skb) {
kfree_skb(kingsun->rx_unwrap_buff.skb);
kingsun->rx_unwrap_buff.skb = NULL;
kingsun->rx_unwrap_buff.head = NULL;
}
return err;
}
/*
* Function ksdazzle_net_close (dev)
*
* Network device is taken down. Usually this is done by
* "ifconfig irda0 down"
*/
static int ksdazzle_net_close(struct net_device *netdev)
{
struct ksdazzle_cb *kingsun = netdev_priv(netdev);
/* Stop transmit processing */
netif_stop_queue(netdev);
/* Mop up receive && transmit urb's */
usb_kill_urb(kingsun->tx_urb);
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
usb_kill_urb(kingsun->speed_urb);
usb_free_urb(kingsun->speed_urb);
kingsun->speed_urb = NULL;
usb_kill_urb(kingsun->rx_urb);
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
kfree_skb(kingsun->rx_unwrap_buff.skb);
kingsun->rx_unwrap_buff.skb = NULL;
kingsun->rx_unwrap_buff.head = NULL;
kingsun->rx_unwrap_buff.in_frame = FALSE;
kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
kingsun->receiving = 0;
/* Stop and remove instance of IrLAP */
irlap_close(kingsun->irlap);
kingsun->irlap = NULL;
return 0;
}
/*
* IOCTLs : Extra out-of-band network commands...
*/
static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq,
int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *)rq;
struct ksdazzle_cb *kingsun = netdev_priv(netdev);
int ret = 0;
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Check if the device is still there */
if (netif_device_present(kingsun->netdev))
return ksdazzle_change_speed(kingsun,
irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Check if the IrDA stack is still there */
if (netif_running(kingsun->netdev))
irda_device_set_media_busy(kingsun->netdev, TRUE);
break;
case SIOCGRECEIVING:
/* Only approximately true */
irq->ifr_receiving = kingsun->receiving;
break;
default:
ret = -EOPNOTSUPP;
}
return ret;
}
static const struct net_device_ops ksdazzle_ops = {
.ndo_start_xmit = ksdazzle_hard_xmit,
.ndo_open = ksdazzle_net_open,
.ndo_stop = ksdazzle_net_close,
.ndo_do_ioctl = ksdazzle_net_ioctl,
};
/*
* 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.
*/
static int ksdazzle_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *dev = interface_to_usbdev(intf);
struct ksdazzle_cb *kingsun = NULL;
struct net_device *net = NULL;
int ret = -ENOMEM;
int pipe, maxp_in, maxp_out;
__u8 ep_in;
__u8 ep_out;
/* Check that there really are two interrupt endpoints. Check based on the
one in drivers/usb/input/usbmouse.c
*/
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2) {
dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n",
interface->desc.bNumEndpoints);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
if (!usb_endpoint_is_int_in(endpoint)) {
dev_err(&intf->dev,
"ksdazzle: endpoint 0 is not interrupt IN\n");
return -ENODEV;
}
ep_in = endpoint->bEndpointAddress;
pipe = usb_rcvintpipe(dev, ep_in);
maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp_in > 255 || maxp_in <= 1) {
dev_err(&intf->dev,
"ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n",
maxp_in);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
if (!usb_endpoint_is_int_out(endpoint)) {
dev_err(&intf->dev,
"ksdazzle: endpoint 1 is not interrupt OUT\n");
return -ENODEV;
}
ep_out = endpoint->bEndpointAddress;
pipe = usb_sndintpipe(dev, ep_out);
maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
/* Allocate network device container. */
net = alloc_irdadev(sizeof(*kingsun));
if (!net)
goto err_out1;
SET_NETDEV_DEV(net, &intf->dev);
kingsun = netdev_priv(net);
kingsun->netdev = net;
kingsun->usbdev = dev;
kingsun->ep_in = ep_in;
kingsun->ep_out = ep_out;
kingsun->irlap = NULL;
kingsun->tx_urb = NULL;
kingsun->tx_buf_clear = NULL;
kingsun->tx_buf_clear_used = 0;
kingsun->tx_buf_clear_sent = 0;
kingsun->rx_urb = NULL;
kingsun->rx_buf = NULL;
kingsun->rx_unwrap_buff.in_frame = FALSE;
kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
kingsun->rx_unwrap_buff.skb = NULL;
kingsun->receiving = 0;
spin_lock_init(&kingsun->lock);
kingsun->speed_setuprequest = NULL;
kingsun->speed_urb = NULL;
kingsun->speedparams.baudrate = 0;
/* Allocate input buffer */
kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL);
if (!kingsun->rx_buf)
goto free_mem;
/* Allocate output buffer */
kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
if (!kingsun->tx_buf_clear)
goto free_mem;
/* Allocate and initialize speed setup packet */
kingsun->speed_setuprequest =
kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!kingsun->speed_setuprequest)
goto free_mem;
kingsun->speed_setuprequest->bRequestType =
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
kingsun->speed_setuprequest->wLength =
cpu_to_le16(sizeof(struct ksdazzle_speedparams));
printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, "
"Vendor: %x, Product: %x\n",
dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&kingsun->qos);
/* Baud rates known to be supported. Please uncomment if devices (other
than a SonyEriccson K300 phone) can be shown to support higher speeds
with this dongle.
*/
kingsun->qos.baud_rate.bits =
IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
irda_qos_bits_to_value(&kingsun->qos);
/* Override the network functions we need to use */
net->netdev_ops = &ksdazzle_ops;
ret = register_netdev(net);
if (ret != 0)
goto free_mem;
dev_info(&net->dev, "IrDA: Registered KingSun/Dazzle device %s\n",
net->name);
usb_set_intfdata(intf, kingsun);
/* Situation at this point:
- all work buffers allocated
- setup requests pre-filled
- urbs not allocated, set to NULL
- max rx packet known (is KINGSUN_FIFO_SIZE)
- unwrap state machine (partially) initialized, but skb == NULL
*/
return 0;
free_mem:
kfree(kingsun->speed_setuprequest);
kfree(kingsun->tx_buf_clear);
kfree(kingsun->rx_buf);
free_netdev(net);
err_out1:
return ret;
}
/*
* The current device is removed, the USB layer tell us to shut it down...
*/
static void ksdazzle_disconnect(struct usb_interface *intf)
{
struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
if (!kingsun)
return;
unregister_netdev(kingsun->netdev);
/* Mop up receive && transmit urb's */
usb_kill_urb(kingsun->speed_urb);
usb_free_urb(kingsun->speed_urb);
kingsun->speed_urb = NULL;
usb_kill_urb(kingsun->tx_urb);
usb_free_urb(kingsun->tx_urb);
kingsun->tx_urb = NULL;
usb_kill_urb(kingsun->rx_urb);
usb_free_urb(kingsun->rx_urb);
kingsun->rx_urb = NULL;
kfree(kingsun->speed_setuprequest);
kfree(kingsun->tx_buf_clear);
kfree(kingsun->rx_buf);
free_netdev(kingsun->netdev);
usb_set_intfdata(intf, NULL);
}
#ifdef CONFIG_PM
/* USB suspend, so power off the transmitter/receiver */
static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message)
{
struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
netif_device_detach(kingsun->netdev);
if (kingsun->speed_urb != NULL)
usb_kill_urb(kingsun->speed_urb);
if (kingsun->tx_urb != NULL)
usb_kill_urb(kingsun->tx_urb);
if (kingsun->rx_urb != NULL)
usb_kill_urb(kingsun->rx_urb);
return 0;
}
/* Coming out of suspend, so reset hardware */
static int ksdazzle_resume(struct usb_interface *intf)
{
struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
if (kingsun->rx_urb != NULL) {
/* Setup request already filled in ksdazzle_probe */
usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
}
netif_device_attach(kingsun->netdev);
return 0;
}
#endif
/*
* USB device callbacks
*/
static struct usb_driver irda_driver = {
.name = "ksdazzle-sir",
.probe = ksdazzle_probe,
.disconnect = ksdazzle_disconnect,
.id_table = dongles,
#ifdef CONFIG_PM
.suspend = ksdazzle_suspend,
.resume = ksdazzle_resume,
#endif
};
module_usb_driver(irda_driver);
MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,207 @@
/*********************************************************************
*
* Filename: litelink.c
* Version: 1.1
* Description: Driver for the Parallax LiteLink dongle
* Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Fri May 7 12:50:33 1999
* Modified at: Fri Dec 17 09:14:23 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, 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, see <http://www.gnu.org/licenses/>.
*
********************************************************************/
/*
* Modified at: Thu Jan 15 2003
* Modified by: Eugene Crosser <crosser@average.org>
*
* Convert to "new" IRDA infrastructure for kernel 2.6
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
#define MAX_DELAY 10000 /* 1 ms */
static int litelink_open(struct sir_dev *dev);
static int litelink_close(struct sir_dev *dev);
static int litelink_change_speed(struct sir_dev *dev, unsigned speed);
static int litelink_reset(struct sir_dev *dev);
/* These are the baudrates supported - 9600 must be last one! */
static unsigned baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
static struct dongle_driver litelink = {
.owner = THIS_MODULE,
.driver_name = "Parallax LiteLink",
.type = IRDA_LITELINK_DONGLE,
.open = litelink_open,
.close = litelink_close,
.reset = litelink_reset,
.set_speed = litelink_change_speed,
};
static int __init litelink_sir_init(void)
{
return irda_register_dongle(&litelink);
}
static void __exit litelink_sir_cleanup(void)
{
irda_unregister_dongle(&litelink);
}
static int litelink_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power up dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Set the speeds we can accept */
qos->baud_rate.bits &= IR_115200|IR_57600|IR_38400|IR_19200|IR_9600;
qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
irda_qos_bits_to_value(qos);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int litelink_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function litelink_change_speed (task)
*
* Change speed of the Litelink dongle. To cycle through the available
* baud rates, pulse RTS low for a few ms.
*/
static int litelink_change_speed(struct sir_dev *dev, unsigned speed)
{
int i;
IRDA_DEBUG(2, "%s()\n", __func__);
/* dongle already reset by irda-thread - current speed (dongle and
* port) is the default speed (115200 for litelink!)
*/
/* Cycle through avaiable baudrates until we reach the correct one */
for (i = 0; baud_rates[i] != speed; i++) {
/* end-of-list reached due to invalid speed request */
if (baud_rates[i] == 9600)
break;
/* Set DTR, clear RTS */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
/* Sleep a minimum of 15 us */
udelay(MIN_DELAY);
/* Set DTR, Set RTS */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Sleep a minimum of 15 us */
udelay(MIN_DELAY);
}
dev->speed = baud_rates[i];
/* invalid baudrate should not happen - but if, we return -EINVAL and
* the dongle configured for 9600 so the stack has a chance to recover
*/
return (dev->speed == speed) ? 0 : -EINVAL;
}
/*
* Function litelink_reset (task)
*
* Reset the Litelink type dongle.
*
*/
static int litelink_reset(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* probably the power-up can be dropped here, but with only
* 15 usec delay it's not worth the risk unless somebody with
* the hardware confirms it doesn't break anything...
*/
/* Power on dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Sleep a minimum of 15 us */
udelay(MIN_DELAY);
/* Clear RTS to reset dongle */
sirdev_set_dtr_rts(dev, TRUE, FALSE);
/* Sleep a minimum of 15 us */
udelay(MIN_DELAY);
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Sleep a minimum of 15 us */
udelay(MIN_DELAY);
/* This dongles speed defaults to 115200 bps */
dev->speed = 115200;
return 0;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Parallax Litelink dongle driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-5"); /* IRDA_LITELINK_DONGLE */
/*
* Function init_module (void)
*
* Initialize Litelink module
*
*/
module_init(litelink_sir_init);
/*
* Function cleanup_module (void)
*
* Cleanup Litelink module
*
*/
module_exit(litelink_sir_cleanup);

View file

@ -0,0 +1,261 @@
/*********************************************************************
*
* Filename: ma600.c
* Version: 0.1
* Description: Implementation of the MA600 dongle
* Status: Experimental.
* Author: Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95
* Created at: Sat Jun 10 20:02:35 2000
* Modified at: Sat Aug 16 09:34:13 2003
* Modified by: Martin Diehl <mad@mdiehl.de> (modified for new sir_dev)
*
* Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing
* information on the MA600 dongle
*
* Copyright (c) 2000 Leung, 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, see <http://www.gnu.org/licenses/>.
*
********************************************************************/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
static int ma600_open(struct sir_dev *);
static int ma600_close(struct sir_dev *);
static int ma600_change_speed(struct sir_dev *, unsigned);
static int ma600_reset(struct sir_dev *);
/* control byte for MA600 */
#define MA600_9600 0x00
#define MA600_19200 0x01
#define MA600_38400 0x02
#define MA600_57600 0x03
#define MA600_115200 0x04
#define MA600_DEV_ID1 0x05
#define MA600_DEV_ID2 0x06
#define MA600_2400 0x08
static struct dongle_driver ma600 = {
.owner = THIS_MODULE,
.driver_name = "MA600",
.type = IRDA_MA600_DONGLE,
.open = ma600_open,
.close = ma600_close,
.reset = ma600_reset,
.set_speed = ma600_change_speed,
};
static int __init ma600_sir_init(void)
{
IRDA_DEBUG(2, "%s()\n", __func__);
return irda_register_dongle(&ma600);
}
static void __exit ma600_sir_cleanup(void)
{
IRDA_DEBUG(2, "%s()\n", __func__);
irda_unregister_dongle(&ma600);
}
/*
Power on:
(0) Clear RTS and DTR for 1 second
(1) Set RTS and DTR for 1 second
(2) 9600 bps now
Note: assume RTS, DTR are clear before
*/
static int ma600_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __func__);
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Explicitly set the speeds we can accept */
qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400
|IR_57600|IR_115200;
/* Hm, 0x01 means 10ms - for >= 1ms we would need 0x07 */
qos->min_turn_time.bits = 0x01; /* Needs at least 1 ms */
irda_qos_bits_to_value(qos);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int ma600_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
static __u8 get_control_byte(__u32 speed)
{
__u8 byte;
switch (speed) {
default:
case 115200:
byte = MA600_115200;
break;
case 57600:
byte = MA600_57600;
break;
case 38400:
byte = MA600_38400;
break;
case 19200:
byte = MA600_19200;
break;
case 9600:
byte = MA600_9600;
break;
case 2400:
byte = MA600_2400;
break;
}
return byte;
}
/*
* Function ma600_change_speed (dev, speed)
*
* Set the speed for the MA600 type dongle.
*
* The dongle has already been reset to a known state (dongle default)
* We cycle through speeds by pulsing RTS low and then high.
*/
/*
* Function ma600_change_speed (dev, speed)
*
* Set the speed for the MA600 type dongle.
*
* Algorithm
* 1. Reset (already done by irda thread state machine)
* 2. clear RTS, set DTR and wait for 1ms
* 3. send Control Byte to the MA600 through TXD to set new baud rate
* wait until the stop bit of Control Byte is sent (for 9600 baud rate,
* it takes about 10 msec)
* 4. set RTS, set DTR (return to NORMAL Operation)
* 5. wait at least 10 ms, new setting (baud rate, etc) takes effect here
* after
*/
/* total delays are only about 20ms - let's just sleep for now to
* avoid the state machine complexity before we get things working
*/
static int ma600_change_speed(struct sir_dev *dev, unsigned speed)
{
u8 byte;
IRDA_DEBUG(2, "%s(), speed=%d (was %d)\n", __func__,
speed, dev->speed);
/* dongle already reset, dongle and port at default speed (9600) */
/* Set RTS low for 1 ms */
sirdev_set_dtr_rts(dev, TRUE, FALSE);
mdelay(1);
/* Write control byte */
byte = get_control_byte(speed);
sirdev_raw_write(dev, &byte, sizeof(byte));
/* Wait at least 10ms: fake wait_until_sent - 10 bits at 9600 baud*/
msleep(15); /* old ma600 uses 15ms */
#if 1
/* read-back of the control byte. ma600 is the first dongle driver
* which uses this so there might be some unidentified issues.
* Disable this in case of problems with readback.
*/
sirdev_raw_read(dev, &byte, sizeof(byte));
if (byte != get_control_byte(speed)) {
IRDA_WARNING("%s(): bad control byte read-back %02x != %02x\n",
__func__, (unsigned) byte,
(unsigned) get_control_byte(speed));
return -1;
}
else
IRDA_DEBUG(2, "%s() control byte write read OK\n", __func__);
#endif
/* Set DTR, Set RTS */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Wait at least 10ms */
msleep(10);
/* dongle is now switched to the new speed */
dev->speed = speed;
return 0;
}
/*
* Function ma600_reset (dev)
*
* This function resets the ma600 dongle.
*
* Algorithm:
* 0. DTR=0, RTS=1 and wait 10 ms
* 1. DTR=1, RTS=1 and wait 10 ms
* 2. 9600 bps now
*/
/* total delays are only about 20ms - let's just sleep for now to
* avoid the state machine complexity before we get things working
*/
static int ma600_reset(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Reset the dongle : set DTR low for 10 ms */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
msleep(10);
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
msleep(10);
dev->speed = 9600; /* That's the dongle-default */
return 0;
}
MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95");
MODULE_DESCRIPTION("MA600 dongle driver version 0.1");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-11"); /* IRDA_MA600_DONGLE */
module_init(ma600_sir_init);
module_exit(ma600_sir_cleanup);

View file

@ -0,0 +1,230 @@
/*********************************************************************
*
*
* Filename: mcp2120.c
* Version: 1.0
* Description: Implementation for the MCP2120 (Microchip)
* Status: Experimental.
* Author: Felix Tang (tangf@eyetap.org)
* Created at: Sun Mar 31 19:32:12 EST 2002
* Based on code by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 2002 Felix Tang, 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.
*
********************************************************************/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
#include "sir-dev.h"
static int mcp2120_reset(struct sir_dev *dev);
static int mcp2120_open(struct sir_dev *dev);
static int mcp2120_close(struct sir_dev *dev);
static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed);
#define MCP2120_9600 0x87
#define MCP2120_19200 0x8B
#define MCP2120_38400 0x85
#define MCP2120_57600 0x83
#define MCP2120_115200 0x81
#define MCP2120_COMMIT 0x11
static struct dongle_driver mcp2120 = {
.owner = THIS_MODULE,
.driver_name = "Microchip MCP2120",
.type = IRDA_MCP2120_DONGLE,
.open = mcp2120_open,
.close = mcp2120_close,
.reset = mcp2120_reset,
.set_speed = mcp2120_change_speed,
};
static int __init mcp2120_sir_init(void)
{
return irda_register_dongle(&mcp2120);
}
static void __exit mcp2120_sir_cleanup(void)
{
irda_unregister_dongle(&mcp2120);
}
static int mcp2120_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __func__);
/* seems no explicit power-on required here and reset switching it on anyway */
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
qos->min_turn_time.bits = 0x01;
irda_qos_bits_to_value(qos);
return 0;
}
static int mcp2120_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power off dongle */
/* reset and inhibit mcp2120 */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
// sirdev_set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function mcp2120_change_speed (dev, speed)
*
* Set the speed for the MCP2120.
*
*/
#define MCP2120_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED+1)
static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed)
{
unsigned state = dev->fsm.substate;
unsigned delay = 0;
u8 control[2];
static int ret = 0;
IRDA_DEBUG(2, "%s()\n", __func__);
switch (state) {
case SIRDEV_STATE_DONGLE_SPEED:
/* Set DTR to enter command mode */
sirdev_set_dtr_rts(dev, TRUE, FALSE);
udelay(500);
ret = 0;
switch (speed) {
default:
speed = 9600;
ret = -EINVAL;
/* fall through */
case 9600:
control[0] = MCP2120_9600;
//printk("mcp2120 9600\n");
break;
case 19200:
control[0] = MCP2120_19200;
//printk("mcp2120 19200\n");
break;
case 34800:
control[0] = MCP2120_38400;
//printk("mcp2120 38400\n");
break;
case 57600:
control[0] = MCP2120_57600;
//printk("mcp2120 57600\n");
break;
case 115200:
control[0] = MCP2120_115200;
//printk("mcp2120 115200\n");
break;
}
control[1] = MCP2120_COMMIT;
/* Write control bytes */
sirdev_raw_write(dev, control, 2);
dev->speed = speed;
state = MCP2120_STATE_WAIT_SPEED;
delay = 100;
//printk("mcp2120_change_speed: dongle_speed\n");
break;
case MCP2120_STATE_WAIT_SPEED:
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
//printk("mcp2120_change_speed: mcp_wait\n");
break;
default:
IRDA_ERROR("%s(), undefine state %d\n", __func__, state);
ret = -EINVAL;
break;
}
dev->fsm.substate = state;
return (delay > 0) ? delay : ret;
}
/*
* Function mcp2120_reset (driver)
*
* This function resets the mcp2120 dongle.
*
* Info: -set RTS to reset mcp2120
* -set DTR to set mcp2120 software command mode
* -mcp2120 defaults to 9600 baud after reset
*
* Algorithm:
* 0. Set RTS to reset mcp2120.
* 1. Clear RTS and wait for device reset timer of 30 ms (max).
*
*/
#define MCP2120_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1)
#define MCP2120_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2)
static int mcp2120_reset(struct sir_dev *dev)
{
unsigned state = dev->fsm.substate;
unsigned delay = 0;
int ret = 0;
IRDA_DEBUG(2, "%s()\n", __func__);
switch (state) {
case SIRDEV_STATE_DONGLE_RESET:
//printk("mcp2120_reset: dongle_reset\n");
/* Reset dongle by setting RTS*/
sirdev_set_dtr_rts(dev, TRUE, TRUE);
state = MCP2120_STATE_WAIT1_RESET;
delay = 50;
break;
case MCP2120_STATE_WAIT1_RESET:
//printk("mcp2120_reset: mcp2120_wait1\n");
/* clear RTS and wait for at least 30 ms. */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
state = MCP2120_STATE_WAIT2_RESET;
delay = 50;
break;
case MCP2120_STATE_WAIT2_RESET:
//printk("mcp2120_reset mcp2120_wait2\n");
/* Go back to normal mode */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
break;
default:
IRDA_ERROR("%s(), undefined state %d\n", __func__, state);
ret = -EINVAL;
break;
}
dev->fsm.substate = state;
return (delay > 0) ? delay : ret;
}
MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
MODULE_DESCRIPTION("Microchip MCP2120");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */
module_init(mcp2120_sir_init);
module_exit(mcp2120_sir_cleanup);

978
drivers/net/irda/mcs7780.c Normal file
View file

@ -0,0 +1,978 @@
/*****************************************************************************
*
* Filename: mcs7780.c
* Version: 0.4-alpha
* Description: Irda MosChip USB Dongle Driver
* Authors: Lukasz Stelmach <stlman@poczta.fm>
* Brian Pugh <bpugh@cs.pdx.edu>
* Judy Fischbach <jfisch@cs.pdx.edu>
*
* Based on stir4200 driver, but some things done differently.
* Based on earlier driver by Paul Stewart <stewart@parc.com>
*
* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
* Copyright (C) 2001, Dag Brattli <dag@brattli.net>
* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm>
* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu>
* Copyright (C) 2005, Judy Fischbach <jfisch@cs.pdx.edu>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*****************************************************************************/
/*
* MCS7780 is a simple USB to IrDA bridge by MosChip. It is neither
* compatibile with irda-usb nor with stir4200. Although it is quite
* similar to the later as far as general idea of operation is concerned.
* That is it requires the software to do all the framing job at SIR speeds.
* The hardware does take care of the framing at MIR and FIR speeds.
* It supports all speeds from 2400 through 4Mbps
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/device.h>
#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/crc.h>
#include "mcs7780.h"
#define MCS_VENDOR_ID 0x9710
#define MCS_PRODUCT_ID 0x7780
static struct usb_device_id mcs_table[] = {
/* MosChip Corp., MCS7780 FIR-USB Adapter */
{USB_DEVICE(MCS_VENDOR_ID, MCS_PRODUCT_ID)},
{},
};
MODULE_AUTHOR("Brian Pugh <bpugh@cs.pdx.edu>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for MosChip MCS7780");
MODULE_VERSION("0.3alpha");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(usb, mcs_table);
static int qos_mtt_bits = 0x07 /* > 1ms */ ;
module_param(qos_mtt_bits, int, 0);
MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
static int receive_mode = 0x1;
module_param(receive_mode, int, 0);
MODULE_PARM_DESC(receive_mode,
"Receive mode of the device (1:fast, 0:slow, default:1)");
static int sir_tweak = 1;
module_param(sir_tweak, int, 0444);
MODULE_PARM_DESC(sir_tweak,
"Default pulse width (1:1.6us, 0:3/16 bit, default:1).");
static int transceiver_type = MCS_TSC_VISHAY;
module_param(transceiver_type, int, 0444);
MODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h.");
static struct usb_driver mcs_driver = {
.name = "mcs7780",
.probe = mcs_probe,
.disconnect = mcs_disconnect,
.id_table = mcs_table,
};
/* speed flag selection by direct addressing.
addr = (speed >> 8) & 0x0f
0x1 57600 0x2 115200 0x4 1152000 0x5 9600
0x6 38400 0x9 2400 0xa 576000 0xb 19200
4Mbps (or 2400) must be checked separately. Since it also has
to be programmed in a different manner that is not a big problem.
*/
static __u16 mcs_speed_set[16] = { 0,
MCS_SPEED_57600,
MCS_SPEED_115200,
0,
MCS_SPEED_1152000,
MCS_SPEED_9600,
MCS_SPEED_38400,
0, 0,
MCS_SPEED_2400,
MCS_SPEED_576000,
MCS_SPEED_19200,
0, 0, 0,
};
/* Set given 16 bit register with a 16 bit value. Send control message
* to set dongle register. */
static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val)
{
struct usb_device *dev = mcs->usbdev;
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
MCS_WR_RTYPE, val, reg, NULL, 0,
msecs_to_jiffies(MCS_CTRL_TIMEOUT));
}
/* Get 16 bit register value. Send contol message to read dongle register. */
static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val)
{
struct usb_device *dev = mcs->usbdev;
int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
MCS_RD_RTYPE, 0, reg, val, 2,
msecs_to_jiffies(MCS_CTRL_TIMEOUT));
return ret;
}
/* Setup a communication between mcs7780 and TFDU chips. It is described
* in more detail in the data sheet. The setup sequence puts the the
* vishay tranceiver into high speed mode. It will also receive SIR speed
* packets but at reduced sensitivity.
*/
/* 0: OK 1:ERROR */
static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs)
{
int ret = 0;
__u16 rval;
/* mcs_get_reg should read exactly two bytes from the dongle */
ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval);
if (unlikely(ret != 2)) {
ret = -EIO;
goto error;
}
/* The MCS_XCVR_CONF bit puts the transceiver into configuration
* mode. The MCS_MODE0 bit must start out high (1) and then
* transition to low and the MCS_STFIR and MCS_MODE1 bits must
* be low.
*/
rval |= (MCS_MODE0 | MCS_XCVR_CONF);
rval &= ~MCS_STFIR;
rval &= ~MCS_MODE1;
ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
if (unlikely(ret))
goto error;
rval &= ~MCS_MODE0;
ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
if (unlikely(ret))
goto error;
rval &= ~MCS_XCVR_CONF;
ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
if (unlikely(ret))
goto error;
ret = 0;
error:
return ret;
}
/* Setup a communication between mcs7780 and agilent chip. */
static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs)
{
IRDA_WARNING("This transceiver type is not supported yet.\n");
return 1;
}
/* Setup a communication between mcs7780 and sharp chip. */
static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs)
{
IRDA_WARNING("This transceiver type is not supported yet.\n");
return 1;
}
/* Common setup for all transceivers */
static inline int mcs_setup_transceiver(struct mcs_cb *mcs)
{
int ret = 0;
__u16 rval;
char *msg;
msg = "Basic transceiver setup error.";
/* read value of MODE Register, set the DRIVER and RESET bits
* and write value back out to MODE Register
*/
ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
if(unlikely(ret != 2))
goto error;
rval |= MCS_DRIVER; /* put the mcs7780 into configuration mode. */
ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
if(unlikely(ret))
goto error;
rval = 0; /* set min pulse width to 0 initially. */
ret = mcs_set_reg(mcs, MCS_MINRXPW_REG, rval);
if(unlikely(ret))
goto error;
ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
if(unlikely(ret != 2))
goto error;
rval &= ~MCS_FIR; /* turn off fir mode. */
if(mcs->sir_tweak)
rval |= MCS_SIR16US; /* 1.6us pulse width */
else
rval &= ~MCS_SIR16US; /* 3/16 bit time pulse width */
/* make sure ask mode and back to back packets are off. */
rval &= ~(MCS_BBTG | MCS_ASK);
rval &= ~MCS_SPEED_MASK;
rval |= MCS_SPEED_9600; /* make sure initial speed is 9600. */
mcs->speed = 9600;
mcs->new_speed = 0; /* new_speed is set to 0 */
rval &= ~MCS_PLLPWDN; /* disable power down. */
/* make sure device determines direction and that the auto send sip
* pulse are on.
*/
rval |= MCS_DTD | MCS_SIPEN;
ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
if(unlikely(ret))
goto error;
msg = "transceiver model specific setup error.";
switch (mcs->transceiver_type) {
case MCS_TSC_VISHAY:
ret = mcs_setup_transceiver_vishay(mcs);
break;
case MCS_TSC_SHARP:
ret = mcs_setup_transceiver_sharp(mcs);
break;
case MCS_TSC_AGILENT:
ret = mcs_setup_transceiver_agilent(mcs);
break;
default:
IRDA_WARNING("Unknown transceiver type: %d\n",
mcs->transceiver_type);
ret = 1;
}
if (unlikely(ret))
goto error;
/* If transceiver is not SHARP, then if receive mode set
* on the RXFAST bit in the XCVR Register otherwise unset it
*/
if (mcs->transceiver_type != MCS_TSC_SHARP) {
ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval);
if (unlikely(ret != 2))
goto error;
if (mcs->receive_mode)
rval |= MCS_RXFAST;
else
rval &= ~MCS_RXFAST;
ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval);
if (unlikely(ret))
goto error;
}
msg = "transceiver reset.";
ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval);
if (unlikely(ret != 2))
goto error;
/* reset the mcs7780 so all changes take effect. */
rval &= ~MCS_RESET;
ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
if (unlikely(ret))
goto error;
else
return ret;
error:
IRDA_ERROR("%s\n", msg);
return ret;
}
/* Wraps the data in format for SIR */
static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf)
{
int wraplen;
/* 2: full frame length, including "the length" */
wraplen = async_wrap_skb(skb, buf + 2, 4094);
wraplen += 2;
buf[0] = wraplen & 0xff;
buf[1] = (wraplen >> 8) & 0xff;
return wraplen;
}
/* Wraps the data in format for FIR */
static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf)
{
unsigned int len = 0;
__u32 fcs = ~(crc32_le(~0, skb->data, skb->len));
/* add 2 bytes for length value and 4 bytes for fcs. */
len = skb->len + 6;
/* The mcs7780 requires that the first two bytes are the packet
* length in little endian order. Note: the length value includes
* the two bytes for the length value itself.
*/
buf[0] = len & 0xff;
buf[1] = (len >> 8) & 0xff;
/* copy the data into the tx buffer. */
skb_copy_from_linear_data(skb, buf + 2, skb->len);
/* put the fcs in the last four bytes in little endian order. */
buf[len - 4] = fcs & 0xff;
buf[len - 3] = (fcs >> 8) & 0xff;
buf[len - 2] = (fcs >> 16) & 0xff;
buf[len - 1] = (fcs >> 24) & 0xff;
return len;
}
/* Wraps the data in format for MIR */
static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf)
{
__u16 fcs = 0;
int len = skb->len + 4;
fcs = ~(irda_calc_crc16(~fcs, skb->data, skb->len));
/* put the total packet length in first. Note: packet length
* value includes the two bytes that hold the packet length
* itself.
*/
buf[0] = len & 0xff;
buf[1] = (len >> 8) & 0xff;
/* copy the data */
skb_copy_from_linear_data(skb, buf + 2, skb->len);
/* put the fcs in last two bytes in little endian order. */
buf[len - 2] = fcs & 0xff;
buf[len - 1] = (fcs >> 8) & 0xff;
return len;
}
/* Unwrap received packets at MIR speed. A 16 bit crc_ccitt checksum is
* used for the fcs. When performed over the entire packet the result
* should be GOOD_FCS = 0xf0b8. Hands the unwrapped data off to the IrDA
* layer via a sk_buff.
*/
static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len)
{
__u16 fcs;
int new_len;
struct sk_buff *skb;
/* Assume that the frames are going to fill a single packet
* rather than span multiple packets.
*/
new_len = len - 2;
if(unlikely(new_len <= 0)) {
IRDA_ERROR("%s short frame length %d\n",
mcs->netdev->name, new_len);
++mcs->netdev->stats.rx_errors;
++mcs->netdev->stats.rx_length_errors;
return;
}
fcs = 0;
fcs = irda_calc_crc16(~fcs, buf, len);
if(fcs != GOOD_FCS) {
IRDA_ERROR("crc error calc 0x%x len %d\n",
fcs, new_len);
mcs->netdev->stats.rx_errors++;
mcs->netdev->stats.rx_crc_errors++;
return;
}
skb = dev_alloc_skb(new_len + 1);
if(unlikely(!skb)) {
++mcs->netdev->stats.rx_dropped;
return;
}
skb_reserve(skb, 1);
skb_copy_to_linear_data(skb, buf, new_len);
skb_put(skb, new_len);
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
skb->dev = mcs->netdev;
netif_rx(skb);
mcs->netdev->stats.rx_packets++;
mcs->netdev->stats.rx_bytes += new_len;
}
/* Unwrap received packets at FIR speed. A 32 bit crc_ccitt checksum is
* used for the fcs. Hands the unwrapped data off to the IrDA
* layer via a sk_buff.
*/
static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
{
__u32 fcs;
int new_len;
struct sk_buff *skb;
/* Assume that the frames are going to fill a single packet
* rather than span multiple packets. This is most likely a false
* assumption.
*/
new_len = len - 4;
if(unlikely(new_len <= 0)) {
IRDA_ERROR("%s short frame length %d\n",
mcs->netdev->name, new_len);
++mcs->netdev->stats.rx_errors;
++mcs->netdev->stats.rx_length_errors;
return;
}
fcs = ~(crc32_le(~0, buf, new_len));
if(fcs != get_unaligned_le32(buf + new_len)) {
IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
mcs->netdev->stats.rx_errors++;
mcs->netdev->stats.rx_crc_errors++;
return;
}
skb = dev_alloc_skb(new_len + 1);
if(unlikely(!skb)) {
++mcs->netdev->stats.rx_dropped;
return;
}
skb_reserve(skb, 1);
skb_copy_to_linear_data(skb, buf, new_len);
skb_put(skb, new_len);
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
skb->dev = mcs->netdev;
netif_rx(skb);
mcs->netdev->stats.rx_packets++;
mcs->netdev->stats.rx_bytes += new_len;
}
/* Allocates urbs for both receive and transmit.
* If alloc fails return error code 0 (fail) otherwise
* return error code 1 (success).
*/
static inline int mcs_setup_urbs(struct mcs_cb *mcs)
{
mcs->rx_urb = NULL;
mcs->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!mcs->tx_urb)
return 0;
mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!mcs->rx_urb) {
usb_free_urb(mcs->tx_urb);
mcs->tx_urb = NULL;
return 0;
}
return 1;
}
/* Sets up state to be initially outside frame, gets receive urb,
* sets status to successful and then submits the urb to start
* receiving the data.
*/
static inline int mcs_receive_start(struct mcs_cb *mcs)
{
mcs->rx_buff.in_frame = FALSE;
mcs->rx_buff.state = OUTSIDE_FRAME;
usb_fill_bulk_urb(mcs->rx_urb, mcs->usbdev,
usb_rcvbulkpipe(mcs->usbdev, mcs->ep_in),
mcs->in_buf, 4096, mcs_receive_irq, mcs);
mcs->rx_urb->status = 0;
return usb_submit_urb(mcs->rx_urb, GFP_KERNEL);
}
/* Finds the in and out endpoints for the mcs control block */
static inline int mcs_find_endpoints(struct mcs_cb *mcs,
struct usb_host_endpoint *ep, int epnum)
{
int i;
int ret = 0;
/* If no place to store the endpoints just return */
if (!ep)
return ret;
/* cycle through all endpoints, find the first two that are DIR_IN */
for (i = 0; i < epnum; i++) {
if (ep[i].desc.bEndpointAddress & USB_DIR_IN)
mcs->ep_in = ep[i].desc.bEndpointAddress;
else
mcs->ep_out = ep[i].desc.bEndpointAddress;
/* MosChip says that the chip has only two bulk
* endpoints. Find one for each direction and move on.
*/
if ((mcs->ep_in != 0) && (mcs->ep_out != 0)) {
ret = 1;
break;
}
}
return ret;
}
static void mcs_speed_work(struct work_struct *work)
{
struct mcs_cb *mcs = container_of(work, struct mcs_cb, work);
struct net_device *netdev = mcs->netdev;
mcs_speed_change(mcs);
netif_wake_queue(netdev);
}
/* Function to change the speed of the mcs7780. Fully supports SIR,
* MIR, and FIR speeds.
*/
static int mcs_speed_change(struct mcs_cb *mcs)
{
int ret = 0;
int rst = 0;
int cnt = 0;
__u16 nspeed;
__u16 rval;
nspeed = mcs_speed_set[(mcs->new_speed >> 8) & 0x0f];
do {
mcs_get_reg(mcs, MCS_RESV_REG, &rval);
} while(cnt++ < 100 && (rval & MCS_IRINTX));
if (cnt > 100) {
IRDA_ERROR("unable to change speed\n");
ret = -EIO;
goto error;
}
mcs_get_reg(mcs, MCS_MODE_REG, &rval);
/* MINRXPW values recommended by MosChip */
if (mcs->new_speed <= 115200) {
rval &= ~MCS_FIR;
if ((rst = (mcs->speed > 115200)))
mcs_set_reg(mcs, MCS_MINRXPW_REG, 0);
} else if (mcs->new_speed <= 1152000) {
rval &= ~MCS_FIR;
if ((rst = !(mcs->speed == 576000 || mcs->speed == 1152000)))
mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);
} else {
rval |= MCS_FIR;
if ((rst = (mcs->speed != 4000000)))
mcs_set_reg(mcs, MCS_MINRXPW_REG, 5);
}
rval &= ~MCS_SPEED_MASK;
rval |= nspeed;
ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
if (unlikely(ret))
goto error;
if (rst)
switch (mcs->transceiver_type) {
case MCS_TSC_VISHAY:
ret = mcs_setup_transceiver_vishay(mcs);
break;
case MCS_TSC_SHARP:
ret = mcs_setup_transceiver_sharp(mcs);
break;
case MCS_TSC_AGILENT:
ret = mcs_setup_transceiver_agilent(mcs);
break;
default:
ret = 1;
IRDA_WARNING("Unknown transceiver type: %d\n",
mcs->transceiver_type);
}
if (unlikely(ret))
goto error;
mcs_get_reg(mcs, MCS_MODE_REG, &rval);
rval &= ~MCS_RESET;
ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
mcs->speed = mcs->new_speed;
error:
mcs->new_speed = 0;
return ret;
}
/* Ioctl calls not supported at this time. Can be an area of future work. */
static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
/* struct if_irda_req *irq = (struct if_irda_req *)rq; */
/* struct mcs_cb *mcs = netdev_priv(netdev); */
int ret = 0;
switch (cmd) {
default:
ret = -EOPNOTSUPP;
}
return ret;
}
/* Network device is taken down, done by "ifconfig irda0 down" */
static int mcs_net_close(struct net_device *netdev)
{
int ret = 0;
struct mcs_cb *mcs = netdev_priv(netdev);
/* Stop transmit processing */
netif_stop_queue(netdev);
kfree_skb(mcs->rx_buff.skb);
/* kill and free the receive and transmit URBs */
usb_kill_urb(mcs->rx_urb);
usb_free_urb(mcs->rx_urb);
usb_kill_urb(mcs->tx_urb);
usb_free_urb(mcs->tx_urb);
/* Stop and remove instance of IrLAP */
if (mcs->irlap)
irlap_close(mcs->irlap);
mcs->irlap = NULL;
return ret;
}
/* Network device is taken up, done by "ifconfig irda0 up" */
static int mcs_net_open(struct net_device *netdev)
{
struct mcs_cb *mcs = netdev_priv(netdev);
char hwname[16];
int ret = 0;
ret = usb_clear_halt(mcs->usbdev,
usb_sndbulkpipe(mcs->usbdev, mcs->ep_in));
if (ret)
goto error1;
ret = usb_clear_halt(mcs->usbdev,
usb_rcvbulkpipe(mcs->usbdev, mcs->ep_out));
if (ret)
goto error1;
ret = mcs_setup_transceiver(mcs);
if (ret)
goto error1;
ret = -ENOMEM;
/* Initialize for SIR/FIR to copy data directly into skb. */
mcs->receiving = 0;
mcs->rx_buff.truesize = IRDA_SKB_MAX_MTU;
mcs->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
if (!mcs->rx_buff.skb)
goto error1;
skb_reserve(mcs->rx_buff.skb, 1);
mcs->rx_buff.head = mcs->rx_buff.skb->data;
do_gettimeofday(&mcs->rx_time);
/*
* Now that everything should be initialized properly,
* Open new IrLAP layer instance to take care of us...
* Note : will send immediately a speed change...
*/
sprintf(hwname, "usb#%d", mcs->usbdev->devnum);
mcs->irlap = irlap_open(netdev, &mcs->qos, hwname);
if (!mcs->irlap) {
IRDA_ERROR("mcs7780: irlap_open failed\n");
goto error2;
}
if (!mcs_setup_urbs(mcs))
goto error3;
ret = mcs_receive_start(mcs);
if (ret)
goto error4;
netif_start_queue(netdev);
return 0;
error4:
usb_free_urb(mcs->rx_urb);
usb_free_urb(mcs->tx_urb);
error3:
irlap_close(mcs->irlap);
error2:
kfree_skb(mcs->rx_buff.skb);
error1:
return ret;
}
/* Receive callback function. */
static void mcs_receive_irq(struct urb *urb)
{
__u8 *bytes;
struct mcs_cb *mcs = urb->context;
int i;
int ret;
if (!netif_running(mcs->netdev))
return;
if (urb->status)
return;
if (urb->actual_length > 0) {
bytes = urb->transfer_buffer;
/* MCS returns frames without BOF and EOF
* I assume it returns whole frames.
*/
/* SIR speed */
if(mcs->speed < 576000) {
async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
&mcs->rx_buff, 0xc0);
for (i = 0; i < urb->actual_length; i++)
async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
&mcs->rx_buff, bytes[i]);
async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
&mcs->rx_buff, 0xc1);
}
/* MIR speed */
else if(mcs->speed == 576000 || mcs->speed == 1152000) {
mcs_unwrap_mir(mcs, urb->transfer_buffer,
urb->actual_length);
}
/* FIR speed */
else {
mcs_unwrap_fir(mcs, urb->transfer_buffer,
urb->actual_length);
}
do_gettimeofday(&mcs->rx_time);
}
ret = usb_submit_urb(urb, GFP_ATOMIC);
}
/* Transmit callback function. */
static void mcs_send_irq(struct urb *urb)
{
struct mcs_cb *mcs = urb->context;
struct net_device *ndev = mcs->netdev;
if (unlikely(mcs->new_speed))
schedule_work(&mcs->work);
else
netif_wake_queue(ndev);
}
/* Transmit callback function. */
static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
unsigned long flags;
struct mcs_cb *mcs;
int wraplen;
int ret = 0;
netif_stop_queue(ndev);
mcs = netdev_priv(ndev);
spin_lock_irqsave(&mcs->lock, flags);
mcs->new_speed = irda_get_next_speed(skb);
if (likely(mcs->new_speed == mcs->speed))
mcs->new_speed = 0;
/* SIR speed */
if(mcs->speed < 576000) {
wraplen = mcs_wrap_sir_skb(skb, mcs->out_buf);
}
/* MIR speed */
else if(mcs->speed == 576000 || mcs->speed == 1152000) {
wraplen = mcs_wrap_mir_skb(skb, mcs->out_buf);
}
/* FIR speed */
else {
wraplen = mcs_wrap_fir_skb(skb, mcs->out_buf);
}
usb_fill_bulk_urb(mcs->tx_urb, mcs->usbdev,
usb_sndbulkpipe(mcs->usbdev, mcs->ep_out),
mcs->out_buf, wraplen, mcs_send_irq, mcs);
if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) {
IRDA_ERROR("failed tx_urb: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
break;
default:
mcs->netdev->stats.tx_errors++;
netif_start_queue(ndev);
}
} else {
mcs->netdev->stats.tx_packets++;
mcs->netdev->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
spin_unlock_irqrestore(&mcs->lock, flags);
return NETDEV_TX_OK;
}
static const struct net_device_ops mcs_netdev_ops = {
.ndo_open = mcs_net_open,
.ndo_stop = mcs_net_close,
.ndo_start_xmit = mcs_hard_xmit,
.ndo_do_ioctl = mcs_net_ioctl,
};
/*
* This function is called by the USB subsystem for each new device in the
* system. Need to verify the device and if it is, then start handling it.
*/
static int mcs_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct net_device *ndev = NULL;
struct mcs_cb *mcs;
int ret = -ENOMEM;
ndev = alloc_irdadev(sizeof(*mcs));
if (!ndev)
goto error1;
IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
SET_NETDEV_DEV(ndev, &intf->dev);
ret = usb_reset_configuration(udev);
if (ret != 0) {
IRDA_ERROR("mcs7780: usb reset configuration failed\n");
goto error2;
}
mcs = netdev_priv(ndev);
mcs->usbdev = udev;
mcs->netdev = ndev;
spin_lock_init(&mcs->lock);
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&mcs->qos);
/* That's the Rx capability. */
mcs->qos.baud_rate.bits &=
IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200
| IR_576000 | IR_1152000 | (IR_4000000 << 8);
mcs->qos.min_turn_time.bits &= qos_mtt_bits;
irda_qos_bits_to_value(&mcs->qos);
/* Speed change work initialisation*/
INIT_WORK(&mcs->work, mcs_speed_work);
ndev->netdev_ops = &mcs_netdev_ops;
if (!intf->cur_altsetting) {
ret = -ENOMEM;
goto error2;
}
ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint,
intf->cur_altsetting->desc.bNumEndpoints);
if (!ret) {
ret = -ENODEV;
goto error2;
}
ret = register_netdev(ndev);
if (ret != 0)
goto error2;
IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s\n",
ndev->name);
mcs->transceiver_type = transceiver_type;
mcs->sir_tweak = sir_tweak;
mcs->receive_mode = receive_mode;
usb_set_intfdata(intf, mcs);
return 0;
error2:
free_netdev(ndev);
error1:
return ret;
}
/* The current device is removed, the USB layer tells us to shut down. */
static void mcs_disconnect(struct usb_interface *intf)
{
struct mcs_cb *mcs = usb_get_intfdata(intf);
if (!mcs)
return;
cancel_work_sync(&mcs->work);
unregister_netdev(mcs->netdev);
free_netdev(mcs->netdev);
usb_set_intfdata(intf, NULL);
IRDA_DEBUG(0, "MCS7780 now disconnected.\n");
}
module_usb_driver(mcs_driver);

166
drivers/net/irda/mcs7780.h Normal file
View file

@ -0,0 +1,166 @@
/*****************************************************************************
*
* Filename: mcs7780.h
* Version: 0.2-alpha
* Description: Irda MosChip USB Dongle
* Status: Experimental
* Authors: Lukasz Stelmach <stlman@poczta.fm>
* Brian Pugh <bpugh@cs.pdx.edu>
*
* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm>
* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*****************************************************************************/
#ifndef _MCS7780_H
#define _MCS7780_H
#define MCS_MODE_SIR 0
#define MCS_MODE_MIR 1
#define MCS_MODE_FIR 2
#define MCS_CTRL_TIMEOUT 500
#define MCS_XMIT_TIMEOUT 500
/* Possible transceiver types */
#define MCS_TSC_VISHAY 0 /* Vishay TFD, default choice */
#define MCS_TSC_AGILENT 1 /* Agilent 3602/3600 */
#define MCS_TSC_SHARP 2 /* Sharp GP2W1000YP */
/* Requests */
#define MCS_RD_RTYPE 0xC0
#define MCS_WR_RTYPE 0x40
#define MCS_RDREQ 0x0F
#define MCS_WRREQ 0x0E
/* Register 0x00 */
#define MCS_MODE_REG 0
#define MCS_FIR ((__u16)0x0001)
#define MCS_SIR16US ((__u16)0x0002)
#define MCS_BBTG ((__u16)0x0004)
#define MCS_ASK ((__u16)0x0008)
#define MCS_PARITY ((__u16)0x0010)
/* SIR/MIR speed constants */
#define MCS_SPEED_SHIFT 5
#define MCS_SPEED_MASK ((__u16)0x00E0)
#define MCS_SPEED(x) ((x & MCS_SPEED_MASK) >> MCS_SPEED_SHIFT)
#define MCS_SPEED_2400 ((0 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_SPEED_9600 ((1 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_SPEED_19200 ((2 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_SPEED_38400 ((3 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_SPEED_57600 ((4 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_SPEED_115200 ((5 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_SPEED_576000 ((6 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_SPEED_1152000 ((7 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK)
#define MCS_PLLPWDN ((__u16)0x0100)
#define MCS_DRIVER ((__u16)0x0200)
#define MCS_DTD ((__u16)0x0400)
#define MCS_DIR ((__u16)0x0800)
#define MCS_SIPEN ((__u16)0x1000)
#define MCS_SENDSIP ((__u16)0x2000)
#define MCS_CHGDIR ((__u16)0x4000)
#define MCS_RESET ((__u16)0x8000)
/* Register 0x02 */
#define MCS_XCVR_REG 2
#define MCS_MODE0 ((__u16)0x0001)
#define MCS_STFIR ((__u16)0x0002)
#define MCS_XCVR_CONF ((__u16)0x0004)
#define MCS_RXFAST ((__u16)0x0008)
/* TXCUR [6:4] */
#define MCS_TXCUR_SHIFT 4
#define MCS_TXCUR_MASK ((__u16)0x0070)
#define MCS_TXCUR(x) ((x & MCS_TXCUR_MASK) >> MCS_TXCUR_SHIFT)
#define MCS_SETTXCUR(x,y) \
((x & ~MCS_TXCUR_MASK) | (y << MCS_TXCUR_SHIFT) & MCS_TXCUR_MASK)
#define MCS_MODE1 ((__u16)0x0080)
#define MCS_SMODE0 ((__u16)0x0100)
#define MCS_SMODE1 ((__u16)0x0200)
#define MCS_INVTX ((__u16)0x0400)
#define MCS_INVRX ((__u16)0x0800)
#define MCS_MINRXPW_REG 4
#define MCS_RESV_REG 7
#define MCS_IRINTX ((__u16)0x0001)
#define MCS_IRINRX ((__u16)0x0002)
struct mcs_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 qos_info qos;
unsigned int speed; /* Current speed */
unsigned int new_speed; /* new speed */
struct work_struct work; /* Change speed work */
struct sk_buff *tx_pending;
char in_buf[4096]; /* transmit/receive buffer */
char out_buf[4096]; /* transmit/receive buffer */
__u8 *fifo_status;
iobuff_t rx_buff; /* receive unwrap state machine */
struct timeval rx_time;
spinlock_t lock;
int receiving;
__u8 ep_in;
__u8 ep_out;
struct urb *rx_urb;
struct urb *tx_urb;
int transceiver_type;
int sir_tweak;
int receive_mode;
};
static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val);
static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val);
static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs);
static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs);
static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs);
static inline int mcs_setup_transceiver(struct mcs_cb *mcs);
static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf);
static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf);
static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf);
static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len);
static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len);
static inline int mcs_setup_urbs(struct mcs_cb *mcs);
static inline int mcs_receive_start(struct mcs_cb *mcs);
static inline int mcs_find_endpoints(struct mcs_cb *mcs,
struct usb_host_endpoint *ep, int epnum);
static int mcs_speed_change(struct mcs_cb *mcs);
static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd);
static int mcs_net_close(struct net_device *netdev);
static int mcs_net_open(struct net_device *netdev);
static void mcs_receive_irq(struct urb *urb);
static void mcs_send_irq(struct urb *urb);
static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb,
struct net_device *netdev);
static int mcs_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void mcs_disconnect(struct usb_interface *intf);
#endif /* _MCS7780_H */

2419
drivers/net/irda/nsc-ircc.c Normal file

File diff suppressed because it is too large Load diff

282
drivers/net/irda/nsc-ircc.h Normal file
View file

@ -0,0 +1,282 @@
/*********************************************************************
*
* Filename: nsc-ircc.h
* Version:
* Description:
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Fri Nov 13 14:37:40 1998
* Modified at: Sun Jan 23 17:47:00 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* 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
* 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.
*
********************************************************************/
#ifndef NSC_IRCC_H
#define NSC_IRCC_H
#include <linux/time.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/types.h>
#include <asm/io.h>
/* Features for chips (set in driver_data) */
#define NSC_FORCE_DONGLE_TYPE9 0x00000001
/* DMA modes needed */
#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
/* Config registers for the '108 */
#define CFG_108_BAIC 0x00
#define CFG_108_CSRT 0x01
#define CFG_108_MCTL 0x02
/* Config registers for the '338 */
#define CFG_338_FER 0x00
#define CFG_338_FAR 0x01
#define CFG_338_PTR 0x02
#define CFG_338_PNP0 0x1b
#define CFG_338_PNP1 0x1c
#define CFG_338_PNP3 0x4f
/* Config registers for the '39x (in the logical device bank) */
#define CFG_39X_LDN 0x07 /* Logical device number (Super I/O bank) */
#define CFG_39X_SIOCF1 0x21 /* SuperI/O Config */
#define CFG_39X_ACT 0x30 /* Device activation */
#define CFG_39X_BASEH 0x60 /* Device base address (high bits) */
#define CFG_39X_BASEL 0x61 /* Device base address (low bits) */
#define CFG_39X_IRQNUM 0x70 /* Interrupt number & wake up enable */
#define CFG_39X_IRQSEL 0x71 /* Interrupt select (edge/level + polarity) */
#define CFG_39X_DMA0 0x74 /* DMA 0 configuration */
#define CFG_39X_DMA1 0x75 /* DMA 1 configuration */
#define CFG_39X_SPC 0xF0 /* Serial port configuration register */
/* Flags for configuration register CRF0 */
#define APEDCRC 0x02
#define ENBNKSEL 0x01
/* Set 0 */
#define TXD 0x00 /* Transmit data port */
#define RXD 0x00 /* Receive data port */
/* Register 1 */
#define IER 0x01 /* Interrupt Enable Register*/
#define IER_RXHDL_IE 0x01 /* Receiver high data level interrupt */
#define IER_TXLDL_IE 0x02 /* Transeiver low data level interrupt */
#define IER_LS_IE 0x04//* Link Status Interrupt */
#define IER_ETXURI 0x04 /* Tx underrun */
#define IER_DMA_IE 0x10 /* DMA finished interrupt */
#define IER_TXEMP_IE 0x20
#define IER_SFIF_IE 0x40 /* Frame status FIFO intr */
#define IER_TMR_IE 0x80 /* Timer event */
#define FCR 0x02 /* (write only) */
#define FCR_FIFO_EN 0x01 /* Enable FIFO's */
#define FCR_RXSR 0x02 /* Rx FIFO soft reset */
#define FCR_TXSR 0x04 /* Tx FIFO soft reset */
#define FCR_RXTH 0x40 /* Rx FIFO threshold (set to 16) */
#define FCR_TXTH 0x20 /* Tx FIFO threshold (set to 17) */
#define EIR 0x02 /* (read only) */
#define EIR_RXHDL_EV 0x01
#define EIR_TXLDL_EV 0x02
#define EIR_LS_EV 0x04
#define EIR_DMA_EV 0x10
#define EIR_TXEMP_EV 0x20
#define EIR_SFIF_EV 0x40
#define EIR_TMR_EV 0x80
#define LCR 0x03 /* Link control register */
#define LCR_WLS_8 0x03 /* 8 bits */
#define BSR 0x03 /* Bank select register */
#define BSR_BKSE 0x80
#define BANK0 LCR_WLS_8 /* Must make sure that we set 8N1 */
#define BANK1 0x80
#define BANK2 0xe0
#define BANK3 0xe4
#define BANK4 0xe8
#define BANK5 0xec
#define BANK6 0xf0
#define BANK7 0xf4
#define MCR 0x04 /* Mode Control Register */
#define MCR_MODE_MASK ~(0xd0)
#define MCR_UART 0x00
#define MCR_RESERVED 0x20
#define MCR_SHARP_IR 0x40
#define MCR_SIR 0x60
#define MCR_MIR 0x80
#define MCR_FIR 0xa0
#define MCR_CEIR 0xb0
#define MCR_IR_PLS 0x10
#define MCR_DMA_EN 0x04
#define MCR_EN_IRQ 0x08
#define MCR_TX_DFR 0x08
#define LSR 0x05 /* Link status register */
#define LSR_RXDA 0x01 /* Receiver data available */
#define LSR_TXRDY 0x20 /* Transmitter ready */
#define LSR_TXEMP 0x40 /* Transmitter empty */
#define ASCR 0x07 /* Auxiliary Status and Control Register */
#define ASCR_RXF_TOUT 0x01 /* Rx FIFO timeout */
#define ASCR_FEND_INF 0x02 /* Frame end bytes in rx FIFO */
#define ASCR_S_EOT 0x04 /* Set end of transmission */
#define ASCT_RXBSY 0x20 /* Rx busy */
#define ASCR_TXUR 0x40 /* Transeiver underrun */
#define ASCR_CTE 0x80 /* Clear timer event */
/* Bank 2 */
#define BGDL 0x00 /* Baud Generator Divisor Port (Low Byte) */
#define BGDH 0x01 /* Baud Generator Divisor Port (High Byte) */
#define ECR1 0x02 /* Extended Control Register 1 */
#define ECR1_EXT_SL 0x01 /* Extended Mode Select */
#define ECR1_DMANF 0x02 /* DMA Fairness */
#define ECR1_DMATH 0x04 /* DMA Threshold */
#define ECR1_DMASWP 0x08 /* DMA Swap */
#define EXCR2 0x04
#define EXCR2_TFSIZ 0x01 /* Rx FIFO size = 32 */
#define EXCR2_RFSIZ 0x04 /* Tx FIFO size = 32 */
#define TXFLV 0x06 /* Tx FIFO level */
#define RXFLV 0x07 /* Rx FIFO level */
/* Bank 3 */
#define MID 0x00
/* Bank 4 */
#define TMRL 0x00 /* Timer low byte */
#define TMRH 0x01 /* Timer high byte */
#define IRCR1 0x02 /* Infrared control register 1 */
#define IRCR1_TMR_EN 0x01 /* Timer enable */
#define TFRLL 0x04
#define TFRLH 0x05
#define RFRLL 0x06
#define RFRLH 0x07
/* Bank 5 */
#define IRCR2 0x04 /* Infrared control register 2 */
#define IRCR2_MDRS 0x04 /* MIR data rate select */
#define IRCR2_FEND_MD 0x20 /* */
#define FRM_ST 0x05 /* Frame status FIFO */
#define FRM_ST_VLD 0x80 /* Frame status FIFO data valid */
#define FRM_ST_ERR_MSK 0x5f
#define FRM_ST_LOST_FR 0x40 /* Frame lost */
#define FRM_ST_MAX_LEN 0x10 /* Max frame len exceeded */
#define FRM_ST_PHY_ERR 0x08 /* Physical layer error */
#define FRM_ST_BAD_CRC 0x04
#define FRM_ST_OVR1 0x02 /* Rx FIFO overrun */
#define FRM_ST_OVR2 0x01 /* Frame status FIFO overrun */
#define RFLFL 0x06
#define RFLFH 0x07
/* Bank 6 */
#define IR_CFG2 0x00
#define IR_CFG2_DIS_CRC 0x02
/* Bank 7 */
#define IRM_CR 0x07 /* Infrared module control register */
#define IRM_CR_IRX_MSL 0x40
#define IRM_CR_AF_MNT 0x80 /* Automatic format */
/* NSC chip information */
struct nsc_chip {
char *name; /* Name of chipset */
int cfg[3]; /* Config registers */
u_int8_t cid_index; /* Chip identification index reg */
u_int8_t cid_value; /* Chip identification expected value */
u_int8_t cid_mask; /* Chip identification revision mask */
/* Functions for probing and initializing the specific chip */
int (*probe)(struct nsc_chip *chip, chipio_t *info);
int (*init)(struct nsc_chip *chip, chipio_t *info);
};
typedef struct nsc_chip nsc_chip_t;
/* For storing entries in the status FIFO */
struct st_fifo_entry {
int status;
int len;
};
#define MAX_TX_WINDOW 7
#define MAX_RX_WINDOW 7
struct st_fifo {
struct st_fifo_entry entries[MAX_RX_WINDOW];
int pending_bytes;
int head;
int tail;
int len;
};
struct frame_cb {
void *start; /* Start of frame in DMA mem */
int len; /* Length of frame in DMA mem */
};
struct tx_fifo {
struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
int ptr; /* Currently being sent */
int len; /* Length of queue */
int free; /* Next free slot */
void *tail; /* Next free start in DMA mem */
};
/* Private data for each instance */
struct nsc_ircc_cb {
struct st_fifo st_fifo; /* Info about received frames */
struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos; /* QoS capabilities for this device */
chipio_t io; /* IrDA controller information */
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
dma_addr_t tx_buff_dma;
dma_addr_t rx_buff_dma;
__u8 ier; /* Interrupt enable register */
struct timeval stamp;
struct timeval now;
spinlock_t lock; /* For serializing operations */
__u32 new_speed;
int index; /* Instance index */
struct platform_device *pldev;
};
static inline void switch_bank(int iobase, int bank)
{
outb(bank, iobase+BSR);
}
#endif /* NSC_IRCC_H */

View file

@ -0,0 +1,154 @@
/*********************************************************************
*
* Filename: old_belkin.c
* Version: 1.1
* Description: Driver for the Belkin (old) SmartBeam dongle
* Status: Experimental...
* Author: Jean Tourrilhes <jt@hpl.hp.com>
* Created at: 22/11/99
* Modified at: Fri Dec 17 09:13:32 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Jean Tourrilhes, 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, see <http://www.gnu.org/licenses/>.
*
********************************************************************/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <net/irda/irda.h>
// #include <net/irda/irda_device.h>
#include "sir-dev.h"
/*
* Belkin is selling a dongle called the SmartBeam.
* In fact, there is two hardware version of this dongle, of course with
* the same name and looking the exactly same (grrr...).
* I guess that I've got the old one, because inside I don't have
* a jumper for IrDA/ASK...
*
* As far as I can make it from info on their web site, the old dongle
* support only 9600 b/s, which make our life much simpler as far as
* the driver is concerned, but you might not like it very much ;-)
* The new SmartBeam does 115 kb/s, and I've not tested it...
*
* Belkin claim that the correct driver for the old dongle (in Windows)
* is the generic Parallax 9500a driver, but the Linux LiteLink driver
* fails for me (probably because Linux-IrDA doesn't rate fallback),
* so I created this really dumb driver...
*
* In fact, this driver doesn't do much. The only thing it does is to
* prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This
* driver is called "old_belkin" so that when the new SmartBeam is supported
* its driver can be called "belkin" instead of "new_belkin".
*
* Note : this driver was written without any info/help from Belkin,
* so a lot of info here might be totally wrong. Blame me ;-)
*/
static int old_belkin_open(struct sir_dev *dev);
static int old_belkin_close(struct sir_dev *dev);
static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed);
static int old_belkin_reset(struct sir_dev *dev);
static struct dongle_driver old_belkin = {
.owner = THIS_MODULE,
.driver_name = "Old Belkin SmartBeam",
.type = IRDA_OLD_BELKIN_DONGLE,
.open = old_belkin_open,
.close = old_belkin_close,
.reset = old_belkin_reset,
.set_speed = old_belkin_change_speed,
};
static int __init old_belkin_sir_init(void)
{
return irda_register_dongle(&old_belkin);
}
static void __exit old_belkin_sir_cleanup(void)
{
irda_unregister_dongle(&old_belkin);
}
static int old_belkin_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power on dongle */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Not too fast, please... */
qos->baud_rate.bits &= IR_9600;
/* Needs at least 10 ms (totally wild guess, can do probably better) */
qos->min_turn_time.bits = 0x01;
irda_qos_bits_to_value(qos);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int old_belkin_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power off dongle */
sirdev_set_dtr_rts(dev, FALSE, FALSE);
return 0;
}
/*
* Function old_belkin_change_speed (task)
*
* With only one speed available, not much to do...
*/
static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed)
{
IRDA_DEBUG(2, "%s()\n", __func__);
dev->speed = 9600;
return (speed==dev->speed) ? 0 : -EINVAL;
}
/*
* Function old_belkin_reset (task)
*
* Reset the Old-Belkin type dongle.
*
*/
static int old_belkin_reset(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* This dongles speed "defaults" to 9600 bps ;-) */
dev->speed = 9600;
return 0;
}
MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-7"); /* IRDA_OLD_BELKIN_DONGLE */
module_init(old_belkin_sir_init);
module_exit(old_belkin_sir_cleanup);

View file

@ -0,0 +1,980 @@
/*
* linux/drivers/net/irda/pxaficp_ir.c
*
* Based on sa1100_ir.c by Russell King
*
* Changes copyright (C) 2003-2005 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor
*
*/
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#include <mach/dma.h>
#include <linux/platform_data/irda-pxaficp.h>
#include <mach/regs-ost.h>
#include <mach/regs-uart.h>
#define FICP __REG(0x40800000) /* Start of FICP area */
#define ICCR0 __REG(0x40800000) /* ICP Control Register 0 */
#define ICCR1 __REG(0x40800004) /* ICP Control Register 1 */
#define ICCR2 __REG(0x40800008) /* ICP Control Register 2 */
#define ICDR __REG(0x4080000c) /* ICP Data Register */
#define ICSR0 __REG(0x40800014) /* ICP Status Register 0 */
#define ICSR1 __REG(0x40800018) /* ICP Status Register 1 */
#define ICCR0_AME (1 << 7) /* Address match enable */
#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */
#define ICCR0_RIE (1 << 5) /* Receive FIFO interrupt enable */
#define ICCR0_RXE (1 << 4) /* Receive enable */
#define ICCR0_TXE (1 << 3) /* Transmit enable */
#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */
#define ICCR0_LBM (1 << 1) /* Loopback mode */
#define ICCR0_ITR (1 << 0) /* IrDA transmission */
#define ICCR2_RXP (1 << 3) /* Receive Pin Polarity select */
#define ICCR2_TXP (1 << 2) /* Transmit Pin Polarity select */
#define ICCR2_TRIG (3 << 0) /* Receive FIFO Trigger threshold */
#define ICCR2_TRIG_8 (0 << 0) /* >= 8 bytes */
#define ICCR2_TRIG_16 (1 << 0) /* >= 16 bytes */
#define ICCR2_TRIG_32 (2 << 0) /* >= 32 bytes */
#ifdef CONFIG_PXA27x
#define ICSR0_EOC (1 << 6) /* DMA End of Descriptor Chain */
#endif
#define ICSR0_FRE (1 << 5) /* Framing error */
#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */
#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */
#define ICSR0_RAB (1 << 2) /* Receiver abort */
#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */
#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */
#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */
#define ICSR1_CRE (1 << 5) /* CRC error */
#define ICSR1_EOF (1 << 4) /* End of frame */
#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */
#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */
#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */
#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */
#define IrSR_RXPL_NEG_IS_ZERO (1<<4)
#define IrSR_RXPL_POS_IS_ZERO 0x0
#define IrSR_TXPL_NEG_IS_ZERO (1<<3)
#define IrSR_TXPL_POS_IS_ZERO 0x0
#define IrSR_XMODE_PULSE_1_6 (1<<2)
#define IrSR_XMODE_PULSE_3_16 0x0
#define IrSR_RCVEIR_IR_MODE (1<<1)
#define IrSR_RCVEIR_UART_MODE 0x0
#define IrSR_XMITIR_IR_MODE (1<<0)
#define IrSR_XMITIR_UART_MODE 0x0
#define IrSR_IR_RECEIVE_ON (\
IrSR_RXPL_NEG_IS_ZERO | \
IrSR_TXPL_POS_IS_ZERO | \
IrSR_XMODE_PULSE_3_16 | \
IrSR_RCVEIR_IR_MODE | \
IrSR_XMITIR_UART_MODE)
#define IrSR_IR_TRANSMIT_ON (\
IrSR_RXPL_NEG_IS_ZERO | \
IrSR_TXPL_POS_IS_ZERO | \
IrSR_XMODE_PULSE_3_16 | \
IrSR_RCVEIR_UART_MODE | \
IrSR_XMITIR_IR_MODE)
struct pxa_irda {
int speed;
int newspeed;
unsigned long last_oscr;
unsigned char *dma_rx_buff;
unsigned char *dma_tx_buff;
dma_addr_t dma_rx_buff_phy;
dma_addr_t dma_tx_buff_phy;
unsigned int dma_tx_buff_len;
int txdma;
int rxdma;
int uart_irq;
int icp_irq;
struct irlap_cb *irlap;
struct qos_info qos;
iobuff_t tx_buff;
iobuff_t rx_buff;
struct device *dev;
struct pxaficp_platform_data *pdata;
struct clk *fir_clk;
struct clk *sir_clk;
struct clk *cur_clk;
};
static inline void pxa_irda_disable_clk(struct pxa_irda *si)
{
if (si->cur_clk)
clk_disable_unprepare(si->cur_clk);
si->cur_clk = NULL;
}
static inline void pxa_irda_enable_firclk(struct pxa_irda *si)
{
si->cur_clk = si->fir_clk;
clk_prepare_enable(si->fir_clk);
}
static inline void pxa_irda_enable_sirclk(struct pxa_irda *si)
{
si->cur_clk = si->sir_clk;
clk_prepare_enable(si->sir_clk);
}
#define IS_FIR(si) ((si)->speed >= 4000000)
#define IRDA_FRAME_SIZE_LIMIT 2047
inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si)
{
DCSR(si->rxdma) = DCSR_NODESC;
DSADR(si->rxdma) = __PREG(ICDR);
DTADR(si->rxdma) = si->dma_rx_buff_phy;
DCMD(si->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_WIDTH1 | DCMD_BURST32 | IRDA_FRAME_SIZE_LIMIT;
DCSR(si->rxdma) |= DCSR_RUN;
}
inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si)
{
DCSR(si->txdma) = DCSR_NODESC;
DSADR(si->txdma) = si->dma_tx_buff_phy;
DTADR(si->txdma) = __PREG(ICDR);
DCMD(si->txdma) = DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST32 | si->dma_tx_buff_len;
DCSR(si->txdma) |= DCSR_RUN;
}
/*
* Set the IrDA communications mode.
*/
static void pxa_irda_set_mode(struct pxa_irda *si, int mode)
{
if (si->pdata->transceiver_mode)
si->pdata->transceiver_mode(si->dev, mode);
else {
if (gpio_is_valid(si->pdata->gpio_pwdown))
gpio_set_value(si->pdata->gpio_pwdown,
!(mode & IR_OFF) ^
!si->pdata->gpio_pwdown_inverted);
pxa2xx_transceiver_mode(si->dev, mode);
}
}
/*
* Set the IrDA communications speed.
*/
static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
{
unsigned long flags;
unsigned int divisor;
switch (speed) {
case 9600: case 19200: case 38400:
case 57600: case 115200:
/* refer to PXA250/210 Developer's Manual 10-7 */
/* BaudRate = 14.7456 MHz / (16*Divisor) */
divisor = 14745600 / (16 * speed);
local_irq_save(flags);
if (IS_FIR(si)) {
/* stop RX DMA */
DCSR(si->rxdma) &= ~DCSR_RUN;
/* disable FICP */
ICCR0 = 0;
pxa_irda_disable_clk(si);
/* set board transceiver to SIR mode */
pxa_irda_set_mode(si, IR_SIRMODE);
/* enable the STUART clock */
pxa_irda_enable_sirclk(si);
}
/* disable STUART first */
STIER = 0;
/* access DLL & DLH */
STLCR |= LCR_DLAB;
STDLL = divisor & 0xff;
STDLH = divisor >> 8;
STLCR &= ~LCR_DLAB;
si->speed = speed;
STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6;
STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE;
local_irq_restore(flags);
break;
case 4000000:
local_irq_save(flags);
/* disable STUART */
STIER = 0;
STISR = 0;
pxa_irda_disable_clk(si);
/* disable FICP first */
ICCR0 = 0;
/* set board transceiver to FIR mode */
pxa_irda_set_mode(si, IR_FIRMODE);
/* enable the FICP clock */
pxa_irda_enable_firclk(si);
si->speed = speed;
pxa_irda_fir_dma_rx_start(si);
ICCR0 = ICCR0_ITR | ICCR0_RXE;
local_irq_restore(flags);
break;
default:
return -EINVAL;
}
return 0;
}
/* SIR interrupt service routine. */
static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct pxa_irda *si = netdev_priv(dev);
int iir, lsr, data;
iir = STIIR;
switch (iir & 0x0F) {
case 0x06: /* Receiver Line Status */
lsr = STLSR;
while (lsr & LSR_FIFOE) {
data = STRBR;
if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) {
printk(KERN_DEBUG "pxa_ir: sir receiving error\n");
dev->stats.rx_errors++;
if (lsr & LSR_FE)
dev->stats.rx_frame_errors++;
if (lsr & LSR_OE)
dev->stats.rx_fifo_errors++;
} else {
dev->stats.rx_bytes++;
async_unwrap_char(dev, &dev->stats,
&si->rx_buff, data);
}
lsr = STLSR;
}
si->last_oscr = readl_relaxed(OSCR);
break;
case 0x04: /* Received Data Available */
/* forth through */
case 0x0C: /* Character Timeout Indication */
do {
dev->stats.rx_bytes++;
async_unwrap_char(dev, &dev->stats, &si->rx_buff, STRBR);
} while (STLSR & LSR_DR);
si->last_oscr = readl_relaxed(OSCR);
break;
case 0x02: /* Transmit FIFO Data Request */
while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) {
STTHR = *si->tx_buff.data++;
si->tx_buff.len -= 1;
}
if (si->tx_buff.len == 0) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head;
/* We need to ensure that the transmitter has finished. */
while ((STLSR & LSR_TEMT) == 0)
cpu_relax();
si->last_oscr = readl_relaxed(OSCR);
/*
* Ok, we've finished transmitting. Now enable
* the receiver. Sometimes we get a receive IRQ
* immediately after a transmit...
*/
if (si->newspeed) {
pxa_irda_set_speed(si, si->newspeed);
si->newspeed = 0;
} else {
/* enable IR Receiver, disable IR Transmitter */
STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6;
/* enable STUART and receive interrupts */
STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE;
}
/* I'm hungry! */
netif_wake_queue(dev);
}
break;
}
return IRQ_HANDLED;
}
/* FIR Receive DMA interrupt handler */
static void pxa_irda_fir_dma_rx_irq(int channel, void *data)
{
int dcsr = DCSR(channel);
DCSR(channel) = dcsr & ~DCSR_RUN;
printk(KERN_DEBUG "pxa_ir: fir rx dma bus error %#x\n", dcsr);
}
/* FIR Transmit DMA interrupt handler */
static void pxa_irda_fir_dma_tx_irq(int channel, void *data)
{
struct net_device *dev = data;
struct pxa_irda *si = netdev_priv(dev);
int dcsr;
dcsr = DCSR(channel);
DCSR(channel) = dcsr & ~DCSR_RUN;
if (dcsr & DCSR_ENDINTR) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += si->dma_tx_buff_len;
} else {
dev->stats.tx_errors++;
}
while (ICSR1 & ICSR1_TBY)
cpu_relax();
si->last_oscr = readl_relaxed(OSCR);
/*
* HACK: It looks like the TBY bit is dropped too soon.
* Without this delay things break.
*/
udelay(120);
if (si->newspeed) {
pxa_irda_set_speed(si, si->newspeed);
si->newspeed = 0;
} else {
int i = 64;
ICCR0 = 0;
pxa_irda_fir_dma_rx_start(si);
while ((ICSR1 & ICSR1_RNE) && i--)
(void)ICDR;
ICCR0 = ICCR0_ITR | ICCR0_RXE;
if (i < 0)
printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
}
netif_wake_queue(dev);
}
/* EIF(Error in FIFO/End in Frame) handler for FIR */
static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, int icsr0)
{
unsigned int len, stat, data;
/* Get the current data position. */
len = DTADR(si->rxdma) - si->dma_rx_buff_phy;
do {
/* Read Status, and then Data. */
stat = ICSR1;
rmb();
data = ICDR;
if (stat & (ICSR1_CRE | ICSR1_ROR)) {
dev->stats.rx_errors++;
if (stat & ICSR1_CRE) {
printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n");
dev->stats.rx_crc_errors++;
}
if (stat & ICSR1_ROR) {
printk(KERN_DEBUG "pxa_ir: fir receive overrun\n");
dev->stats.rx_over_errors++;
}
} else {
si->dma_rx_buff[len++] = data;
}
/* If we hit the end of frame, there's no point in continuing. */
if (stat & ICSR1_EOF)
break;
} while (ICSR0 & ICSR0_EIF);
if (stat & ICSR1_EOF) {
/* end of frame. */
struct sk_buff *skb;
if (icsr0 & ICSR0_FRE) {
printk(KERN_ERR "pxa_ir: dropping erroneous frame\n");
dev->stats.rx_dropped++;
return;
}
skb = alloc_skb(len+1,GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n");
dev->stats.rx_dropped++;
return;
}
/* Align IP header to 20 bytes */
skb_reserve(skb, 1);
skb_copy_to_linear_data(skb, si->dma_rx_buff, len);
skb_put(skb, len);
/* Feed it to IrLAP */
skb->dev = dev;
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
netif_rx(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
}
}
/* FIR interrupt handler */
static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct pxa_irda *si = netdev_priv(dev);
int icsr0, i = 64;
/* stop RX DMA */
DCSR(si->rxdma) &= ~DCSR_RUN;
si->last_oscr = readl_relaxed(OSCR);
icsr0 = ICSR0;
if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) {
if (icsr0 & ICSR0_FRE) {
printk(KERN_DEBUG "pxa_ir: fir receive frame error\n");
dev->stats.rx_frame_errors++;
} else {
printk(KERN_DEBUG "pxa_ir: fir receive abort\n");
dev->stats.rx_errors++;
}
ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB);
}
if (icsr0 & ICSR0_EIF) {
/* An error in FIFO occurred, or there is a end of frame */
pxa_irda_fir_irq_eif(si, dev, icsr0);
}
ICCR0 = 0;
pxa_irda_fir_dma_rx_start(si);
while ((ICSR1 & ICSR1_RNE) && i--)
(void)ICDR;
ICCR0 = ICCR0_ITR | ICCR0_RXE;
if (i < 0)
printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
return IRQ_HANDLED;
}
/* hard_xmit interface of irda device */
static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct pxa_irda *si = netdev_priv(dev);
int speed = irda_get_next_speed(skb);
/*
* Does this packet contain a request to change the interface
* speed? If so, remember it until we complete the transmission
* of this frame.
*/
if (speed != si->speed && speed != -1)
si->newspeed = speed;
/*
* If this is an empty frame, we can bypass a lot.
*/
if (skb->len == 0) {
if (si->newspeed) {
si->newspeed = 0;
pxa_irda_set_speed(si, speed);
}
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
netif_stop_queue(dev);
if (!IS_FIR(si)) {
si->tx_buff.data = si->tx_buff.head;
si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize);
/* Disable STUART interrupts and switch to transmit mode. */
STIER = 0;
STISR = IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6;
/* enable STUART and transmit interrupts */
STIER = IER_UUE | IER_TIE;
} else {
unsigned long mtt = irda_get_mtt(skb);
si->dma_tx_buff_len = skb->len;
skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len);
if (mtt)
while ((unsigned)(readl_relaxed(OSCR) - si->last_oscr)/4 < mtt)
cpu_relax();
/* stop RX DMA, disable FICP */
DCSR(si->rxdma) &= ~DCSR_RUN;
ICCR0 = 0;
pxa_irda_fir_dma_tx_start(si);
ICCR0 = ICCR0_ITR | ICCR0_TXE;
}
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
{
struct if_irda_req *rq = (struct if_irda_req *)ifreq;
struct pxa_irda *si = netdev_priv(dev);
int ret;
switch (cmd) {
case SIOCSBANDWIDTH:
ret = -EPERM;
if (capable(CAP_NET_ADMIN)) {
/*
* We are unable to set the speed if the
* device is not running.
*/
if (netif_running(dev)) {
ret = pxa_irda_set_speed(si,
rq->ifr_baudrate);
} else {
printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n");
ret = 0;
}
}
break;
case SIOCSMEDIABUSY:
ret = -EPERM;
if (capable(CAP_NET_ADMIN)) {
irda_device_set_media_busy(dev, TRUE);
ret = 0;
}
break;
case SIOCGRECEIVING:
ret = 0;
rq->ifr_receiving = IS_FIR(si) ? 0
: si->rx_buff.state != OUTSIDE_FRAME;
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static void pxa_irda_startup(struct pxa_irda *si)
{
/* Disable STUART interrupts */
STIER = 0;
/* enable STUART interrupt to the processor */
STMCR = MCR_OUT2;
/* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */
STLCR = LCR_WLS0 | LCR_WLS1;
/* enable FIFO, we use FIFO to improve performance */
STFCR = FCR_TRFIFOE | FCR_ITL_32;
/* disable FICP */
ICCR0 = 0;
/* configure FICP ICCR2 */
ICCR2 = ICCR2_TXP | ICCR2_TRIG_32;
/* configure DMAC */
DRCMR(17) = si->rxdma | DRCMR_MAPVLD;
DRCMR(18) = si->txdma | DRCMR_MAPVLD;
/* force SIR reinitialization */
si->speed = 4000000;
pxa_irda_set_speed(si, 9600);
printk(KERN_DEBUG "pxa_ir: irda startup\n");
}
static void pxa_irda_shutdown(struct pxa_irda *si)
{
unsigned long flags;
local_irq_save(flags);
/* disable STUART and interrupt */
STIER = 0;
/* disable STUART SIR mode */
STISR = 0;
/* disable DMA */
DCSR(si->txdma) &= ~DCSR_RUN;
DCSR(si->rxdma) &= ~DCSR_RUN;
/* disable FICP */
ICCR0 = 0;
/* disable the STUART or FICP clocks */
pxa_irda_disable_clk(si);
DRCMR(17) = 0;
DRCMR(18) = 0;
local_irq_restore(flags);
/* power off board transceiver */
pxa_irda_set_mode(si, IR_OFF);
printk(KERN_DEBUG "pxa_ir: irda shutdown\n");
}
static int pxa_irda_start(struct net_device *dev)
{
struct pxa_irda *si = netdev_priv(dev);
int err;
si->speed = 9600;
err = request_irq(si->uart_irq, pxa_irda_sir_irq, 0, dev->name, dev);
if (err)
goto err_irq1;
err = request_irq(si->icp_irq, pxa_irda_fir_irq, 0, dev->name, dev);
if (err)
goto err_irq2;
/*
* The interrupt must remain disabled for now.
*/
disable_irq(si->uart_irq);
disable_irq(si->icp_irq);
err = -EBUSY;
si->rxdma = pxa_request_dma("FICP_RX",DMA_PRIO_LOW, pxa_irda_fir_dma_rx_irq, dev);
if (si->rxdma < 0)
goto err_rx_dma;
si->txdma = pxa_request_dma("FICP_TX",DMA_PRIO_LOW, pxa_irda_fir_dma_tx_irq, dev);
if (si->txdma < 0)
goto err_tx_dma;
err = -ENOMEM;
si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
&si->dma_rx_buff_phy, GFP_KERNEL);
if (!si->dma_rx_buff)
goto err_dma_rx_buff;
si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
&si->dma_tx_buff_phy, GFP_KERNEL);
if (!si->dma_tx_buff)
goto err_dma_tx_buff;
/* Setup the serial port for the initial speed. */
pxa_irda_startup(si);
/*
* Open a new IrLAP layer instance.
*/
si->irlap = irlap_open(dev, &si->qos, "pxa");
err = -ENOMEM;
if (!si->irlap)
goto err_irlap;
/*
* Now enable the interrupt and start the queue
*/
enable_irq(si->uart_irq);
enable_irq(si->icp_irq);
netif_start_queue(dev);
printk(KERN_DEBUG "pxa_ir: irda driver opened\n");
return 0;
err_irlap:
pxa_irda_shutdown(si);
dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);
err_dma_tx_buff:
dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);
err_dma_rx_buff:
pxa_free_dma(si->txdma);
err_tx_dma:
pxa_free_dma(si->rxdma);
err_rx_dma:
free_irq(si->icp_irq, dev);
err_irq2:
free_irq(si->uart_irq, dev);
err_irq1:
return err;
}
static int pxa_irda_stop(struct net_device *dev)
{
struct pxa_irda *si = netdev_priv(dev);
netif_stop_queue(dev);
pxa_irda_shutdown(si);
/* Stop IrLAP */
if (si->irlap) {
irlap_close(si->irlap);
si->irlap = NULL;
}
free_irq(si->uart_irq, dev);
free_irq(si->icp_irq, dev);
pxa_free_dma(si->rxdma);
pxa_free_dma(si->txdma);
if (si->dma_rx_buff)
dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);
if (si->dma_tx_buff)
dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);
printk(KERN_DEBUG "pxa_ir: irda driver closed\n");
return 0;
}
static int pxa_irda_suspend(struct platform_device *_dev, pm_message_t state)
{
struct net_device *dev = platform_get_drvdata(_dev);
struct pxa_irda *si;
if (dev && netif_running(dev)) {
si = netdev_priv(dev);
netif_device_detach(dev);
pxa_irda_shutdown(si);
}
return 0;
}
static int pxa_irda_resume(struct platform_device *_dev)
{
struct net_device *dev = platform_get_drvdata(_dev);
struct pxa_irda *si;
if (dev && netif_running(dev)) {
si = netdev_priv(dev);
pxa_irda_startup(si);
netif_device_attach(dev);
netif_wake_queue(dev);
}
return 0;
}
static int pxa_irda_init_iobuf(iobuff_t *io, int size)
{
io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);
if (io->head != NULL) {
io->truesize = size;
io->in_frame = FALSE;
io->state = OUTSIDE_FRAME;
io->data = io->head;
}
return io->head ? 0 : -ENOMEM;
}
static const struct net_device_ops pxa_irda_netdev_ops = {
.ndo_open = pxa_irda_start,
.ndo_stop = pxa_irda_stop,
.ndo_start_xmit = pxa_irda_hard_xmit,
.ndo_do_ioctl = pxa_irda_ioctl,
};
static int pxa_irda_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct pxa_irda *si;
unsigned int baudrate_mask;
int err;
if (!pdev->dev.platform_data)
return -ENODEV;
err = request_mem_region(__PREG(STUART), 0x24, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_1;
err = request_mem_region(__PREG(FICP), 0x1c, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_2;
dev = alloc_irdadev(sizeof(struct pxa_irda));
if (!dev) {
err = -ENOMEM;
goto err_mem_3;
}
SET_NETDEV_DEV(dev, &pdev->dev);
si = netdev_priv(dev);
si->dev = &pdev->dev;
si->pdata = pdev->dev.platform_data;
si->uart_irq = platform_get_irq(pdev, 0);
si->icp_irq = platform_get_irq(pdev, 1);
si->sir_clk = clk_get(&pdev->dev, "UARTCLK");
si->fir_clk = clk_get(&pdev->dev, "FICPCLK");
if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) {
err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk);
goto err_mem_4;
}
/*
* Initialise the SIR buffers
*/
err = pxa_irda_init_iobuf(&si->rx_buff, 14384);
if (err)
goto err_mem_4;
err = pxa_irda_init_iobuf(&si->tx_buff, 4000);
if (err)
goto err_mem_5;
if (gpio_is_valid(si->pdata->gpio_pwdown)) {
err = gpio_request(si->pdata->gpio_pwdown, "IrDA switch");
if (err)
goto err_startup;
err = gpio_direction_output(si->pdata->gpio_pwdown,
!si->pdata->gpio_pwdown_inverted);
if (err) {
gpio_free(si->pdata->gpio_pwdown);
goto err_startup;
}
}
if (si->pdata->startup) {
err = si->pdata->startup(si->dev);
if (err)
goto err_startup;
}
if (gpio_is_valid(si->pdata->gpio_pwdown) && si->pdata->startup)
dev_warn(si->dev, "gpio_pwdown and startup() both defined!\n");
dev->netdev_ops = &pxa_irda_netdev_ops;
irda_init_max_qos_capabilies(&si->qos);
baudrate_mask = 0;
if (si->pdata->transceiver_cap & IR_SIRMODE)
baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
if (si->pdata->transceiver_cap & IR_FIRMODE)
baudrate_mask |= IR_4000000 << 8;
si->qos.baud_rate.bits &= baudrate_mask;
si->qos.min_turn_time.bits = 7; /* 1ms or more */
irda_qos_bits_to_value(&si->qos);
err = register_netdev(dev);
if (err == 0)
platform_set_drvdata(pdev, dev);
if (err) {
if (si->pdata->shutdown)
si->pdata->shutdown(si->dev);
err_startup:
kfree(si->tx_buff.head);
err_mem_5:
kfree(si->rx_buff.head);
err_mem_4:
if (si->sir_clk && !IS_ERR(si->sir_clk))
clk_put(si->sir_clk);
if (si->fir_clk && !IS_ERR(si->fir_clk))
clk_put(si->fir_clk);
free_netdev(dev);
err_mem_3:
release_mem_region(__PREG(FICP), 0x1c);
err_mem_2:
release_mem_region(__PREG(STUART), 0x24);
}
err_mem_1:
return err;
}
static int pxa_irda_remove(struct platform_device *_dev)
{
struct net_device *dev = platform_get_drvdata(_dev);
if (dev) {
struct pxa_irda *si = netdev_priv(dev);
unregister_netdev(dev);
if (gpio_is_valid(si->pdata->gpio_pwdown))
gpio_free(si->pdata->gpio_pwdown);
if (si->pdata->shutdown)
si->pdata->shutdown(si->dev);
kfree(si->tx_buff.head);
kfree(si->rx_buff.head);
clk_put(si->fir_clk);
clk_put(si->sir_clk);
free_netdev(dev);
}
release_mem_region(__PREG(STUART), 0x24);
release_mem_region(__PREG(FICP), 0x1c);
return 0;
}
static struct platform_driver pxa_ir_driver = {
.driver = {
.name = "pxa2xx-ir",
.owner = THIS_MODULE,
},
.probe = pxa_irda_probe,
.remove = pxa_irda_remove,
.suspend = pxa_irda_suspend,
.resume = pxa_irda_resume,
};
module_platform_driver(pxa_ir_driver);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa2xx-ir");

1151
drivers/net/irda/sa1100_ir.c Normal file

File diff suppressed because it is too large Load diff

875
drivers/net/irda/sh_irda.c Normal file
View file

@ -0,0 +1,875 @@
/*
* SuperH IrDA Driver
*
* Copyright (C) 2010 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* Based on sh_sir.c
* Copyright (C) 2009 Renesas Solutions Corp.
* Copyright 2006-2009 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* CAUTION
*
* This driver is very simple.
* So, it doesn't have below support now
* - MIR/FIR support
* - DMA transfer support
* - FIFO mode support
*/
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#define DRIVER_NAME "sh_irda"
#define __IRDARAM_LEN 0x1039
#define IRTMR 0x1F00 /* Transfer mode */
#define IRCFR 0x1F02 /* Configuration */
#define IRCTR 0x1F04 /* IR control */
#define IRTFLR 0x1F20 /* Transmit frame length */
#define IRTCTR 0x1F22 /* Transmit control */
#define IRRFLR 0x1F40 /* Receive frame length */
#define IRRCTR 0x1F42 /* Receive control */
#define SIRISR 0x1F60 /* SIR-UART mode interrupt source */
#define SIRIMR 0x1F62 /* SIR-UART mode interrupt mask */
#define SIRICR 0x1F64 /* SIR-UART mode interrupt clear */
#define SIRBCR 0x1F68 /* SIR-UART mode baud rate count */
#define MFIRISR 0x1F70 /* MIR/FIR mode interrupt source */
#define MFIRIMR 0x1F72 /* MIR/FIR mode interrupt mask */
#define MFIRICR 0x1F74 /* MIR/FIR mode interrupt clear */
#define CRCCTR 0x1F80 /* CRC engine control */
#define CRCIR 0x1F86 /* CRC engine input data */
#define CRCCR 0x1F8A /* CRC engine calculation */
#define CRCOR 0x1F8E /* CRC engine output data */
#define FIFOCP 0x1FC0 /* FIFO current pointer */
#define FIFOFP 0x1FC2 /* FIFO follow pointer */
#define FIFORSMSK 0x1FC4 /* FIFO receive status mask */
#define FIFORSOR 0x1FC6 /* FIFO receive status OR */
#define FIFOSEL 0x1FC8 /* FIFO select */
#define FIFORS 0x1FCA /* FIFO receive status */
#define FIFORFL 0x1FCC /* FIFO receive frame length */
#define FIFORAMCP 0x1FCE /* FIFO RAM current pointer */
#define FIFORAMFP 0x1FD0 /* FIFO RAM follow pointer */
#define BIFCTL 0x1FD2 /* BUS interface control */
#define IRDARAM 0x0000 /* IrDA buffer RAM */
#define IRDARAM_LEN __IRDARAM_LEN /* - 8/16/32 (read-only for 32) */
/* IRTMR */
#define TMD_MASK (0x3 << 14) /* Transfer Mode */
#define TMD_SIR (0x0 << 14)
#define TMD_MIR (0x3 << 14)
#define TMD_FIR (0x2 << 14)
#define FIFORIM (1 << 8) /* FIFO receive interrupt mask */
#define MIM (1 << 4) /* MIR/FIR Interrupt Mask */
#define SIM (1 << 0) /* SIR Interrupt Mask */
#define xIM_MASK (FIFORIM | MIM | SIM)
/* IRCFR */
#define RTO_SHIFT 8 /* shift for Receive Timeout */
#define RTO (0x3 << RTO_SHIFT)
/* IRTCTR */
#define ARMOD (1 << 15) /* Auto-Receive Mode */
#define TE (1 << 0) /* Transmit Enable */
/* IRRFLR */
#define RFL_MASK (0x1FFF) /* mask for Receive Frame Length */
/* IRRCTR */
#define RE (1 << 0) /* Receive Enable */
/*
* SIRISR, SIRIMR, SIRICR,
* MFIRISR, MFIRIMR, MFIRICR
*/
#define FRE (1 << 15) /* Frame Receive End */
#define TROV (1 << 11) /* Transfer Area Overflow */
#define xIR_9 (1 << 9)
#define TOT xIR_9 /* for SIR Timeout */
#define ABTD xIR_9 /* for MIR/FIR Abort Detection */
#define xIR_8 (1 << 8)
#define FER xIR_8 /* for SIR Framing Error */
#define CRCER xIR_8 /* for MIR/FIR CRC error */
#define FTE (1 << 7) /* Frame Transmit End */
#define xIR_MASK (FRE | TROV | xIR_9 | xIR_8 | FTE)
/* SIRBCR */
#define BRC_MASK (0x3F) /* mask for Baud Rate Count */
/* CRCCTR */
#define CRC_RST (1 << 15) /* CRC Engine Reset */
#define CRC_CT_MASK 0x0FFF /* mask for CRC Engine Input Data Count */
/* CRCIR */
#define CRC_IN_MASK 0x0FFF /* mask for CRC Engine Input Data */
/************************************************************************
enum / structure
************************************************************************/
enum sh_irda_mode {
SH_IRDA_NONE = 0,
SH_IRDA_SIR,
SH_IRDA_MIR,
SH_IRDA_FIR,
};
struct sh_irda_self;
struct sh_irda_xir_func {
int (*xir_fre) (struct sh_irda_self *self);
int (*xir_trov) (struct sh_irda_self *self);
int (*xir_9) (struct sh_irda_self *self);
int (*xir_8) (struct sh_irda_self *self);
int (*xir_fte) (struct sh_irda_self *self);
};
struct sh_irda_self {
void __iomem *membase;
unsigned int irq;
struct platform_device *pdev;
struct net_device *ndev;
struct irlap_cb *irlap;
struct qos_info qos;
iobuff_t tx_buff;
iobuff_t rx_buff;
enum sh_irda_mode mode;
spinlock_t lock;
struct sh_irda_xir_func *xir_func;
};
/************************************************************************
common function
************************************************************************/
static void sh_irda_write(struct sh_irda_self *self, u32 offset, u16 data)
{
unsigned long flags;
spin_lock_irqsave(&self->lock, flags);
iowrite16(data, self->membase + offset);
spin_unlock_irqrestore(&self->lock, flags);
}
static u16 sh_irda_read(struct sh_irda_self *self, u32 offset)
{
unsigned long flags;
u16 ret;
spin_lock_irqsave(&self->lock, flags);
ret = ioread16(self->membase + offset);
spin_unlock_irqrestore(&self->lock, flags);
return ret;
}
static void sh_irda_update_bits(struct sh_irda_self *self, u32 offset,
u16 mask, u16 data)
{
unsigned long flags;
u16 old, new;
spin_lock_irqsave(&self->lock, flags);
old = ioread16(self->membase + offset);
new = (old & ~mask) | data;
if (old != new)
iowrite16(data, self->membase + offset);
spin_unlock_irqrestore(&self->lock, flags);
}
/************************************************************************
mode function
************************************************************************/
/*=====================================
*
* common
*
*=====================================*/
static void sh_irda_rcv_ctrl(struct sh_irda_self *self, int enable)
{
struct device *dev = &self->ndev->dev;
sh_irda_update_bits(self, IRRCTR, RE, enable ? RE : 0);
dev_dbg(dev, "recv %s\n", enable ? "enable" : "disable");
}
static int sh_irda_set_timeout(struct sh_irda_self *self, int interval)
{
struct device *dev = &self->ndev->dev;
if (SH_IRDA_SIR != self->mode)
interval = 0;
if (interval < 0 || interval > 2) {
dev_err(dev, "unsupported timeout interval\n");
return -EINVAL;
}
sh_irda_update_bits(self, IRCFR, RTO, interval << RTO_SHIFT);
return 0;
}
static int sh_irda_set_baudrate(struct sh_irda_self *self, int baudrate)
{
struct device *dev = &self->ndev->dev;
u16 val;
if (baudrate < 0)
return 0;
if (SH_IRDA_SIR != self->mode) {
dev_err(dev, "it is not SIR mode\n");
return -EINVAL;
}
/*
* Baud rate (bits/s) =
* (48 MHz / 26) / (baud rate counter value + 1) x 16
*/
val = (48000000 / 26 / 16 / baudrate) - 1;
dev_dbg(dev, "baudrate = %d, val = 0x%02x\n", baudrate, val);
sh_irda_update_bits(self, SIRBCR, BRC_MASK, val);
return 0;
}
static int sh_irda_get_rcv_length(struct sh_irda_self *self)
{
return RFL_MASK & sh_irda_read(self, IRRFLR);
}
/*=====================================
*
* NONE MODE
*
*=====================================*/
static int sh_irda_xir_fre(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: frame recv\n");
return 0;
}
static int sh_irda_xir_trov(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: buffer ram over\n");
return 0;
}
static int sh_irda_xir_9(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: time over\n");
return 0;
}
static int sh_irda_xir_8(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: framing error\n");
return 0;
}
static int sh_irda_xir_fte(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "none mode: frame transmit end\n");
return 0;
}
static struct sh_irda_xir_func sh_irda_xir_func = {
.xir_fre = sh_irda_xir_fre,
.xir_trov = sh_irda_xir_trov,
.xir_9 = sh_irda_xir_9,
.xir_8 = sh_irda_xir_8,
.xir_fte = sh_irda_xir_fte,
};
/*=====================================
*
* MIR/FIR MODE
*
* MIR/FIR are not supported now
*=====================================*/
static struct sh_irda_xir_func sh_irda_mfir_func = {
.xir_fre = sh_irda_xir_fre,
.xir_trov = sh_irda_xir_trov,
.xir_9 = sh_irda_xir_9,
.xir_8 = sh_irda_xir_8,
.xir_fte = sh_irda_xir_fte,
};
/*=====================================
*
* SIR MODE
*
*=====================================*/
static int sh_irda_sir_fre(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
u16 data16;
u8 *data = (u8 *)&data16;
int len = sh_irda_get_rcv_length(self);
int i, j;
if (len > IRDARAM_LEN)
len = IRDARAM_LEN;
dev_dbg(dev, "frame recv length = %d\n", len);
for (i = 0; i < len; i++) {
j = i % 2;
if (!j)
data16 = sh_irda_read(self, IRDARAM + i);
async_unwrap_char(self->ndev, &self->ndev->stats,
&self->rx_buff, data[j]);
}
self->ndev->last_rx = jiffies;
sh_irda_rcv_ctrl(self, 1);
return 0;
}
static int sh_irda_sir_trov(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "buffer ram over\n");
sh_irda_rcv_ctrl(self, 1);
return 0;
}
static int sh_irda_sir_tot(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "time over\n");
sh_irda_set_baudrate(self, 9600);
sh_irda_rcv_ctrl(self, 1);
return 0;
}
static int sh_irda_sir_fer(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_err(dev, "framing error\n");
sh_irda_rcv_ctrl(self, 1);
return 0;
}
static int sh_irda_sir_fte(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
dev_dbg(dev, "frame transmit end\n");
netif_wake_queue(self->ndev);
return 0;
}
static struct sh_irda_xir_func sh_irda_sir_func = {
.xir_fre = sh_irda_sir_fre,
.xir_trov = sh_irda_sir_trov,
.xir_9 = sh_irda_sir_tot,
.xir_8 = sh_irda_sir_fer,
.xir_fte = sh_irda_sir_fte,
};
static void sh_irda_set_mode(struct sh_irda_self *self, enum sh_irda_mode mode)
{
struct device *dev = &self->ndev->dev;
struct sh_irda_xir_func *func;
const char *name;
u16 data;
switch (mode) {
case SH_IRDA_SIR:
name = "SIR";
data = TMD_SIR;
func = &sh_irda_sir_func;
break;
case SH_IRDA_MIR:
name = "MIR";
data = TMD_MIR;
func = &sh_irda_mfir_func;
break;
case SH_IRDA_FIR:
name = "FIR";
data = TMD_FIR;
func = &sh_irda_mfir_func;
break;
default:
name = "NONE";
data = 0;
func = &sh_irda_xir_func;
break;
}
self->mode = mode;
self->xir_func = func;
sh_irda_update_bits(self, IRTMR, TMD_MASK, data);
dev_dbg(dev, "switch to %s mode", name);
}
/************************************************************************
irq function
************************************************************************/
static void sh_irda_set_irq_mask(struct sh_irda_self *self)
{
u16 tmr_hole;
u16 xir_reg;
/* set all mask */
sh_irda_update_bits(self, IRTMR, xIM_MASK, xIM_MASK);
sh_irda_update_bits(self, SIRIMR, xIR_MASK, xIR_MASK);
sh_irda_update_bits(self, MFIRIMR, xIR_MASK, xIR_MASK);
/* clear irq */
sh_irda_update_bits(self, SIRICR, xIR_MASK, xIR_MASK);
sh_irda_update_bits(self, MFIRICR, xIR_MASK, xIR_MASK);
switch (self->mode) {
case SH_IRDA_SIR:
tmr_hole = SIM;
xir_reg = SIRIMR;
break;
case SH_IRDA_MIR:
case SH_IRDA_FIR:
tmr_hole = MIM;
xir_reg = MFIRIMR;
break;
default:
tmr_hole = 0;
xir_reg = 0;
break;
}
/* open mask */
if (xir_reg) {
sh_irda_update_bits(self, IRTMR, tmr_hole, 0);
sh_irda_update_bits(self, xir_reg, xIR_MASK, 0);
}
}
static irqreturn_t sh_irda_irq(int irq, void *dev_id)
{
struct sh_irda_self *self = dev_id;
struct sh_irda_xir_func *func = self->xir_func;
u16 isr = sh_irda_read(self, SIRISR);
/* clear irq */
sh_irda_write(self, SIRICR, isr);
if (isr & FRE)
func->xir_fre(self);
if (isr & TROV)
func->xir_trov(self);
if (isr & xIR_9)
func->xir_9(self);
if (isr & xIR_8)
func->xir_8(self);
if (isr & FTE)
func->xir_fte(self);
return IRQ_HANDLED;
}
/************************************************************************
CRC function
************************************************************************/
static void sh_irda_crc_reset(struct sh_irda_self *self)
{
sh_irda_write(self, CRCCTR, CRC_RST);
}
static void sh_irda_crc_add(struct sh_irda_self *self, u16 data)
{
sh_irda_write(self, CRCIR, data & CRC_IN_MASK);
}
static u16 sh_irda_crc_cnt(struct sh_irda_self *self)
{
return CRC_CT_MASK & sh_irda_read(self, CRCCTR);
}
static u16 sh_irda_crc_out(struct sh_irda_self *self)
{
return sh_irda_read(self, CRCOR);
}
static int sh_irda_crc_init(struct sh_irda_self *self)
{
struct device *dev = &self->ndev->dev;
int ret = -EIO;
u16 val;
sh_irda_crc_reset(self);
sh_irda_crc_add(self, 0xCC);
sh_irda_crc_add(self, 0xF5);
sh_irda_crc_add(self, 0xF1);
sh_irda_crc_add(self, 0xA7);
val = sh_irda_crc_cnt(self);
if (4 != val) {
dev_err(dev, "CRC count error %x\n", val);
goto crc_init_out;
}
val = sh_irda_crc_out(self);
if (0x51DF != val) {
dev_err(dev, "CRC result error%x\n", val);
goto crc_init_out;
}
ret = 0;
crc_init_out:
sh_irda_crc_reset(self);
return ret;
}
/************************************************************************
iobuf function
************************************************************************/
static void sh_irda_remove_iobuf(struct sh_irda_self *self)
{
kfree(self->rx_buff.head);
self->tx_buff.head = NULL;
self->tx_buff.data = NULL;
self->rx_buff.head = NULL;
self->rx_buff.data = NULL;
}
static int sh_irda_init_iobuf(struct sh_irda_self *self, int rxsize, int txsize)
{
if (self->rx_buff.head ||
self->tx_buff.head) {
dev_err(&self->ndev->dev, "iobuff has already existed.");
return -EINVAL;
}
/* rx_buff */
self->rx_buff.head = kmalloc(rxsize, GFP_KERNEL);
if (!self->rx_buff.head)
return -ENOMEM;
self->rx_buff.truesize = rxsize;
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
self->rx_buff.data = self->rx_buff.head;
/* tx_buff */
self->tx_buff.head = self->membase + IRDARAM;
self->tx_buff.truesize = IRDARAM_LEN;
return 0;
}
/************************************************************************
net_device_ops function
************************************************************************/
static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct sh_irda_self *self = netdev_priv(ndev);
struct device *dev = &self->ndev->dev;
int speed = irda_get_next_speed(skb);
int ret;
dev_dbg(dev, "hard xmit\n");
netif_stop_queue(ndev);
sh_irda_rcv_ctrl(self, 0);
ret = sh_irda_set_baudrate(self, speed);
if (ret < 0)
goto sh_irda_hard_xmit_end;
self->tx_buff.len = 0;
if (skb->len) {
unsigned long flags;
spin_lock_irqsave(&self->lock, flags);
self->tx_buff.len = async_wrap_skb(skb,
self->tx_buff.head,
self->tx_buff.truesize);
spin_unlock_irqrestore(&self->lock, flags);
if (self->tx_buff.len > self->tx_buff.truesize)
self->tx_buff.len = self->tx_buff.truesize;
sh_irda_write(self, IRTFLR, self->tx_buff.len);
sh_irda_write(self, IRTCTR, ARMOD | TE);
} else
goto sh_irda_hard_xmit_end;
dev_kfree_skb(skb);
return 0;
sh_irda_hard_xmit_end:
sh_irda_set_baudrate(self, 9600);
netif_wake_queue(self->ndev);
sh_irda_rcv_ctrl(self, 1);
dev_kfree_skb(skb);
return ret;
}
static int sh_irda_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
{
/*
* FIXME
*
* This function is needed for irda framework.
* But nothing to do now
*/
return 0;
}
static struct net_device_stats *sh_irda_stats(struct net_device *ndev)
{
struct sh_irda_self *self = netdev_priv(ndev);
return &self->ndev->stats;
}
static int sh_irda_open(struct net_device *ndev)
{
struct sh_irda_self *self = netdev_priv(ndev);
int err;
pm_runtime_get_sync(&self->pdev->dev);
err = sh_irda_crc_init(self);
if (err)
goto open_err;
sh_irda_set_mode(self, SH_IRDA_SIR);
sh_irda_set_timeout(self, 2);
sh_irda_set_baudrate(self, 9600);
self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
if (!self->irlap) {
err = -ENODEV;
goto open_err;
}
netif_start_queue(ndev);
sh_irda_rcv_ctrl(self, 1);
sh_irda_set_irq_mask(self);
dev_info(&ndev->dev, "opened\n");
return 0;
open_err:
pm_runtime_put_sync(&self->pdev->dev);
return err;
}
static int sh_irda_stop(struct net_device *ndev)
{
struct sh_irda_self *self = netdev_priv(ndev);
/* Stop IrLAP */
if (self->irlap) {
irlap_close(self->irlap);
self->irlap = NULL;
}
netif_stop_queue(ndev);
pm_runtime_put_sync(&self->pdev->dev);
dev_info(&ndev->dev, "stopped\n");
return 0;
}
static const struct net_device_ops sh_irda_ndo = {
.ndo_open = sh_irda_open,
.ndo_stop = sh_irda_stop,
.ndo_start_xmit = sh_irda_hard_xmit,
.ndo_do_ioctl = sh_irda_ioctl,
.ndo_get_stats = sh_irda_stats,
};
/************************************************************************
platform_driver function
************************************************************************/
static int sh_irda_probe(struct platform_device *pdev)
{
struct net_device *ndev;
struct sh_irda_self *self;
struct resource *res;
int irq;
int err = -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!res || irq < 0) {
dev_err(&pdev->dev, "Not enough platform resources.\n");
goto exit;
}
ndev = alloc_irdadev(sizeof(*self));
if (!ndev)
goto exit;
self = netdev_priv(ndev);
self->membase = ioremap_nocache(res->start, resource_size(res));
if (!self->membase) {
err = -ENXIO;
dev_err(&pdev->dev, "Unable to ioremap.\n");
goto err_mem_1;
}
err = sh_irda_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME);
if (err)
goto err_mem_2;
self->pdev = pdev;
pm_runtime_enable(&pdev->dev);
irda_init_max_qos_capabilies(&self->qos);
ndev->netdev_ops = &sh_irda_ndo;
ndev->irq = irq;
self->ndev = ndev;
self->qos.baud_rate.bits &= IR_9600; /* FIXME */
self->qos.min_turn_time.bits = 1; /* 10 ms or more */
spin_lock_init(&self->lock);
irda_qos_bits_to_value(&self->qos);
err = register_netdev(ndev);
if (err)
goto err_mem_4;
platform_set_drvdata(pdev, ndev);
err = devm_request_irq(&pdev->dev, irq, sh_irda_irq, 0, "sh_irda", self);
if (err) {
dev_warn(&pdev->dev, "Unable to attach sh_irda interrupt\n");
goto err_mem_4;
}
dev_info(&pdev->dev, "SuperH IrDA probed\n");
goto exit;
err_mem_4:
pm_runtime_disable(&pdev->dev);
sh_irda_remove_iobuf(self);
err_mem_2:
iounmap(self->membase);
err_mem_1:
free_netdev(ndev);
exit:
return err;
}
static int sh_irda_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct sh_irda_self *self = netdev_priv(ndev);
if (!self)
return 0;
unregister_netdev(ndev);
pm_runtime_disable(&pdev->dev);
sh_irda_remove_iobuf(self);
iounmap(self->membase);
free_netdev(ndev);
return 0;
}
static int sh_irda_runtime_nop(struct device *dev)
{
/* Runtime PM callback shared between ->runtime_suspend()
* and ->runtime_resume(). Simply returns success.
*
* This driver re-initializes all registers after
* pm_runtime_get_sync() anyway so there is no need
* to save and restore registers here.
*/
return 0;
}
static const struct dev_pm_ops sh_irda_pm_ops = {
.runtime_suspend = sh_irda_runtime_nop,
.runtime_resume = sh_irda_runtime_nop,
};
static struct platform_driver sh_irda_driver = {
.probe = sh_irda_probe,
.remove = sh_irda_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &sh_irda_pm_ops,
},
};
module_platform_driver(sh_irda_driver);
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("SuperH IrDA driver");
MODULE_LICENSE("GPL");

811
drivers/net/irda/sh_sir.c Normal file
View file

@ -0,0 +1,811 @@
/*
* SuperH IrDA Driver
*
* Copyright (C) 2009 Renesas Solutions Corp.
* Kuninori Morimoto <morimoto.kuninori@renesas.com>
*
* Based on bfin_sir.c
* Copyright 2006-2009 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#include <asm/clock.h>
#define DRIVER_NAME "sh_sir"
#define RX_PHASE (1 << 0)
#define TX_PHASE (1 << 1)
#define TX_COMP_PHASE (1 << 2) /* tx complete */
#define NONE_PHASE (1 << 31)
#define IRIF_RINTCLR 0x0016 /* DMA rx interrupt source clear */
#define IRIF_TINTCLR 0x0018 /* DMA tx interrupt source clear */
#define IRIF_SIR0 0x0020 /* IrDA-SIR10 control */
#define IRIF_SIR1 0x0022 /* IrDA-SIR10 baudrate error correction */
#define IRIF_SIR2 0x0024 /* IrDA-SIR10 baudrate count */
#define IRIF_SIR3 0x0026 /* IrDA-SIR10 status */
#define IRIF_SIR_FRM 0x0028 /* Hardware frame processing set */
#define IRIF_SIR_EOF 0x002A /* EOF value */
#define IRIF_SIR_FLG 0x002C /* Flag clear */
#define IRIF_UART_STS2 0x002E /* UART status 2 */
#define IRIF_UART0 0x0030 /* UART control */
#define IRIF_UART1 0x0032 /* UART status */
#define IRIF_UART2 0x0034 /* UART mode */
#define IRIF_UART3 0x0036 /* UART transmit data */
#define IRIF_UART4 0x0038 /* UART receive data */
#define IRIF_UART5 0x003A /* UART interrupt mask */
#define IRIF_UART6 0x003C /* UART baud rate error correction */
#define IRIF_UART7 0x003E /* UART baud rate count set */
#define IRIF_CRC0 0x0040 /* CRC engine control */
#define IRIF_CRC1 0x0042 /* CRC engine input data */
#define IRIF_CRC2 0x0044 /* CRC engine calculation */
#define IRIF_CRC3 0x0046 /* CRC engine output data 1 */
#define IRIF_CRC4 0x0048 /* CRC engine output data 2 */
/* IRIF_SIR0 */
#define IRTPW (1 << 1) /* transmit pulse width select */
#define IRERRC (1 << 0) /* Clear receive pulse width error */
/* IRIF_SIR3 */
#define IRERR (1 << 0) /* received pulse width Error */
/* IRIF_SIR_FRM */
#define EOFD (1 << 9) /* EOF detection flag */
#define FRER (1 << 8) /* Frame Error bit */
#define FRP (1 << 0) /* Frame processing set */
/* IRIF_UART_STS2 */
#define IRSME (1 << 6) /* Receive Sum Error flag */
#define IROVE (1 << 5) /* Receive Overrun Error flag */
#define IRFRE (1 << 4) /* Receive Framing Error flag */
#define IRPRE (1 << 3) /* Receive Parity Error flag */
/* IRIF_UART0_*/
#define TBEC (1 << 2) /* Transmit Data Clear */
#define RIE (1 << 1) /* Receive Enable */
#define TIE (1 << 0) /* Transmit Enable */
/* IRIF_UART1 */
#define URSME (1 << 6) /* Receive Sum Error Flag */
#define UROVE (1 << 5) /* Receive Overrun Error Flag */
#define URFRE (1 << 4) /* Receive Framing Error Flag */
#define URPRE (1 << 3) /* Receive Parity Error Flag */
#define RBF (1 << 2) /* Receive Buffer Full Flag */
#define TSBE (1 << 1) /* Transmit Shift Buffer Empty Flag */
#define TBE (1 << 0) /* Transmit Buffer Empty flag */
#define TBCOMP (TSBE | TBE)
/* IRIF_UART5 */
#define RSEIM (1 << 6) /* Receive Sum Error Flag IRQ Mask */
#define RBFIM (1 << 2) /* Receive Buffer Full Flag IRQ Mask */
#define TSBEIM (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */
#define TBEIM (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */
#define RX_MASK (RSEIM | RBFIM)
/* IRIF_CRC0 */
#define CRC_RST (1 << 15) /* CRC Engine Reset */
#define CRC_CT_MASK 0x0FFF
/************************************************************************
structure
************************************************************************/
struct sh_sir_self {
void __iomem *membase;
unsigned int irq;
struct clk *clk;
struct net_device *ndev;
struct irlap_cb *irlap;
struct qos_info qos;
iobuff_t tx_buff;
iobuff_t rx_buff;
};
/************************************************************************
common function
************************************************************************/
static void sh_sir_write(struct sh_sir_self *self, u32 offset, u16 data)
{
iowrite16(data, self->membase + offset);
}
static u16 sh_sir_read(struct sh_sir_self *self, u32 offset)
{
return ioread16(self->membase + offset);
}
static void sh_sir_update_bits(struct sh_sir_self *self, u32 offset,
u16 mask, u16 data)
{
u16 old, new;
old = sh_sir_read(self, offset);
new = (old & ~mask) | data;
if (old != new)
sh_sir_write(self, offset, new);
}
/************************************************************************
CRC function
************************************************************************/
static void sh_sir_crc_reset(struct sh_sir_self *self)
{
sh_sir_write(self, IRIF_CRC0, CRC_RST);
}
static void sh_sir_crc_add(struct sh_sir_self *self, u8 data)
{
sh_sir_write(self, IRIF_CRC1, (u16)data);
}
static u16 sh_sir_crc_cnt(struct sh_sir_self *self)
{
return CRC_CT_MASK & sh_sir_read(self, IRIF_CRC0);
}
static u16 sh_sir_crc_out(struct sh_sir_self *self)
{
return sh_sir_read(self, IRIF_CRC4);
}
static int sh_sir_crc_init(struct sh_sir_self *self)
{
struct device *dev = &self->ndev->dev;
int ret = -EIO;
u16 val;
sh_sir_crc_reset(self);
sh_sir_crc_add(self, 0xCC);
sh_sir_crc_add(self, 0xF5);
sh_sir_crc_add(self, 0xF1);
sh_sir_crc_add(self, 0xA7);
val = sh_sir_crc_cnt(self);
if (4 != val) {
dev_err(dev, "CRC count error %x\n", val);
goto crc_init_out;
}
val = sh_sir_crc_out(self);
if (0x51DF != val) {
dev_err(dev, "CRC result error%x\n", val);
goto crc_init_out;
}
ret = 0;
crc_init_out:
sh_sir_crc_reset(self);
return ret;
}
/************************************************************************
baud rate functions
************************************************************************/
#define SCLK_BASE 1843200 /* 1.8432MHz */
static u32 sh_sir_find_sclk(struct clk *irda_clk)
{
struct cpufreq_frequency_table *freq_table = irda_clk->freq_table;
struct cpufreq_frequency_table *pos;
struct clk *pclk = clk_get(NULL, "peripheral_clk");
u32 limit, min = 0xffffffff, tmp;
int index = 0;
limit = clk_get_rate(pclk);
clk_put(pclk);
/* IrDA can not set over peripheral_clk */
cpufreq_for_each_valid_entry(pos, freq_table) {
u32 freq = pos->frequency;
/* IrDA should not over peripheral_clk */
if (freq > limit)
continue;
tmp = freq % SCLK_BASE;
if (tmp < min) {
min = tmp;
index = pos - freq_table;
}
}
return freq_table[index].frequency;
}
#define ERR_ROUNDING(a) ((a + 5000) / 10000)
static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate)
{
struct clk *clk;
struct device *dev = &self->ndev->dev;
u32 rate;
u16 uabca, uabc;
u16 irbca, irbc;
u32 min, rerr, tmp;
int i;
/* Baud Rate Error Correction x 10000 */
u32 rate_err_array[] = {
0, 625, 1250, 1875,
2500, 3125, 3750, 4375,
5000, 5625, 6250, 6875,
7500, 8125, 8750, 9375,
};
/*
* FIXME
*
* it support 9600 only now
*/
switch (baudrate) {
case 9600:
break;
default:
dev_err(dev, "un-supported baudrate %d\n", baudrate);
return -EIO;
}
clk = clk_get(NULL, "irda_clk");
if (IS_ERR(clk)) {
dev_err(dev, "can not get irda_clk\n");
return -EIO;
}
clk_set_rate(clk, sh_sir_find_sclk(clk));
rate = clk_get_rate(clk);
clk_put(clk);
dev_dbg(dev, "selected sclk = %d\n", rate);
/*
* CALCULATION
*
* 1843200 = system rate / (irbca + (irbc + 1))
*/
irbc = rate / SCLK_BASE;
tmp = rate - (SCLK_BASE * irbc);
tmp *= 10000;
rerr = tmp / SCLK_BASE;
min = 0xffffffff;
irbca = 0;
for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
tmp = abs(rate_err_array[i] - rerr);
if (min > tmp) {
min = tmp;
irbca = i;
}
}
tmp = rate / (irbc + ERR_ROUNDING(rate_err_array[irbca]));
if ((SCLK_BASE / 100) < abs(tmp - SCLK_BASE))
dev_warn(dev, "IrDA freq error margin over %d\n", tmp);
dev_dbg(dev, "target = %d, result = %d, infrared = %d.%d\n",
SCLK_BASE, tmp, irbc, rate_err_array[irbca]);
irbca = (irbca & 0xF) << 4;
irbc = (irbc - 1) & 0xF;
if (!irbc) {
dev_err(dev, "sh_sir can not set 0 in IRIF_SIR2\n");
return -EIO;
}
sh_sir_write(self, IRIF_SIR0, IRTPW | IRERRC);
sh_sir_write(self, IRIF_SIR1, irbca);
sh_sir_write(self, IRIF_SIR2, irbc);
/*
* CALCULATION
*
* BaudRate[bps] = system rate / (uabca + (uabc + 1) x 16)
*/
uabc = rate / baudrate;
uabc = (uabc / 16) - 1;
uabc = (uabc + 1) * 16;
tmp = rate - (uabc * baudrate);
tmp *= 10000;
rerr = tmp / baudrate;
min = 0xffffffff;
uabca = 0;
for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
tmp = abs(rate_err_array[i] - rerr);
if (min > tmp) {
min = tmp;
uabca = i;
}
}
tmp = rate / (uabc + ERR_ROUNDING(rate_err_array[uabca]));
if ((baudrate / 100) < abs(tmp - baudrate))
dev_warn(dev, "UART freq error margin over %d\n", tmp);
dev_dbg(dev, "target = %d, result = %d, uart = %d.%d\n",
baudrate, tmp,
uabc, rate_err_array[uabca]);
uabca = (uabca & 0xF) << 4;
uabc = (uabc / 16) - 1;
sh_sir_write(self, IRIF_UART6, uabca);
sh_sir_write(self, IRIF_UART7, uabc);
return 0;
}
/************************************************************************
iobuf function
************************************************************************/
static int __sh_sir_init_iobuf(iobuff_t *io, int size)
{
io->head = kmalloc(size, GFP_KERNEL);
if (!io->head)
return -ENOMEM;
io->truesize = size;
io->in_frame = FALSE;
io->state = OUTSIDE_FRAME;
io->data = io->head;
return 0;
}
static void sh_sir_remove_iobuf(struct sh_sir_self *self)
{
kfree(self->rx_buff.head);
kfree(self->tx_buff.head);
self->rx_buff.head = NULL;
self->tx_buff.head = NULL;
}
static int sh_sir_init_iobuf(struct sh_sir_self *self, int rxsize, int txsize)
{
int err = -ENOMEM;
if (self->rx_buff.head ||
self->tx_buff.head) {
dev_err(&self->ndev->dev, "iobuff has already existed.");
return err;
}
err = __sh_sir_init_iobuf(&self->rx_buff, rxsize);
if (err)
goto iobuf_err;
err = __sh_sir_init_iobuf(&self->tx_buff, txsize);
iobuf_err:
if (err)
sh_sir_remove_iobuf(self);
return err;
}
/************************************************************************
status function
************************************************************************/
static void sh_sir_clear_all_err(struct sh_sir_self *self)
{
/* Clear error flag for receive pulse width */
sh_sir_update_bits(self, IRIF_SIR0, IRERRC, IRERRC);
/* Clear frame / EOF error flag */
sh_sir_write(self, IRIF_SIR_FLG, 0xffff);
/* Clear all status error */
sh_sir_write(self, IRIF_UART_STS2, 0);
}
static void sh_sir_set_phase(struct sh_sir_self *self, int phase)
{
u16 uart5 = 0;
u16 uart0 = 0;
switch (phase) {
case TX_PHASE:
uart5 = TBEIM;
uart0 = TBEC | TIE;
break;
case TX_COMP_PHASE:
uart5 = TSBEIM;
uart0 = TIE;
break;
case RX_PHASE:
uart5 = RX_MASK;
uart0 = RIE;
break;
default:
break;
}
sh_sir_write(self, IRIF_UART5, uart5);
sh_sir_write(self, IRIF_UART0, uart0);
}
static int sh_sir_is_which_phase(struct sh_sir_self *self)
{
u16 val = sh_sir_read(self, IRIF_UART5);
if (val & TBEIM)
return TX_PHASE;
if (val & TSBEIM)
return TX_COMP_PHASE;
if (val & RX_MASK)
return RX_PHASE;
return NONE_PHASE;
}
static void sh_sir_tx(struct sh_sir_self *self, int phase)
{
switch (phase) {
case TX_PHASE:
if (0 >= self->tx_buff.len) {
sh_sir_set_phase(self, TX_COMP_PHASE);
} else {
sh_sir_write(self, IRIF_UART3, self->tx_buff.data[0]);
self->tx_buff.len--;
self->tx_buff.data++;
}
break;
case TX_COMP_PHASE:
sh_sir_set_phase(self, RX_PHASE);
netif_wake_queue(self->ndev);
break;
default:
dev_err(&self->ndev->dev, "should not happen\n");
break;
}
}
static int sh_sir_read_data(struct sh_sir_self *self)
{
u16 val = 0;
int timeout = 1024;
while (timeout--) {
val = sh_sir_read(self, IRIF_UART1);
/* data get */
if (val & RBF) {
if (val & (URSME | UROVE | URFRE | URPRE))
break;
return (int)sh_sir_read(self, IRIF_UART4);
}
udelay(1);
}
dev_err(&self->ndev->dev, "UART1 %04x : STATUS %04x\n",
val, sh_sir_read(self, IRIF_UART_STS2));
/* read data register for clear error */
sh_sir_read(self, IRIF_UART4);
return -1;
}
static void sh_sir_rx(struct sh_sir_self *self)
{
int timeout = 1024;
int data;
while (timeout--) {
data = sh_sir_read_data(self);
if (data < 0)
break;
async_unwrap_char(self->ndev, &self->ndev->stats,
&self->rx_buff, (u8)data);
self->ndev->last_rx = jiffies;
if (EOFD & sh_sir_read(self, IRIF_SIR_FRM))
continue;
break;
}
}
static irqreturn_t sh_sir_irq(int irq, void *dev_id)
{
struct sh_sir_self *self = dev_id;
struct device *dev = &self->ndev->dev;
int phase = sh_sir_is_which_phase(self);
switch (phase) {
case TX_COMP_PHASE:
case TX_PHASE:
sh_sir_tx(self, phase);
break;
case RX_PHASE:
if (sh_sir_read(self, IRIF_SIR3))
dev_err(dev, "rcv pulse width error occurred\n");
sh_sir_rx(self);
sh_sir_clear_all_err(self);
break;
default:
dev_err(dev, "unknown interrupt\n");
}
return IRQ_HANDLED;
}
/************************************************************************
net_device_ops function
************************************************************************/
static int sh_sir_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct sh_sir_self *self = netdev_priv(ndev);
int speed = irda_get_next_speed(skb);
if ((0 < speed) &&
(9600 != speed)) {
dev_err(&ndev->dev, "support 9600 only (%d)\n", speed);
return -EIO;
}
netif_stop_queue(ndev);
self->tx_buff.data = self->tx_buff.head;
self->tx_buff.len = 0;
if (skb->len)
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
sh_sir_set_phase(self, TX_PHASE);
dev_kfree_skb(skb);
return 0;
}
static int sh_sir_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
{
/*
* FIXME
*
* This function is needed for irda framework.
* But nothing to do now
*/
return 0;
}
static struct net_device_stats *sh_sir_stats(struct net_device *ndev)
{
struct sh_sir_self *self = netdev_priv(ndev);
return &self->ndev->stats;
}
static int sh_sir_open(struct net_device *ndev)
{
struct sh_sir_self *self = netdev_priv(ndev);
int err;
clk_enable(self->clk);
err = sh_sir_crc_init(self);
if (err)
goto open_err;
sh_sir_set_baudrate(self, 9600);
self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
if (!self->irlap) {
err = -ENODEV;
goto open_err;
}
/*
* Now enable the interrupt then start the queue
*/
sh_sir_update_bits(self, IRIF_SIR_FRM, FRP, FRP);
sh_sir_read(self, IRIF_UART1); /* flag clear */
sh_sir_read(self, IRIF_UART4); /* flag clear */
sh_sir_set_phase(self, RX_PHASE);
netif_start_queue(ndev);
dev_info(&self->ndev->dev, "opened\n");
return 0;
open_err:
clk_disable(self->clk);
return err;
}
static int sh_sir_stop(struct net_device *ndev)
{
struct sh_sir_self *self = netdev_priv(ndev);
/* Stop IrLAP */
if (self->irlap) {
irlap_close(self->irlap);
self->irlap = NULL;
}
netif_stop_queue(ndev);
dev_info(&ndev->dev, "stopped\n");
return 0;
}
static const struct net_device_ops sh_sir_ndo = {
.ndo_open = sh_sir_open,
.ndo_stop = sh_sir_stop,
.ndo_start_xmit = sh_sir_hard_xmit,
.ndo_do_ioctl = sh_sir_ioctl,
.ndo_get_stats = sh_sir_stats,
};
/************************************************************************
platform_driver function
************************************************************************/
static int sh_sir_probe(struct platform_device *pdev)
{
struct net_device *ndev;
struct sh_sir_self *self;
struct resource *res;
char clk_name[8];
int irq;
int err = -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!res || irq < 0) {
dev_err(&pdev->dev, "Not enough platform resources.\n");
goto exit;
}
ndev = alloc_irdadev(sizeof(*self));
if (!ndev)
goto exit;
self = netdev_priv(ndev);
self->membase = ioremap_nocache(res->start, resource_size(res));
if (!self->membase) {
err = -ENXIO;
dev_err(&pdev->dev, "Unable to ioremap.\n");
goto err_mem_1;
}
err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME);
if (err)
goto err_mem_2;
snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id);
self->clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(self->clk)) {
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
err = -ENODEV;
goto err_mem_3;
}
irda_init_max_qos_capabilies(&self->qos);
ndev->netdev_ops = &sh_sir_ndo;
ndev->irq = irq;
self->ndev = ndev;
self->qos.baud_rate.bits &= IR_9600; /* FIXME */
self->qos.min_turn_time.bits = 1; /* 10 ms or more */
irda_qos_bits_to_value(&self->qos);
err = register_netdev(ndev);
if (err)
goto err_mem_4;
platform_set_drvdata(pdev, ndev);
err = devm_request_irq(&pdev->dev, irq, sh_sir_irq, 0, "sh_sir", self);
if (err) {
dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n");
goto err_mem_4;
}
dev_info(&pdev->dev, "SuperH IrDA probed\n");
goto exit;
err_mem_4:
clk_put(self->clk);
err_mem_3:
sh_sir_remove_iobuf(self);
err_mem_2:
iounmap(self->membase);
err_mem_1:
free_netdev(ndev);
exit:
return err;
}
static int sh_sir_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct sh_sir_self *self = netdev_priv(ndev);
if (!self)
return 0;
unregister_netdev(ndev);
clk_put(self->clk);
sh_sir_remove_iobuf(self);
iounmap(self->membase);
free_netdev(ndev);
return 0;
}
static struct platform_driver sh_sir_driver = {
.probe = sh_sir_probe,
.remove = sh_sir_remove,
.driver = {
.name = DRIVER_NAME,
},
};
module_platform_driver(sh_sir_driver);
MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
MODULE_DESCRIPTION("SuperH IrDA driver");
MODULE_LICENSE("GPL");

191
drivers/net/irda/sir-dev.h Normal file
View file

@ -0,0 +1,191 @@
/*********************************************************************
*
* 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 <linux/workqueue.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> // iobuff_t
struct sir_fsm {
struct semaphore sem;
struct delayed_work work;
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 */
int irda_register_dongle(struct dongle_driver *new);
int irda_unregister_dongle(struct dongle_driver *drv);
struct sir_dev *sirdev_get_instance(const struct sir_driver *drv,
const char *name);
int sirdev_put_instance(struct sir_dev *self);
int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type);
void sirdev_write_complete(struct sir_dev *dev);
int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count);
/* low level helpers for SIR device/dongle setup */
int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len);
int sirdev_raw_read(struct sir_dev *dev, char *buf, int len);
int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts);
/* not exported */
int sirdev_get_dongle(struct sir_dev *self, IRDA_DONGLE type);
int sirdev_put_dongle(struct sir_dev *self);
void sirdev_enable_rx(struct sir_dev *dev);
int sirdev_schedule_request(struct sir_dev *dev, int state, unsigned param);
/* 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 irlap_cb *irlap;
struct qos_info qos;
char hwname[32];
struct sir_fsm fsm;
atomic_t enable_rx;
int raw_tx;
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;
};
#endif /* IRDA_SIR_H */

986
drivers/net/irda/sir_dev.c Normal file
View file

@ -0,0 +1,986 @@
/*********************************************************************
*
* sir_dev.c: irda sir network device
*
* 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/hardirq.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#include "sir-dev.h"
static struct workqueue_struct *irda_sir_wq;
/* STATE MACHINE */
/* substate handler of the config-fsm to handle the cases where we want
* to wait for transmit completion before changing the port configuration
*/
static int sirdev_tx_complete_fsm(struct sir_dev *dev)
{
struct sir_fsm *fsm = &dev->fsm;
unsigned next_state, delay;
unsigned bytes_left;
do {
next_state = fsm->substate; /* default: stay in current substate */
delay = 0;
switch(fsm->substate) {
case SIRDEV_STATE_WAIT_XMIT:
if (dev->drv->chars_in_buffer)
bytes_left = dev->drv->chars_in_buffer(dev);
else
bytes_left = 0;
if (!bytes_left) {
next_state = SIRDEV_STATE_WAIT_UNTIL_SENT;
break;
}
if (dev->speed > 115200)
delay = (bytes_left*8*10000) / (dev->speed/100);
else if (dev->speed > 0)
delay = (bytes_left*10*10000) / (dev->speed/100);
else
delay = 0;
/* expected delay (usec) until remaining bytes are sent */
if (delay < 100) {
udelay(delay);
delay = 0;
break;
}
/* sleep some longer delay (msec) */
delay = (delay+999) / 1000;
break;
case SIRDEV_STATE_WAIT_UNTIL_SENT:
/* block until underlaying hardware buffer are empty */
if (dev->drv->wait_until_sent)
dev->drv->wait_until_sent(dev);
next_state = SIRDEV_STATE_TX_DONE;
break;
case SIRDEV_STATE_TX_DONE:
return 0;
default:
IRDA_ERROR("%s - undefined state\n", __func__);
return -EINVAL;
}
fsm->substate = next_state;
} while (delay == 0);
return delay;
}
/*
* Function sirdev_config_fsm
*
* State machine to handle the configuration of the device (and attached dongle, if any).
* This handler is scheduled for execution in kIrDAd context, so we can sleep.
* however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too
* long. Instead, for longer delays we start a timer to reschedule us later.
* On entry, fsm->sem is always locked and the netdev xmit queue stopped.
* Both must be unlocked/restarted on completion - but only on final exit.
*/
static void sirdev_config_fsm(struct work_struct *work)
{
struct sir_dev *dev = container_of(work, struct sir_dev, fsm.work.work);
struct sir_fsm *fsm = &dev->fsm;
int next_state;
int ret = -1;
unsigned delay;
IRDA_DEBUG(2, "%s(), <%ld>\n", __func__, jiffies);
do {
IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n",
__func__, fsm->state, fsm->substate);
next_state = fsm->state;
delay = 0;
switch(fsm->state) {
case SIRDEV_STATE_DONGLE_OPEN:
if (dev->dongle_drv != NULL) {
ret = sirdev_put_dongle(dev);
if (ret) {
fsm->result = -EINVAL;
next_state = SIRDEV_STATE_ERROR;
break;
}
}
/* Initialize dongle */
ret = sirdev_get_dongle(dev, fsm->param);
if (ret) {
fsm->result = ret;
next_state = SIRDEV_STATE_ERROR;
break;
}
/* Dongles are powered through the modem control lines which
* were just set during open. Before resetting, let's wait for
* the power to stabilize. This is what some dongle drivers did
* in open before, while others didn't - should be safe anyway.
*/
delay = 50;
fsm->substate = SIRDEV_STATE_DONGLE_RESET;
next_state = SIRDEV_STATE_DONGLE_RESET;
fsm->param = 9600;
break;
case SIRDEV_STATE_DONGLE_CLOSE:
/* shouldn't we just treat this as success=? */
if (dev->dongle_drv == NULL) {
fsm->result = -EINVAL;
next_state = SIRDEV_STATE_ERROR;
break;
}
ret = sirdev_put_dongle(dev);
if (ret) {
fsm->result = ret;
next_state = SIRDEV_STATE_ERROR;
break;
}
next_state = SIRDEV_STATE_DONE;
break;
case SIRDEV_STATE_SET_DTR_RTS:
ret = sirdev_set_dtr_rts(dev,
(fsm->param&0x02) ? TRUE : FALSE,
(fsm->param&0x01) ? TRUE : FALSE);
next_state = SIRDEV_STATE_DONE;
break;
case SIRDEV_STATE_SET_SPEED:
fsm->substate = SIRDEV_STATE_WAIT_XMIT;
next_state = SIRDEV_STATE_DONGLE_CHECK;
break;
case SIRDEV_STATE_DONGLE_CHECK:
ret = sirdev_tx_complete_fsm(dev);
if (ret < 0) {
fsm->result = ret;
next_state = SIRDEV_STATE_ERROR;
break;
}
if ((delay=ret) != 0)
break;
if (dev->dongle_drv) {
fsm->substate = SIRDEV_STATE_DONGLE_RESET;
next_state = SIRDEV_STATE_DONGLE_RESET;
}
else {
dev->speed = fsm->param;
next_state = SIRDEV_STATE_PORT_SPEED;
}
break;
case SIRDEV_STATE_DONGLE_RESET:
if (dev->dongle_drv->reset) {
ret = dev->dongle_drv->reset(dev);
if (ret < 0) {
fsm->result = ret;
next_state = SIRDEV_STATE_ERROR;
break;
}
}
else
ret = 0;
if ((delay=ret) == 0) {
/* set serial port according to dongle default speed */
if (dev->drv->set_speed)
dev->drv->set_speed(dev, dev->speed);
fsm->substate = SIRDEV_STATE_DONGLE_SPEED;
next_state = SIRDEV_STATE_DONGLE_SPEED;
}
break;
case SIRDEV_STATE_DONGLE_SPEED:
if (dev->dongle_drv->set_speed) {
ret = dev->dongle_drv->set_speed(dev, fsm->param);
if (ret < 0) {
fsm->result = ret;
next_state = SIRDEV_STATE_ERROR;
break;
}
}
else
ret = 0;
if ((delay=ret) == 0)
next_state = SIRDEV_STATE_PORT_SPEED;
break;
case SIRDEV_STATE_PORT_SPEED:
/* Finally we are ready to change the serial port speed */
if (dev->drv->set_speed)
dev->drv->set_speed(dev, dev->speed);
dev->new_speed = 0;
next_state = SIRDEV_STATE_DONE;
break;
case SIRDEV_STATE_DONE:
/* Signal network layer so it can send more frames */
netif_wake_queue(dev->netdev);
next_state = SIRDEV_STATE_COMPLETE;
break;
default:
IRDA_ERROR("%s - undefined state\n", __func__);
fsm->result = -EINVAL;
/* fall thru */
case SIRDEV_STATE_ERROR:
IRDA_ERROR("%s - error: %d\n", __func__, fsm->result);
#if 0 /* don't enable this before we have netdev->tx_timeout to recover */
netif_stop_queue(dev->netdev);
#else
netif_wake_queue(dev->netdev);
#endif
/* fall thru */
case SIRDEV_STATE_COMPLETE:
/* config change finished, so we are not busy any longer */
sirdev_enable_rx(dev);
up(&fsm->sem);
return;
}
fsm->state = next_state;
} while(!delay);
queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay));
}
/* schedule some device configuration task for execution by kIrDAd
* on behalf of the above state machine.
* can be called from process or interrupt/tasklet context.
*/
int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param)
{
struct sir_fsm *fsm = &dev->fsm;
IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __func__,
initial_state, param);
if (down_trylock(&fsm->sem)) {
if (in_interrupt() || in_atomic() || irqs_disabled()) {
IRDA_DEBUG(1, "%s(), state machine busy!\n", __func__);
return -EWOULDBLOCK;
} else
down(&fsm->sem);
}
if (fsm->state == SIRDEV_STATE_DEAD) {
/* race with sirdev_close should never happen */
IRDA_ERROR("%s(), instance staled!\n", __func__);
up(&fsm->sem);
return -ESTALE; /* or better EPIPE? */
}
netif_stop_queue(dev->netdev);
atomic_set(&dev->enable_rx, 0);
fsm->state = initial_state;
fsm->param = param;
fsm->result = 0;
INIT_DELAYED_WORK(&fsm->work, sirdev_config_fsm);
queue_delayed_work(irda_sir_wq, &fsm->work, 0);
return 0;
}
/***************************************************************************/
void sirdev_enable_rx(struct sir_dev *dev)
{
if (unlikely(atomic_read(&dev->enable_rx)))
return;
/* flush rx-buffer - should also help in case of problems with echo cancelation */
dev->rx_buff.data = dev->rx_buff.head;
dev->rx_buff.len = 0;
dev->rx_buff.in_frame = FALSE;
dev->rx_buff.state = OUTSIDE_FRAME;
atomic_set(&dev->enable_rx, 1);
}
static int sirdev_is_receiving(struct sir_dev *dev)
{
if (!atomic_read(&dev->enable_rx))
return 0;
return dev->rx_buff.state != OUTSIDE_FRAME;
}
int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type)
{
int err;
IRDA_DEBUG(3, "%s : requesting dongle %d.\n", __func__, type);
err = sirdev_schedule_dongle_open(dev, type);
if (unlikely(err))
return err;
down(&dev->fsm.sem); /* block until config change completed */
err = dev->fsm.result;
up(&dev->fsm.sem);
return err;
}
EXPORT_SYMBOL(sirdev_set_dongle);
/* used by dongle drivers for dongle programming */
int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len)
{
unsigned long flags;
int ret;
if (unlikely(len > dev->tx_buff.truesize))
return -ENOSPC;
spin_lock_irqsave(&dev->tx_lock, flags); /* serialize with other tx operations */
while (dev->tx_buff.len > 0) { /* wait until tx idle */
spin_unlock_irqrestore(&dev->tx_lock, flags);
msleep(10);
spin_lock_irqsave(&dev->tx_lock, flags);
}
dev->tx_buff.data = dev->tx_buff.head;
memcpy(dev->tx_buff.data, buf, len);
dev->tx_buff.len = len;
ret = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
if (ret > 0) {
IRDA_DEBUG(3, "%s(), raw-tx started\n", __func__);
dev->tx_buff.data += ret;
dev->tx_buff.len -= ret;
dev->raw_tx = 1;
ret = len; /* all data is going to be sent */
}
spin_unlock_irqrestore(&dev->tx_lock, flags);
return ret;
}
EXPORT_SYMBOL(sirdev_raw_write);
/* seems some dongle drivers may need this */
int sirdev_raw_read(struct sir_dev *dev, char *buf, int len)
{
int count;
if (atomic_read(&dev->enable_rx))
return -EIO; /* fail if we expect irda-frames */
count = (len < dev->rx_buff.len) ? len : dev->rx_buff.len;
if (count > 0) {
memcpy(buf, dev->rx_buff.data, count);
dev->rx_buff.data += count;
dev->rx_buff.len -= count;
}
/* remaining stuff gets flushed when re-enabling normal rx */
return count;
}
EXPORT_SYMBOL(sirdev_raw_read);
int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
{
int ret = -ENXIO;
if (dev->drv->set_dtr_rts)
ret = dev->drv->set_dtr_rts(dev, dtr, rts);
return ret;
}
EXPORT_SYMBOL(sirdev_set_dtr_rts);
/**********************************************************************/
/* called from client driver - likely with bh-context - to indicate
* it made some progress with transmission. Hence we send the next
* chunk, if any, or complete the skb otherwise
*/
void sirdev_write_complete(struct sir_dev *dev)
{
unsigned long flags;
struct sk_buff *skb;
int actual = 0;
int err;
spin_lock_irqsave(&dev->tx_lock, flags);
IRDA_DEBUG(3, "%s() - dev->tx_buff.len = %d\n",
__func__, dev->tx_buff.len);
if (likely(dev->tx_buff.len > 0)) {
/* Write data left in transmit buffer */
actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
if (likely(actual>0)) {
dev->tx_buff.data += actual;
dev->tx_buff.len -= actual;
}
else if (unlikely(actual<0)) {
/* could be dropped later when we have tx_timeout to recover */
IRDA_ERROR("%s: drv->do_write failed (%d)\n",
__func__, actual);
if ((skb=dev->tx_skb) != NULL) {
dev->tx_skb = NULL;
dev_kfree_skb_any(skb);
dev->netdev->stats.tx_errors++;
dev->netdev->stats.tx_dropped++;
}
dev->tx_buff.len = 0;
}
if (dev->tx_buff.len > 0)
goto done; /* more data to send later */
}
if (unlikely(dev->raw_tx != 0)) {
/* in raw mode we are just done now after the buffer was sent
* completely. Since this was requested by some dongle driver
* running under the control of the irda-thread we must take
* care here not to re-enable the queue. The queue will be
* restarted when the irda-thread has completed the request.
*/
IRDA_DEBUG(3, "%s(), raw-tx done\n", __func__);
dev->raw_tx = 0;
goto done; /* no post-frame handling in raw mode */
}
/* we have finished now sending this skb.
* update statistics and free the skb.
* finally we check and trigger a pending speed change, if any.
* if not we switch to rx mode and wake the queue for further
* packets.
* note the scheduled speed request blocks until the lower
* client driver and the corresponding hardware has really
* finished sending all data (xmit fifo drained f.e.)
* before the speed change gets finally done and the queue
* re-activated.
*/
IRDA_DEBUG(5, "%s(), finished with frame!\n", __func__);
if ((skb=dev->tx_skb) != NULL) {
dev->tx_skb = NULL;
dev->netdev->stats.tx_packets++;
dev->netdev->stats.tx_bytes += skb->len;
dev_kfree_skb_any(skb);
}
if (unlikely(dev->new_speed > 0)) {
IRDA_DEBUG(5, "%s(), Changing speed!\n", __func__);
err = sirdev_schedule_speed(dev, dev->new_speed);
if (unlikely(err)) {
/* should never happen
* forget the speed change and hope the stack recovers
*/
IRDA_ERROR("%s - schedule speed change failed: %d\n",
__func__, err);
netif_wake_queue(dev->netdev);
}
/* else: success
* speed change in progress now
* on completion dev->new_speed gets cleared,
* rx-reenabled and the queue restarted
*/
}
else {
sirdev_enable_rx(dev);
netif_wake_queue(dev->netdev);
}
done:
spin_unlock_irqrestore(&dev->tx_lock, flags);
}
EXPORT_SYMBOL(sirdev_write_complete);
/* called from client driver - likely with bh-context - to give us
* some more received bytes. We put them into the rx-buffer,
* normally unwrapping and building LAP-skb's (unless rx disabled)
*/
int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count)
{
if (!dev || !dev->netdev) {
IRDA_WARNING("%s(), not ready yet!\n", __func__);
return -1;
}
if (!dev->irlap) {
IRDA_WARNING("%s - too early: %p / %zd!\n",
__func__, cp, count);
return -1;
}
if (cp==NULL) {
/* error already at lower level receive
* just update stats and set media busy
*/
irda_device_set_media_busy(dev->netdev, TRUE);
dev->netdev->stats.rx_dropped++;
IRDA_DEBUG(0, "%s; rx-drop: %zd\n", __func__, count);
return 0;
}
/* Read the characters into the buffer */
if (likely(atomic_read(&dev->enable_rx))) {
while (count--)
/* Unwrap and destuff one byte */
async_unwrap_char(dev->netdev, &dev->netdev->stats,
&dev->rx_buff, *cp++);
} else {
while (count--) {
/* rx not enabled: save the raw bytes and never
* trigger any netif_rx. The received bytes are flushed
* later when we re-enable rx but might be read meanwhile
* by the dongle driver.
*/
dev->rx_buff.data[dev->rx_buff.len++] = *cp++;
/* What should we do when the buffer is full? */
if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize))
dev->rx_buff.len = 0;
}
}
return 0;
}
EXPORT_SYMBOL(sirdev_receive);
/**********************************************************************/
/* callbacks from network layer */
static netdev_tx_t sirdev_hard_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
struct sir_dev *dev = netdev_priv(ndev);
unsigned long flags;
int actual = 0;
int err;
s32 speed;
IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
netif_stop_queue(ndev);
IRDA_DEBUG(3, "%s(), skb->len = %d\n", __func__, skb->len);
speed = irda_get_next_speed(skb);
if ((speed != dev->speed) && (speed != -1)) {
if (!skb->len) {
err = sirdev_schedule_speed(dev, speed);
if (unlikely(err == -EWOULDBLOCK)) {
/* Failed to initiate the speed change, likely the fsm
* is still busy (pretty unlikely, but...)
* We refuse to accept the skb and return with the queue
* stopped so the network layer will retry after the
* fsm completes and wakes the queue.
*/
return NETDEV_TX_BUSY;
}
else if (unlikely(err)) {
/* other fatal error - forget the speed change and
* hope the stack will recover somehow
*/
netif_start_queue(ndev);
}
/* else: success
* speed change in progress now
* on completion the queue gets restarted
*/
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
} else
dev->new_speed = speed;
}
/* Init tx buffer*/
dev->tx_buff.data = dev->tx_buff.head;
/* Check problems */
if(spin_is_locked(&dev->tx_lock)) {
IRDA_DEBUG(3, "%s(), write not completed\n", __func__);
}
/* serialize with write completion */
spin_lock_irqsave(&dev->tx_lock, flags);
/* Copy skb to tx_buff while wrapping, stuffing and making CRC */
dev->tx_buff.len = async_wrap_skb(skb, dev->tx_buff.data, dev->tx_buff.truesize);
/* transmission will start now - disable receive.
* if we are just in the middle of an incoming frame,
* treat it as collision. probably it's a good idea to
* reset the rx_buf OUTSIDE_FRAME in this case too?
*/
atomic_set(&dev->enable_rx, 0);
if (unlikely(sirdev_is_receiving(dev)))
dev->netdev->stats.collisions++;
actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
if (likely(actual > 0)) {
dev->tx_skb = skb;
dev->tx_buff.data += actual;
dev->tx_buff.len -= actual;
}
else if (unlikely(actual < 0)) {
/* could be dropped later when we have tx_timeout to recover */
IRDA_ERROR("%s: drv->do_write failed (%d)\n",
__func__, actual);
dev_kfree_skb_any(skb);
dev->netdev->stats.tx_errors++;
dev->netdev->stats.tx_dropped++;
netif_wake_queue(ndev);
}
spin_unlock_irqrestore(&dev->tx_lock, flags);
return NETDEV_TX_OK;
}
/* called from network layer with rtnl hold */
static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{
struct if_irda_req *irq = (struct if_irda_req *) rq;
struct sir_dev *dev = netdev_priv(ndev);
int ret = 0;
IRDA_ASSERT(dev != NULL, return -1;);
IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __func__, ndev->name, cmd);
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else
ret = sirdev_schedule_speed(dev, irq->ifr_baudrate);
/* cannot sleep here for completion
* we are called from network layer with rtnl hold
*/
break;
case SIOCSDONGLE: /* Set dongle */
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else
ret = sirdev_schedule_dongle_open(dev, irq->ifr_dongle);
/* cannot sleep here for completion
* we are called from network layer with rtnl hold
*/
break;
case SIOCSMEDIABUSY: /* Set media busy */
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else
irda_device_set_media_busy(dev->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
irq->ifr_receiving = sirdev_is_receiving(dev);
break;
case SIOCSDTRRTS:
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else
ret = sirdev_schedule_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
/* cannot sleep here for completion
* we are called from network layer with rtnl hold
*/
break;
case SIOCSMODE:
#if 0
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else
ret = sirdev_schedule_mode(dev, irq->ifr_mode);
/* cannot sleep here for completion
* we are called from network layer with rtnl hold
*/
break;
#endif
default:
ret = -EOPNOTSUPP;
}
return ret;
}
/* ----------------------------------------------------------------------------- */
#define SIRBUF_ALLOCSIZE 4269 /* worst case size of a wrapped IrLAP frame */
static int sirdev_alloc_buffers(struct sir_dev *dev)
{
dev->tx_buff.truesize = SIRBUF_ALLOCSIZE;
dev->rx_buff.truesize = IRDA_SKB_MAX_MTU;
/* Bootstrap ZeroCopy Rx */
dev->rx_buff.skb = __netdev_alloc_skb(dev->netdev, dev->rx_buff.truesize,
GFP_KERNEL);
if (dev->rx_buff.skb == NULL)
return -ENOMEM;
skb_reserve(dev->rx_buff.skb, 1);
dev->rx_buff.head = dev->rx_buff.skb->data;
dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL);
if (dev->tx_buff.head == NULL) {
kfree_skb(dev->rx_buff.skb);
dev->rx_buff.skb = NULL;
dev->rx_buff.head = NULL;
return -ENOMEM;
}
dev->tx_buff.data = dev->tx_buff.head;
dev->rx_buff.data = dev->rx_buff.head;
dev->tx_buff.len = 0;
dev->rx_buff.len = 0;
dev->rx_buff.in_frame = FALSE;
dev->rx_buff.state = OUTSIDE_FRAME;
return 0;
};
static void sirdev_free_buffers(struct sir_dev *dev)
{
kfree_skb(dev->rx_buff.skb);
kfree(dev->tx_buff.head);
dev->rx_buff.head = dev->tx_buff.head = NULL;
dev->rx_buff.skb = NULL;
}
static int sirdev_open(struct net_device *ndev)
{
struct sir_dev *dev = netdev_priv(ndev);
const struct sir_driver *drv = dev->drv;
if (!drv)
return -ENODEV;
/* increase the reference count of the driver module before doing serious stuff */
if (!try_module_get(drv->owner))
return -ESTALE;
IRDA_DEBUG(2, "%s()\n", __func__);
if (sirdev_alloc_buffers(dev))
goto errout_dec;
if (!dev->drv->start_dev || dev->drv->start_dev(dev))
goto errout_free;
sirdev_enable_rx(dev);
dev->raw_tx = 0;
netif_start_queue(ndev);
dev->irlap = irlap_open(ndev, &dev->qos, dev->hwname);
if (!dev->irlap)
goto errout_stop;
netif_wake_queue(ndev);
IRDA_DEBUG(2, "%s - done, speed = %d\n", __func__, dev->speed);
return 0;
errout_stop:
atomic_set(&dev->enable_rx, 0);
if (dev->drv->stop_dev)
dev->drv->stop_dev(dev);
errout_free:
sirdev_free_buffers(dev);
errout_dec:
module_put(drv->owner);
return -EAGAIN;
}
static int sirdev_close(struct net_device *ndev)
{
struct sir_dev *dev = netdev_priv(ndev);
const struct sir_driver *drv;
// IRDA_DEBUG(0, "%s\n", __func__);
netif_stop_queue(ndev);
down(&dev->fsm.sem); /* block on pending config completion */
atomic_set(&dev->enable_rx, 0);
if (unlikely(!dev->irlap))
goto out;
irlap_close(dev->irlap);
dev->irlap = NULL;
drv = dev->drv;
if (unlikely(!drv || !dev->priv))
goto out;
if (drv->stop_dev)
drv->stop_dev(dev);
sirdev_free_buffers(dev);
module_put(drv->owner);
out:
dev->speed = 0;
up(&dev->fsm.sem);
return 0;
}
static const struct net_device_ops sirdev_ops = {
.ndo_start_xmit = sirdev_hard_xmit,
.ndo_open = sirdev_open,
.ndo_stop = sirdev_close,
.ndo_do_ioctl = sirdev_ioctl,
};
/* ----------------------------------------------------------------------------- */
struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name)
{
struct net_device *ndev;
struct sir_dev *dev;
IRDA_DEBUG(0, "%s - %s\n", __func__, name);
/* instead of adding tests to protect against drv->do_write==NULL
* at several places we refuse to create a sir_dev instance for
* drivers which don't implement do_write.
*/
if (!drv || !drv->do_write)
return NULL;
/*
* Allocate new instance of the device
*/
ndev = alloc_irdadev(sizeof(*dev));
if (ndev == NULL) {
IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __func__);
goto out;
}
dev = netdev_priv(ndev);
irda_init_max_qos_capabilies(&dev->qos);
dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
dev->qos.min_turn_time.bits = drv->qos_mtt_bits;
irda_qos_bits_to_value(&dev->qos);
strncpy(dev->hwname, name, sizeof(dev->hwname)-1);
atomic_set(&dev->enable_rx, 0);
dev->tx_skb = NULL;
spin_lock_init(&dev->tx_lock);
sema_init(&dev->fsm.sem, 1);
dev->drv = drv;
dev->netdev = ndev;
/* Override the network functions we need to use */
ndev->netdev_ops = &sirdev_ops;
if (register_netdev(ndev)) {
IRDA_ERROR("%s(), register_netdev() failed!\n", __func__);
goto out_freenetdev;
}
return dev;
out_freenetdev:
free_netdev(ndev);
out:
return NULL;
}
EXPORT_SYMBOL(sirdev_get_instance);
int sirdev_put_instance(struct sir_dev *dev)
{
int err = 0;
IRDA_DEBUG(0, "%s\n", __func__);
atomic_set(&dev->enable_rx, 0);
netif_carrier_off(dev->netdev);
netif_device_detach(dev->netdev);
if (dev->dongle_drv)
err = sirdev_schedule_dongle_close(dev);
if (err)
IRDA_ERROR("%s - error %d\n", __func__, err);
sirdev_close(dev->netdev);
down(&dev->fsm.sem);
dev->fsm.state = SIRDEV_STATE_DEAD; /* mark staled */
dev->dongle_drv = NULL;
dev->priv = NULL;
up(&dev->fsm.sem);
/* Remove netdevice */
unregister_netdev(dev->netdev);
free_netdev(dev->netdev);
return 0;
}
EXPORT_SYMBOL(sirdev_put_instance);
static int __init sir_wq_init(void)
{
irda_sir_wq = create_singlethread_workqueue("irda_sir_wq");
if (!irda_sir_wq)
return -ENOMEM;
return 0;
}
static void __exit sir_wq_exit(void)
{
destroy_workqueue(irda_sir_wq);
}
module_init(sir_wq_init);
module_exit(sir_wq_exit);
MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
MODULE_DESCRIPTION("IrDA SIR core");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,133 @@
/*********************************************************************
*
* 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/kmod.h>
#include <linux/mutex.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 DEFINE_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",
__func__, new->driver_name, new->type);
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) {
mutex_unlock(&dongle_list_lock);
return -EEXIST;
}
}
list_add(&new->dongle_list, &dongle_list);
mutex_unlock(&dongle_list_lock);
return 0;
}
EXPORT_SYMBOL(irda_register_dongle);
int irda_unregister_dongle(struct dongle_driver *drv)
{
mutex_lock(&dongle_list_lock);
list_del(&drv->dongle_list);
mutex_unlock(&dongle_list_lock);
return 0;
}
EXPORT_SYMBOL(irda_unregister_dongle);
int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
{
struct list_head *entry;
const struct dongle_driver *drv = NULL;
int err = -EINVAL;
request_module("irda-dongle-%d", type);
if (dev->dongle_drv != NULL)
return -EBUSY;
/* serialize access to the list of registered dongles */
mutex_lock(&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_module_get() below will fail
* 3) the try_module_get() below succeeds before the module is marked
* deleted - then sys_delete_module() fails and prevents the removal
* because the module is in use.
*/
if (!try_module_get(drv->owner)) {
err = -ESTALE;
goto out_unlock; /* rmmod already pending */
}
dev->dongle_drv = drv;
if (!drv->open || (err=drv->open(dev))!=0)
goto out_reject; /* failed to open driver */
mutex_unlock(&dongle_list_lock);
return 0;
out_reject:
dev->dongle_drv = NULL;
module_put(drv->owner);
out_unlock:
mutex_unlock(&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 */
module_put(drv->owner);/* decrement driver's module refcount */
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,191 @@
/*********************************************************************
*
* Description: Definitions for the SMC IrCC chipset
* Status: Experimental.
* Author: Daniele Peri (peri@csai.unipa.it)
*
* Copyright (c) 2002 Daniele Peri
* All Rights Reserved.
*
* Based on smc-ircc.h:
*
* Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
* Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net>
* 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, see <http://www.gnu.org/licenses/>.
*
********************************************************************/
#ifndef SMSC_IRCC2_H
#define SMSC_IRCC2_H
/* DMA modes needed */
#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
/* Master Control Register */
#define IRCC_MASTER 0x07
#define IRCC_MASTER_POWERDOWN 0x80
#define IRCC_MASTER_RESET 0x40
#define IRCC_MASTER_INT_EN 0x20
#define IRCC_MASTER_ERROR_RESET 0x10
/* Register block 0 */
/* Interrupt Identification */
#define IRCC_IIR 0x01
#define IRCC_IIR_ACTIVE_FRAME 0x80
#define IRCC_IIR_EOM 0x40
#define IRCC_IIR_RAW_MODE 0x20
#define IRCC_IIR_FIFO 0x10
/* Interrupt Enable */
#define IRCC_IER 0x02
#define IRCC_IER_ACTIVE_FRAME 0x80
#define IRCC_IER_EOM 0x40
#define IRCC_IER_RAW_MODE 0x20
#define IRCC_IER_FIFO 0x10
/* Line Status Register */
#define IRCC_LSR 0x03
#define IRCC_LSR_UNDERRUN 0x80
#define IRCC_LSR_OVERRUN 0x40
#define IRCC_LSR_FRAME_ERROR 0x20
#define IRCC_LSR_SIZE_ERROR 0x10
#define IRCC_LSR_CRC_ERROR 0x80
#define IRCC_LSR_FRAME_ABORT 0x40
/* Line Status Address Register */
#define IRCC_LSAR 0x03
#define IRCC_LSAR_ADDRESS_MASK 0x07
/* Line Control Register A */
#define IRCC_LCR_A 0x04
#define IRCC_LCR_A_FIFO_RESET 0x80
#define IRCC_LCR_A_FAST 0x40
#define IRCC_LCR_A_GP_DATA 0x20
#define IRCC_LCR_A_RAW_TX 0x10
#define IRCC_LCR_A_RAW_RX 0x08
#define IRCC_LCR_A_ABORT 0x04
#define IRCC_LCR_A_DATA_DONE 0x02
/* Line Control Register B */
#define IRCC_LCR_B 0x05
#define IRCC_LCR_B_SCE_DISABLED 0x00
#define IRCC_LCR_B_SCE_TRANSMIT 0x40
#define IRCC_LCR_B_SCE_RECEIVE 0x80
#define IRCC_LCR_B_SCE_UNDEFINED 0xc0
#define IRCC_LCR_B_SIP_ENABLE 0x20
#define IRCC_LCR_B_BRICK_WALL 0x10
/* Bus Status Register */
#define IRCC_BSR 0x06
#define IRCC_BSR_NOT_EMPTY 0x80
#define IRCC_BSR_FIFO_FULL 0x40
#define IRCC_BSR_TIMEOUT 0x20
/* Register block 1 */
#define IRCC_FIFO_THRESHOLD 0x02
#define IRCC_SCE_CFGA 0x00
#define IRCC_CFGA_AUX_IR 0x80
#define IRCC_CFGA_HALF_DUPLEX 0x04
#define IRCC_CFGA_TX_POLARITY 0x02
#define IRCC_CFGA_RX_POLARITY 0x01
#define IRCC_CFGA_COM 0x00
#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87
#define IRCC_CFGA_IRDA_SIR_A 0x08
#define IRCC_CFGA_ASK_SIR 0x10
#define IRCC_CFGA_IRDA_SIR_B 0x18
#define IRCC_CFGA_IRDA_HDLC 0x20
#define IRCC_CFGA_IRDA_4PPM 0x28
#define IRCC_CFGA_CONSUMER 0x30
#define IRCC_CFGA_RAW_IR 0x38
#define IRCC_CFGA_OTHER 0x40
#define IRCC_IR_HDLC 0x04
#define IRCC_IR_4PPM 0x01
#define IRCC_IR_CONSUMER 0x02
#define IRCC_SCE_CFGB 0x01
#define IRCC_CFGB_LOOPBACK 0x20
#define IRCC_CFGB_LPBCK_TX_CRC 0x10
#define IRCC_CFGB_NOWAIT 0x08
#define IRCC_CFGB_STRING_MOVE 0x04
#define IRCC_CFGB_DMA_BURST 0x02
#define IRCC_CFGB_DMA_ENABLE 0x01
#define IRCC_CFGB_MUX_COM 0x00
#define IRCC_CFGB_MUX_IR 0x40
#define IRCC_CFGB_MUX_AUX 0x80
#define IRCC_CFGB_MUX_INACTIVE 0xc0
/* Register block 3 - Identification Registers! */
#define IRCC_ID_HIGH 0x00 /* 0x10 */
#define IRCC_ID_LOW 0x01 /* 0xB8 */
#define IRCC_CHIP_ID 0x02 /* 0xF1 */
#define IRCC_VERSION 0x03 /* 0x01 */
#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
/* Register block 4 - IrDA */
#define IRCC_CONTROL 0x00
#define IRCC_BOF_COUNT_LO 0x01 /* Low byte */
#define IRCC_BOF_COUNT_HI 0x00 /* High nibble (bit 0-3) */
#define IRCC_BRICKWALL_CNT_LO 0x02 /* Low byte */
#define IRCC_BRICKWALL_CNT_HI 0x03 /* High nibble (bit 4-7) */
#define IRCC_TX_SIZE_LO 0x04 /* Low byte */
#define IRCC_TX_SIZE_HI 0x03 /* High nibble (bit 0-3) */
#define IRCC_RX_SIZE_HI 0x05 /* High nibble (bit 0-3) */
#define IRCC_RX_SIZE_LO 0x06 /* Low byte */
#define IRCC_1152 0x80
#define IRCC_CRC 0x40
/* Register block 5 - IrDA */
#define IRCC_ATC 0x00
#define IRCC_ATC_nPROGREADY 0x80
#define IRCC_ATC_SPEED 0x40
#define IRCC_ATC_ENABLE 0x20
#define IRCC_ATC_MASK 0xE0
#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01
#define IRCC_SCE_TX_DELAY_TIMER 0x02
/*
* Other definitions
*/
#define SMSC_IRCC2_MAX_SIR_SPEED 115200
#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
#define SMSC_IRCC2_FIFO_SIZE 16
#define SMSC_IRCC2_FIFO_THRESHOLD 64
/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
#define SMSC_IRCC2_RX_BUFF_TRUESIZE 14384
#define SMSC_IRCC2_TX_BUFF_TRUESIZE 14384
#define SMSC_IRCC2_MIN_TURN_TIME 0x07
#define SMSC_IRCC2_WINDOW_SIZE 0x07
/* Maximum wait for hw transmitter to finish */
#define SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US 1000 /* 1 ms */
/* Maximum wait for ATC transceiver programming to finish */
#define SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES 1
#endif /* SMSC_IRCC2_H */

100
drivers/net/irda/smsc-sio.h Normal file
View file

@ -0,0 +1,100 @@
#ifndef SMSC_SIO_H
#define SMSC_SIO_H
/******************************************
Keys. They should work with every SMsC SIO
******************************************/
#define SMSCSIO_CFGACCESSKEY 0x55
#define SMSCSIO_CFGEXITKEY 0xaa
/*****************************
* Generic SIO Flat (!?) *
*****************************/
/* Register 0x0d */
#define SMSCSIOFLAT_DEVICEID_REG 0x0d
/* Register 0x0c */
#define SMSCSIOFLAT_UARTMODE0C_REG 0x0c
#define SMSCSIOFLAT_UART2MODE_MASK 0x38
#define SMSCSIOFLAT_UART2MODE_VAL_COM 0x00
#define SMSCSIOFLAT_UART2MODE_VAL_IRDA 0x08
#define SMSCSIOFLAT_UART2MODE_VAL_ASKIR 0x10
/* Register 0x25 */
#define SMSCSIOFLAT_UART2BASEADDR_REG 0x25
/* Register 0x2b */
#define SMSCSIOFLAT_FIRBASEADDR_REG 0x2b
/* Register 0x2c */
#define SMSCSIOFLAT_FIRDMASELECT_REG 0x2c
#define SMSCSIOFLAT_FIRDMASELECT_MASK 0x0f
/* Register 0x28 */
#define SMSCSIOFLAT_UARTIRQSELECT_REG 0x28
#define SMSCSIOFLAT_UART2IRQSELECT_MASK 0x0f
#define SMSCSIOFLAT_UART1IRQSELECT_MASK 0xf0
#define SMSCSIOFLAT_UARTIRQSELECT_VAL_NONE 0x00
/*********************
* LPC47N227 *
*********************/
#define LPC47N227_CFGACCESSKEY 0x55
#define LPC47N227_CFGEXITKEY 0xaa
/* Register 0x00 */
#define LPC47N227_FDCPOWERVALIDCONF_REG 0x00
#define LPC47N227_FDCPOWER_MASK 0x08
#define LPC47N227_VALID_MASK 0x80
/* Register 0x02 */
#define LPC47N227_UART12POWER_REG 0x02
#define LPC47N227_UART1POWERDOWN_MASK 0x08
#define LPC47N227_UART2POWERDOWN_MASK 0x80
/* Register 0x07 */
#define LPC47N227_APMBOOTDRIVE_REG 0x07
#define LPC47N227_PARPORT2AUTOPWRDOWN_MASK 0x10 /* auto power down on if set */
#define LPC47N227_UART2AUTOPWRDOWN_MASK 0x20 /* auto power down on if set */
#define LPC47N227_UART1AUTOPWRDOWN_MASK 0x40 /* auto power down on if set */
/* Register 0x0c */
#define LPC47N227_UARTMODE0C_REG 0x0c
#define LPC47N227_UART2MODE_MASK 0x38
#define LPC47N227_UART2MODE_VAL_COM 0x00
#define LPC47N227_UART2MODE_VAL_IRDA 0x08
#define LPC47N227_UART2MODE_VAL_ASKIR 0x10
/* Register 0x0d */
#define LPC47N227_DEVICEID_REG 0x0d
#define LPC47N227_DEVICEID_DEFVAL 0x5a
/* Register 0x0e */
#define LPC47N227_REVISIONID_REG 0x0e
/* Register 0x25 */
#define LPC47N227_UART2BASEADDR_REG 0x25
/* Register 0x28 */
#define LPC47N227_UARTIRQSELECT_REG 0x28
#define LPC47N227_UART2IRQSELECT_MASK 0x0f
#define LPC47N227_UART1IRQSELECT_MASK 0xf0
#define LPC47N227_UARTIRQSELECT_VAL_NONE 0x00
/* Register 0x2b */
#define LPC47N227_FIRBASEADDR_REG 0x2b
/* Register 0x2c */
#define LPC47N227_FIRDMASELECT_REG 0x2c
#define LPC47N227_FIRDMASELECT_MASK 0x0f
#define LPC47N227_FIRDMASELECT_VAL_DMA1 0x01 /* 47n227 has three dma channels */
#define LPC47N227_FIRDMASELECT_VAL_DMA2 0x02
#define LPC47N227_FIRDMASELECT_VAL_DMA3 0x03
#define LPC47N227_FIRDMASELECT_VAL_NONE 0x0f
#endif

1135
drivers/net/irda/stir4200.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,232 @@
/*********************************************************************
*
* 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"
static int tekram_delay = 150; /* default is 150 ms */
module_param(tekram_delay, int, 0);
MODULE_PARM_DESC(tekram_delay, "tekram dongle write complete delay");
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,
};
static int __init tekram_sir_init(void)
{
if (tekram_delay < 1 || tekram_delay > 500)
tekram_delay = 200;
IRDA_DEBUG(1, "%s - using %d ms delay\n",
tekram.driver_name, tekram_delay);
return irda_register_dongle(&tekram);
}
static void __exit tekram_sir_cleanup(void)
{
irda_unregister_dongle(&tekram);
}
static int tekram_open(struct sir_dev *dev)
{
struct qos_info *qos = &dev->qos;
IRDA_DEBUG(2, "%s()\n", __func__);
sirdev_set_dtr_rts(dev, TRUE, TRUE);
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);
/* irda thread waits 50 msec for power settling */
return 0;
}
static int tekram_close(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Power off dongle */
sirdev_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 state = dev->fsm.substate;
unsigned delay = 0;
u8 byte;
static int ret = 0;
IRDA_DEBUG(2, "%s()\n", __func__);
switch(state) {
case SIRDEV_STATE_DONGLE_SPEED:
switch (speed) {
default:
speed = 9600;
ret = -EINVAL;
/* 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 */
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 = TEKRAM_STATE_WAIT_SPEED;
delay = tekram_delay;
break;
case TEKRAM_STATE_WAIT_SPEED:
/* Set DTR, Set RTS */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
udelay(50);
break;
default:
IRDA_ERROR("%s - undefined state %d\n", __func__, state);
ret = -EINVAL;
break;
}
dev->fsm.substate = state;
return (delay > 0) ? delay : ret;
}
/*
* 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
*/
static int tekram_reset(struct sir_dev *dev)
{
IRDA_DEBUG(2, "%s()\n", __func__);
/* Clear DTR, Set RTS */
sirdev_set_dtr_rts(dev, FALSE, TRUE);
/* Should sleep 1 ms */
msleep(1);
/* Set DTR, Set RTS */
sirdev_set_dtr_rts(dev, TRUE, TRUE);
/* Wait at least 50 us */
udelay(75);
dev->speed = 9600;
return 0;
}
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("irda-dongle-0"); /* IRDA_TEKRAM_DONGLE */
module_init(tekram_sir_init);
module_exit(tekram_sir_cleanup);

View file

@ -0,0 +1,376 @@
/*********************************************************************
*
* 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 transceiver.
* 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 <linux/sched.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", __func__);
/* 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", __func__);
/* 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", __func__);
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", __func__, 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", __func__);
/* 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);

1614
drivers/net/irda/via-ircc.c Normal file

File diff suppressed because it is too large Load diff

850
drivers/net/irda/via-ircc.h Normal file
View file

@ -0,0 +1,850 @@
/*********************************************************************
*
* Filename: via-ircc.h
* Version: 1.0
* Description: Driver for the VIA VT8231/VT8233 IrDA chipsets
* Author: VIA Technologies, inc
* Date : 08/06/2003
Copyright (c) 1998-2003 VIA Technologies, Inc.
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, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTIES OR REPRESENTATIONS; 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, see <http://www.gnu.org/licenses/>.
* Comment:
* jul/08/2002 : Rx buffer length should use Rx ring ptr.
* Oct/28/2002 : Add SB id for 3147 and 3177.
* jul/09/2002 : only implement two kind of dongle currently.
* Oct/02/2002 : work on VT8231 and VT8233 .
* Aug/06/2003 : change driver format to pci driver .
********************************************************************/
#ifndef via_IRCC_H
#define via_IRCC_H
#include <linux/time.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/types.h>
#include <asm/io.h>
#define MAX_TX_WINDOW 7
#define MAX_RX_WINDOW 7
struct st_fifo_entry {
int status;
int len;
};
struct st_fifo {
struct st_fifo_entry entries[MAX_RX_WINDOW + 2];
int pending_bytes;
int head;
int tail;
int len;
};
struct frame_cb {
void *start; /* Start of frame in DMA mem */
int len; /* Length of frame in DMA mem */
};
struct tx_fifo {
struct frame_cb queue[MAX_TX_WINDOW + 2]; /* Info about frames in queue */
int ptr; /* Currently being sent */
int len; /* Length of queue */
int free; /* Next free slot */
void *tail; /* Next free start in DMA mem */
};
struct eventflag // for keeping track of Interrupt Events
{
//--------tx part
unsigned char TxFIFOUnderRun;
unsigned char EOMessage;
unsigned char TxFIFOReady;
unsigned char EarlyEOM;
//--------rx part
unsigned char PHYErr;
unsigned char CRCErr;
unsigned char RxFIFOOverRun;
unsigned char EOPacket;
unsigned char RxAvail;
unsigned char TooLargePacket;
unsigned char SIRBad;
//--------unknown
unsigned char Unknown;
//----------
unsigned char TimeOut;
unsigned char RxDMATC;
unsigned char TxDMATC;
};
/* Private data for each instance */
struct via_ircc_cb {
struct st_fifo st_fifo; /* Info about received frames */
struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos; /* QoS capabilities for this device */
chipio_t io; /* IrDA controller information */
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
dma_addr_t tx_buff_dma;
dma_addr_t rx_buff_dma;
__u8 ier; /* Interrupt enable register */
struct timeval stamp;
struct timeval now;
spinlock_t lock; /* For serializing operations */
__u32 flags; /* Interface flags */
__u32 new_speed;
int index; /* Instance index */
struct eventflag EventFlag;
unsigned int chip_id; /* to remember chip id */
unsigned int RetryCount;
unsigned int RxDataReady;
unsigned int RxLastCount;
};
//---------I=Infrared, H=Host, M=Misc, T=Tx, R=Rx, ST=Status,
// CF=Config, CT=Control, L=Low, H=High, C=Count
#define I_CF_L_0 0x10
#define I_CF_H_0 0x11
#define I_SIR_BOF 0x12
#define I_SIR_EOF 0x13
#define I_ST_CT_0 0x15
#define I_ST_L_1 0x16
#define I_ST_H_1 0x17
#define I_CF_L_1 0x18
#define I_CF_H_1 0x19
#define I_CF_L_2 0x1a
#define I_CF_H_2 0x1b
#define I_CF_3 0x1e
#define H_CT 0x20
#define H_ST 0x21
#define M_CT 0x22
#define TX_CT_1 0x23
#define TX_CT_2 0x24
#define TX_ST 0x25
#define RX_CT 0x26
#define RX_ST 0x27
#define RESET 0x28
#define P_ADDR 0x29
#define RX_C_L 0x2a
#define RX_C_H 0x2b
#define RX_P_L 0x2c
#define RX_P_H 0x2d
#define TX_C_L 0x2e
#define TX_C_H 0x2f
#define TIMER 0x32
#define I_CF_4 0x33
#define I_T_C_L 0x34
#define I_T_C_H 0x35
#define VERSION 0x3f
//-------------------------------
#define StartAddr 0x10 // the first register address
#define EndAddr 0x3f // the last register address
#define GetBit(val,bit) val = (unsigned char) ((val>>bit) & 0x1)
// Returns the bit
#define SetBit(val,bit) val= (unsigned char ) (val | (0x1 << bit))
// Sets bit to 1
#define ResetBit(val,bit) val= (unsigned char ) (val & ~(0x1 << bit))
// Sets bit to 0
#define OFF 0
#define ON 1
#define DMA_TX_MODE 0x08
#define DMA_RX_MODE 0x04
#define DMA1 0
#define DMA2 0xc0
#define MASK1 DMA1+0x0a
#define MASK2 DMA2+0x14
#define Clk_bit 0x40
#define Tx_bit 0x01
#define Rd_Valid 0x08
#define RxBit 0x08
static void DisableDmaChannel(unsigned int channel)
{
switch (channel) { // 8 Bit DMA channels DMAC1
case 0:
outb(4, MASK1); //mask channel 0
break;
case 1:
outb(5, MASK1); //Mask channel 1
break;
case 2:
outb(6, MASK1); //Mask channel 2
break;
case 3:
outb(7, MASK1); //Mask channel 3
break;
case 5:
outb(5, MASK2); //Mask channel 5
break;
case 6:
outb(6, MASK2); //Mask channel 6
break;
case 7:
outb(7, MASK2); //Mask channel 7
break;
default:
break;
}
}
static unsigned char ReadLPCReg(int iRegNum)
{
unsigned char iVal;
outb(0x87, 0x2e);
outb(0x87, 0x2e);
outb(iRegNum, 0x2e);
iVal = inb(0x2f);
outb(0xaa, 0x2e);
return iVal;
}
static void WriteLPCReg(int iRegNum, unsigned char iVal)
{
outb(0x87, 0x2e);
outb(0x87, 0x2e);
outb(iRegNum, 0x2e);
outb(iVal, 0x2f);
outb(0xAA, 0x2e);
}
static __u8 ReadReg(unsigned int BaseAddr, int iRegNum)
{
return (__u8) inb(BaseAddr + iRegNum);
}
static void WriteReg(unsigned int BaseAddr, int iRegNum, unsigned char iVal)
{
outb(iVal, BaseAddr + iRegNum);
}
static int WriteRegBit(unsigned int BaseAddr, unsigned char RegNum,
unsigned char BitPos, unsigned char value)
{
__u8 Rtemp, Wtemp;
if (BitPos > 7) {
return -1;
}
if ((RegNum < StartAddr) || (RegNum > EndAddr))
return -1;
Rtemp = ReadReg(BaseAddr, RegNum);
if (value == 0)
Wtemp = ResetBit(Rtemp, BitPos);
else {
if (value == 1)
Wtemp = SetBit(Rtemp, BitPos);
else
return -1;
}
WriteReg(BaseAddr, RegNum, Wtemp);
return 0;
}
static __u8 CheckRegBit(unsigned int BaseAddr, unsigned char RegNum,
unsigned char BitPos)
{
__u8 temp;
if (BitPos > 7)
return 0xff;
if ((RegNum < StartAddr) || (RegNum > EndAddr)) {
// printf("what is the register %x!\n",RegNum);
}
temp = ReadReg(BaseAddr, RegNum);
return GetBit(temp, BitPos);
}
static void SetMaxRxPacketSize(__u16 iobase, __u16 size)
{
__u16 low, high;
if ((size & 0xe000) == 0) {
low = size & 0x00ff;
high = (size & 0x1f00) >> 8;
WriteReg(iobase, I_CF_L_2, low);
WriteReg(iobase, I_CF_H_2, high);
}
}
//for both Rx and Tx
static void SetFIFO(__u16 iobase, __u16 value)
{
switch (value) {
case 128:
WriteRegBit(iobase, 0x11, 0, 0);
WriteRegBit(iobase, 0x11, 7, 1);
break;
case 64:
WriteRegBit(iobase, 0x11, 0, 0);
WriteRegBit(iobase, 0x11, 7, 0);
break;
case 32:
WriteRegBit(iobase, 0x11, 0, 1);
WriteRegBit(iobase, 0x11, 7, 0);
break;
default:
WriteRegBit(iobase, 0x11, 0, 0);
WriteRegBit(iobase, 0x11, 7, 0);
}
}
#define CRC16(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,7,val) //0 for 32 CRC
/*
#define SetVFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,5,val)
#define SetFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,6,val)
#define SetMIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,5,val)
#define SetSIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,4,val)
*/
#define SIRFilter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,3,val)
#define Filter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,2,val)
#define InvertTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,1,val)
#define InvertRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,0,val)
//****************************I_CF_H_0
#define EnableTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,4,val)
#define EnableRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,3,val)
#define EnableDMA(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,2,val)
#define SIRRecvAny(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,1,val)
#define DiableTrans(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,0,val)
//***************************I_SIR_BOF,I_SIR_EOF
#define SetSIRBOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_BOF,val)
#define SetSIREOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_EOF,val)
#define GetSIRBOF(BaseAddr) ReadReg(BaseAddr,I_SIR_BOF)
#define GetSIREOF(BaseAddr) ReadReg(BaseAddr,I_SIR_EOF)
//*******************I_ST_CT_0
#define EnPhys(BaseAddr,val) WriteRegBit(BaseAddr,I_ST_CT_0,7,val)
#define IsModeError(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,6) //RO
#define IsVFIROn(BaseAddr) CheckRegBit(BaseAddr,0x14,0) //RO for VT1211 only
#define IsFIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,5) //RO
#define IsMIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,4) //RO
#define IsSIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,3) //RO
#define IsEnableTX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,2) //RO
#define IsEnableRX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,1) //RO
#define Is16CRC(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,0) //RO
//***************************I_CF_3
#define DisableAdjacentPulseWidth(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,5,val) //1 disable
#define DisablePulseWidthAdjust(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,4,val) //1 disable
#define UseOneRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,1,val) //0 use two RX
#define SlowIRRXLowActive(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,0,val) //0 show RX high=1 in SIR
//***************************H_CT
#define EnAllInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,7,val)
#define TXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,6,val)
#define RXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,5,val)
#define ClearRXInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,4,val) // 1 clear
//*****************H_ST
#define IsRXInt(BaseAddr) CheckRegBit(BaseAddr,H_ST,4)
#define GetIntIndentify(BaseAddr) ((ReadReg(BaseAddr,H_ST)&0xf1) >>1)
#define IsHostBusy(BaseAddr) CheckRegBit(BaseAddr,H_ST,0)
#define GetHostStatus(BaseAddr) ReadReg(BaseAddr,H_ST) //RO
//**************************M_CT
#define EnTXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,7,val)
#define EnRXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,6,val)
#define SwapDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,5,val)
#define EnInternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,4,val)
#define EnExternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,3,val)
//**************************TX_CT_1
#define EnTXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,4,val) //half empty int (1 half)
#define EnTXFIFOUnderrunEOMInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,5,val)
#define EnTXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,6,val) //int when reach it threshold (setting by bit 4)
//**************************TX_CT_2
#define ForceUnderrun(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,7,val) // force an underrun int
#define EnTXCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,6,val) //1 for FIR,MIR...0 (not SIR)
#define ForceBADCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,5,val) //force an bad CRC
#define SendSIP(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,4,val) //send indication pulse for prevent SIR disturb
#define ClearEnTX(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,3,val) // opposite to EnTX
//*****************TX_ST
#define GetTXStatus(BaseAddr) ReadReg(BaseAddr,TX_ST) //RO
//**************************RX_CT
#define EnRXSpecInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,0,val)
#define EnRXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,1,val) //enable int when reach it threshold (setting by bit 7)
#define EnRXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,7,val) //enable int when (1) half full...or (0) just not full
//*****************RX_ST
#define GetRXStatus(BaseAddr) ReadReg(BaseAddr,RX_ST) //RO
//***********************P_ADDR
#define SetPacketAddr(BaseAddr,addr) WriteReg(BaseAddr,P_ADDR,addr)
//***********************I_CF_4
#define EnGPIOtoRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,7,val)
#define EnTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,1,val)
#define ClearTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,0,val)
//***********************I_T_C_L
#define WriteGIO(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,7,val)
#define ReadGIO(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,7)
#define ReadRX(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,3) //RO
#define WriteTX(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,0,val)
//***********************I_T_C_H
#define EnRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_H,7,val)
#define ReadRX2(BaseAddr) CheckRegBit(BaseAddr,I_T_C_H,7)
//**********************Version
#define GetFIRVersion(BaseAddr) ReadReg(BaseAddr,VERSION)
static void SetTimer(__u16 iobase, __u8 count)
{
EnTimerInt(iobase, OFF);
WriteReg(iobase, TIMER, count);
EnTimerInt(iobase, ON);
}
static void SetSendByte(__u16 iobase, __u32 count)
{
__u32 low, high;
if ((count & 0xf000) == 0) {
low = count & 0x00ff;
high = (count & 0x0f00) >> 8;
WriteReg(iobase, TX_C_L, low);
WriteReg(iobase, TX_C_H, high);
}
}
static void ResetChip(__u16 iobase, __u8 type)
{
__u8 value;
value = (type + 2) << 4;
WriteReg(iobase, RESET, type);
}
static int CkRxRecv(__u16 iobase, struct via_ircc_cb *self)
{
__u8 low, high;
__u16 wTmp = 0, wTmp1 = 0, wTmp_new = 0;
low = ReadReg(iobase, RX_C_L);
high = ReadReg(iobase, RX_C_H);
wTmp1 = high;
wTmp = (wTmp1 << 8) | low;
udelay(10);
low = ReadReg(iobase, RX_C_L);
high = ReadReg(iobase, RX_C_H);
wTmp1 = high;
wTmp_new = (wTmp1 << 8) | low;
if (wTmp_new != wTmp)
return 1;
else
return 0;
}
static __u16 RxCurCount(__u16 iobase, struct via_ircc_cb * self)
{
__u8 low, high;
__u16 wTmp = 0, wTmp1 = 0;
low = ReadReg(iobase, RX_P_L);
high = ReadReg(iobase, RX_P_H);
wTmp1 = high;
wTmp = (wTmp1 << 8) | low;
return wTmp;
}
/* This Routine can only use in recevie_complete
* for it will update last count.
*/
static __u16 GetRecvByte(__u16 iobase, struct via_ircc_cb * self)
{
__u8 low, high;
__u16 wTmp, wTmp1, ret;
low = ReadReg(iobase, RX_P_L);
high = ReadReg(iobase, RX_P_H);
wTmp1 = high;
wTmp = (wTmp1 << 8) | low;
if (wTmp >= self->RxLastCount)
ret = wTmp - self->RxLastCount;
else
ret = (0x8000 - self->RxLastCount) + wTmp;
self->RxLastCount = wTmp;
/* RX_P is more actually the RX_C
low=ReadReg(iobase,RX_C_L);
high=ReadReg(iobase,RX_C_H);
if(!(high&0xe000)) {
temp=(high<<8)+low;
return temp;
}
else return 0;
*/
return ret;
}
static void Sdelay(__u16 scale)
{
__u8 bTmp;
int i, j;
for (j = 0; j < scale; j++) {
for (i = 0; i < 0x20; i++) {
bTmp = inb(0xeb);
outb(bTmp, 0xeb);
}
}
}
static void Tdelay(__u16 scale)
{
__u8 bTmp;
int i, j;
for (j = 0; j < scale; j++) {
for (i = 0; i < 0x50; i++) {
bTmp = inb(0xeb);
outb(bTmp, 0xeb);
}
}
}
static void ActClk(__u16 iobase, __u8 value)
{
__u8 bTmp;
bTmp = ReadReg(iobase, 0x34);
if (value)
WriteReg(iobase, 0x34, bTmp | Clk_bit);
else
WriteReg(iobase, 0x34, bTmp & ~Clk_bit);
}
static void ClkTx(__u16 iobase, __u8 Clk, __u8 Tx)
{
__u8 bTmp;
bTmp = ReadReg(iobase, 0x34);
if (Clk == 0)
bTmp &= ~Clk_bit;
else {
if (Clk == 1)
bTmp |= Clk_bit;
}
WriteReg(iobase, 0x34, bTmp);
Sdelay(1);
if (Tx == 0)
bTmp &= ~Tx_bit;
else {
if (Tx == 1)
bTmp |= Tx_bit;
}
WriteReg(iobase, 0x34, bTmp);
}
static void Wr_Byte(__u16 iobase, __u8 data)
{
__u8 bData = data;
// __u8 btmp;
int i;
ClkTx(iobase, 0, 1);
Tdelay(2);
ActClk(iobase, 1);
Tdelay(1);
for (i = 0; i < 8; i++) { //LDN
if ((bData >> i) & 0x01) {
ClkTx(iobase, 0, 1); //bit data = 1;
} else {
ClkTx(iobase, 0, 0); //bit data = 1;
}
Tdelay(2);
Sdelay(1);
ActClk(iobase, 1); //clk hi
Tdelay(1);
}
}
static __u8 Rd_Indx(__u16 iobase, __u8 addr, __u8 index)
{
__u8 data = 0, bTmp, data_bit;
int i;
bTmp = addr | (index << 1) | 0;
ClkTx(iobase, 0, 0);
Tdelay(2);
ActClk(iobase, 1);
udelay(1);
Wr_Byte(iobase, bTmp);
Sdelay(1);
ClkTx(iobase, 0, 0);
Tdelay(2);
for (i = 0; i < 10; i++) {
ActClk(iobase, 1);
Tdelay(1);
ActClk(iobase, 0);
Tdelay(1);
ClkTx(iobase, 0, 1);
Tdelay(1);
bTmp = ReadReg(iobase, 0x34);
if (!(bTmp & Rd_Valid))
break;
}
if (!(bTmp & Rd_Valid)) {
for (i = 0; i < 8; i++) {
ActClk(iobase, 1);
Tdelay(1);
ActClk(iobase, 0);
bTmp = ReadReg(iobase, 0x34);
data_bit = 1 << i;
if (bTmp & RxBit)
data |= data_bit;
else
data &= ~data_bit;
Tdelay(2);
}
} else {
for (i = 0; i < 2; i++) {
ActClk(iobase, 1);
Tdelay(1);
ActClk(iobase, 0);
Tdelay(2);
}
bTmp = ReadReg(iobase, 0x34);
}
for (i = 0; i < 1; i++) {
ActClk(iobase, 1);
Tdelay(1);
ActClk(iobase, 0);
Tdelay(2);
}
ClkTx(iobase, 0, 0);
Tdelay(1);
for (i = 0; i < 3; i++) {
ActClk(iobase, 1);
Tdelay(1);
ActClk(iobase, 0);
Tdelay(2);
}
return data;
}
static void Wr_Indx(__u16 iobase, __u8 addr, __u8 index, __u8 data)
{
int i;
__u8 bTmp;
ClkTx(iobase, 0, 0);
udelay(2);
ActClk(iobase, 1);
udelay(1);
bTmp = addr | (index << 1) | 1;
Wr_Byte(iobase, bTmp);
Wr_Byte(iobase, data);
for (i = 0; i < 2; i++) {
ClkTx(iobase, 0, 0);
Tdelay(2);
ActClk(iobase, 1);
Tdelay(1);
}
ActClk(iobase, 0);
}
static void ResetDongle(__u16 iobase)
{
int i;
ClkTx(iobase, 0, 0);
Tdelay(1);
for (i = 0; i < 30; i++) {
ActClk(iobase, 1);
Tdelay(1);
ActClk(iobase, 0);
Tdelay(1);
}
ActClk(iobase, 0);
}
static void SetSITmode(__u16 iobase)
{
__u8 bTmp;
bTmp = ReadLPCReg(0x28);
WriteLPCReg(0x28, bTmp | 0x10); //select ITMOFF
bTmp = ReadReg(iobase, 0x35);
WriteReg(iobase, 0x35, bTmp | 0x40); // Driver ITMOFF
WriteReg(iobase, 0x28, bTmp | 0x80); // enable All interrupt
}
static void SI_SetMode(__u16 iobase, int mode)
{
//__u32 dTmp;
__u8 bTmp;
WriteLPCReg(0x28, 0x70); // S/W Reset
SetSITmode(iobase);
ResetDongle(iobase);
udelay(10);
Wr_Indx(iobase, 0x40, 0x0, 0x17); //RX ,APEN enable,Normal power
Wr_Indx(iobase, 0x40, 0x1, mode); //Set Mode
Wr_Indx(iobase, 0x40, 0x2, 0xff); //Set power to FIR VFIR > 1m
bTmp = Rd_Indx(iobase, 0x40, 1);
}
static void InitCard(__u16 iobase)
{
ResetChip(iobase, 5);
WriteReg(iobase, I_ST_CT_0, 0x00); // open CHIP on
SetSIRBOF(iobase, 0xc0); // hardware default value
SetSIREOF(iobase, 0xc1);
}
static void CommonInit(__u16 iobase)
{
// EnTXCRC(iobase,0);
SwapDMA(iobase, OFF);
SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095
EnRXFIFOReadyInt(iobase, OFF);
EnRXFIFOHalfLevelInt(iobase, OFF);
EnTXFIFOHalfLevelInt(iobase, OFF);
EnTXFIFOUnderrunEOMInt(iobase, ON);
// EnTXFIFOReadyInt(iobase,ON);
InvertTX(iobase, OFF);
InvertRX(iobase, OFF);
// WriteLPCReg(0xF0,0); //(if VT1211 then do this)
if (IsSIROn(iobase)) {
SIRFilter(iobase, ON);
SIRRecvAny(iobase, ON);
} else {
SIRFilter(iobase, OFF);
SIRRecvAny(iobase, OFF);
}
EnRXSpecInt(iobase, ON);
WriteReg(iobase, I_ST_CT_0, 0x80);
EnableDMA(iobase, ON);
}
static void SetBaudRate(__u16 iobase, __u32 rate)
{
__u8 value = 11, temp;
if (IsSIROn(iobase)) {
switch (rate) {
case (__u32) (2400L):
value = 47;
break;
case (__u32) (9600L):
value = 11;
break;
case (__u32) (19200L):
value = 5;
break;
case (__u32) (38400L):
value = 2;
break;
case (__u32) (57600L):
value = 1;
break;
case (__u32) (115200L):
value = 0;
break;
default:
break;
}
} else if (IsMIROn(iobase)) {
value = 0; // will automatically be fixed in 1.152M
} else if (IsFIROn(iobase)) {
value = 0; // will automatically be fixed in 4M
}
temp = (ReadReg(iobase, I_CF_H_1) & 0x03);
temp |= value << 2;
WriteReg(iobase, I_CF_H_1, temp);
}
static void SetPulseWidth(__u16 iobase, __u8 width)
{
__u8 temp, temp1, temp2;
temp = (ReadReg(iobase, I_CF_L_1) & 0x1f);
temp1 = (ReadReg(iobase, I_CF_H_1) & 0xfc);
temp2 = (width & 0x07) << 5;
temp |= temp2;
temp2 = (width & 0x18) >> 3;
temp1 |= temp2;
WriteReg(iobase, I_CF_L_1, temp);
WriteReg(iobase, I_CF_H_1, temp1);
}
static void SetSendPreambleCount(__u16 iobase, __u8 count)
{
__u8 temp;
temp = ReadReg(iobase, I_CF_L_1) & 0xe0;
temp |= count;
WriteReg(iobase, I_CF_L_1, temp);
}
static void SetVFIR(__u16 BaseAddr, __u8 val)
{
__u8 tmp;
tmp = ReadReg(BaseAddr, I_CF_L_0);
WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
WriteRegBit(BaseAddr, I_CF_H_0, 5, val);
}
static void SetFIR(__u16 BaseAddr, __u8 val)
{
__u8 tmp;
WriteRegBit(BaseAddr, I_CF_H_0, 5, 0);
tmp = ReadReg(BaseAddr, I_CF_L_0);
WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
WriteRegBit(BaseAddr, I_CF_L_0, 6, val);
}
static void SetMIR(__u16 BaseAddr, __u8 val)
{
__u8 tmp;
WriteRegBit(BaseAddr, I_CF_H_0, 5, 0);
tmp = ReadReg(BaseAddr, I_CF_L_0);
WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
WriteRegBit(BaseAddr, I_CF_L_0, 5, val);
}
static void SetSIR(__u16 BaseAddr, __u8 val)
{
__u8 tmp;
WriteRegBit(BaseAddr, I_CF_H_0, 5, 0);
tmp = ReadReg(BaseAddr, I_CF_L_0);
WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f);
WriteRegBit(BaseAddr, I_CF_L_0, 4, val);
}
#endif /* via_IRCC_H */

1883
drivers/net/irda/vlsi_ir.c Normal file

File diff suppressed because it is too large Load diff

756
drivers/net/irda/vlsi_ir.h Normal file
View file

@ -0,0 +1,756 @@
/*********************************************************************
*
* vlsi_ir.h: VLSI82C147 PCI IrDA controller driver for Linux
*
* Version: 0.5
*
* Copyright (c) 2001-2003 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.
*
* 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, see <http://www.gnu.org/licenses/>.
*
********************************************************************/
#ifndef IRDA_VLSI_FIR_H
#define IRDA_VLSI_FIR_H
/* ================================================================
* compatibility stuff
*/
/* definitions not present in pci_ids.h */
#ifndef PCI_CLASS_WIRELESS_IRDA
#define PCI_CLASS_WIRELESS_IRDA 0x0d00
#endif
#ifndef PCI_CLASS_SUBCLASS_MASK
#define PCI_CLASS_SUBCLASS_MASK 0xffff
#endif
/* ================================================================ */
/* non-standard PCI registers */
enum vlsi_pci_regs {
VLSI_PCI_CLKCTL = 0x40, /* chip clock input control */
VLSI_PCI_MSTRPAGE = 0x41, /* addr [31:24] for all busmaster cycles */
VLSI_PCI_IRMISC = 0x42 /* mainly legacy UART related */
};
/* ------------------------------------------ */
/* VLSI_PCI_CLKCTL: Clock Control Register (u8, rw) */
/* Three possible clock sources: either on-chip 48MHz PLL or
* external clock applied to EXTCLK pin. External clock may
* be either 48MHz or 40MHz, which is indicated by XCKSEL.
* CLKSTP controls whether the selected clock source gets
* connected to the IrDA block.
*
* On my HP OB-800 the BIOS sets external 40MHz clock as source
* when IrDA enabled and I've never detected any PLL lock success.
* Apparently the 14.3...MHz OSC input required for the PLL to work
* is not connected and the 40MHz EXTCLK is provided externally.
* At least this is what makes the driver working for me.
*/
enum vlsi_pci_clkctl {
/* PLL control */
CLKCTL_PD_INV = 0x04, /* PD#: inverted power down signal,
* i.e. PLL is powered, if PD_INV set */
CLKCTL_LOCK = 0x40, /* (ro) set, if PLL is locked */
/* clock source selection */
CLKCTL_EXTCLK = 0x20, /* set to select external clock input, not PLL */
CLKCTL_XCKSEL = 0x10, /* set to indicate EXTCLK is 40MHz, not 48MHz */
/* IrDA block control */
CLKCTL_CLKSTP = 0x80, /* set to disconnect from selected clock source */
CLKCTL_WAKE = 0x08 /* set to enable wakeup feature: whenever IR activity
* is detected, PD_INV gets set(?) and CLKSTP cleared */
};
/* ------------------------------------------ */
/* VLSI_PCI_MSTRPAGE: Master Page Register (u8, rw) and busmastering stuff */
#define DMA_MASK_USED_BY_HW 0xffffffff
#define DMA_MASK_MSTRPAGE 0x00ffffff
#define MSTRPAGE_VALUE (DMA_MASK_MSTRPAGE >> 24)
/* PCI busmastering is somewhat special for this guy - in short:
*
* We select to operate using fixed MSTRPAGE=0, use ISA DMA
* address restrictions to make the PCI BM api aware of this,
* but ensure the hardware is dealing with real 32bit access.
*
* In detail:
* The chip executes normal 32bit busmaster cycles, i.e.
* drives all 32 address lines. These addresses however are
* composed of [0:23] taken from various busaddr-pointers
* and [24:31] taken from the MSTRPAGE register in the VLSI82C147
* config space. Therefore _all_ busmastering must be
* targeted to/from one single 16MB (busaddr-) superpage!
* The point is to make sure all the allocations for memory
* locations with busmaster access (ring descriptors, buffers)
* are indeed bus-mappable to the same 16MB range (for x86 this
* means they must reside in the same 16MB physical memory address
* range). The only constraint we have which supports "several objects
* mappable to common 16MB range" paradigma, is the old ISA DMA
* restriction to the first 16MB of physical address range.
* Hence the approach here is to enable PCI busmaster support using
* the correct 32bit dma-mask used by the chip. Afterwards the device's
* dma-mask gets restricted to 24bit, which must be honoured somehow by
* all allocations for memory areas to be exposed to the chip ...
*
* Note:
* Don't be surprised to get "Setting latency timer..." messages every
* time when PCI busmastering is enabled for the chip.
* The chip has its PCI latency timer RO fixed at 0 - which is not a
* problem here, because it is never requesting _burst_ transactions.
*/
/* ------------------------------------------ */
/* VLSI_PCIIRMISC: IR Miscellaneous Register (u8, rw) */
/* legacy UART emulation - not used by this driver - would require:
* (see below for some register-value definitions)
*
* - IRMISC_UARTEN must be set to enable UART address decoding
* - IRMISC_UARTSEL configured
* - IRCFG_MASTER must be cleared
* - IRCFG_SIR must be set
* - IRENABLE_PHYANDCLOCK must be asserted 0->1 (and hence IRENABLE_SIR_ON)
*/
enum vlsi_pci_irmisc {
/* IR transceiver control */
IRMISC_IRRAIL = 0x40, /* (ro?) IR rail power indication (and control?)
* 0=3.3V / 1=5V. Probably set during power-on?
* unclear - not touched by driver */
IRMISC_IRPD = 0x08, /* transceiver power down, if set */
/* legacy UART control */
IRMISC_UARTTST = 0x80, /* UART test mode - "always write 0" */
IRMISC_UARTEN = 0x04, /* enable UART address decoding */
/* bits [1:0] IRMISC_UARTSEL to select legacy UART address */
IRMISC_UARTSEL_3f8 = 0x00,
IRMISC_UARTSEL_2f8 = 0x01,
IRMISC_UARTSEL_3e8 = 0x02,
IRMISC_UARTSEL_2e8 = 0x03
};
/* ================================================================ */
/* registers mapped to 32 byte PCI IO space */
/* note: better access all registers at the indicated u8/u16 size
* although some of them contain only 1 byte of information.
* some of them (particaluarly PROMPT and IRCFG) ignore
* access when using the wrong addressing mode!
*/
enum vlsi_pio_regs {
VLSI_PIO_IRINTR = 0x00, /* interrupt enable/request (u8, rw) */
VLSI_PIO_RINGPTR = 0x02, /* rx/tx ring pointer (u16, ro) */
VLSI_PIO_RINGBASE = 0x04, /* [23:10] of ring address (u16, rw) */
VLSI_PIO_RINGSIZE = 0x06, /* rx/tx ring size (u16, rw) */
VLSI_PIO_PROMPT = 0x08, /* triggers ring processing (u16, wo) */
/* 0x0a-0x0f: reserved / duplicated UART regs */
VLSI_PIO_IRCFG = 0x10, /* configuration select (u16, rw) */
VLSI_PIO_SIRFLAG = 0x12, /* BOF/EOF for filtered SIR (u16, ro) */
VLSI_PIO_IRENABLE = 0x14, /* enable and status register (u16, rw/ro) */
VLSI_PIO_PHYCTL = 0x16, /* physical layer current status (u16, ro) */
VLSI_PIO_NPHYCTL = 0x18, /* next physical layer select (u16, rw) */
VLSI_PIO_MAXPKT = 0x1a, /* [11:0] max len for packet receive (u16, rw) */
VLSI_PIO_RCVBCNT = 0x1c /* current receive-FIFO byte count (u16, ro) */
/* 0x1e-0x1f: reserved / duplicated UART regs */
};
/* ------------------------------------------ */
/* VLSI_PIO_IRINTR: Interrupt Register (u8, rw) */
/* enable-bits:
* 1 = enable / 0 = disable
* interrupt condition bits:
* set according to corresponding interrupt source
* (regardless of the state of the enable bits)
* enable bit status indicates whether interrupt gets raised
* write-to-clear
* note: RPKTINT and TPKTINT behave different in legacy UART mode (which we don't use :-)
*/
enum vlsi_pio_irintr {
IRINTR_ACTEN = 0x80, /* activity interrupt enable */
IRINTR_ACTIVITY = 0x40, /* activity monitor (traffic detected) */
IRINTR_RPKTEN = 0x20, /* receive packet interrupt enable*/
IRINTR_RPKTINT = 0x10, /* rx-packet transferred from fifo to memory finished */
IRINTR_TPKTEN = 0x08, /* transmit packet interrupt enable */
IRINTR_TPKTINT = 0x04, /* last bit of tx-packet+crc shifted to ir-pulser */
IRINTR_OE_EN = 0x02, /* UART rx fifo overrun error interrupt enable */
IRINTR_OE_INT = 0x01 /* UART rx fifo overrun error (read LSR to clear) */
};
/* we use this mask to check whether the (shared PCI) interrupt is ours */
#define IRINTR_INT_MASK (IRINTR_ACTIVITY|IRINTR_RPKTINT|IRINTR_TPKTINT)
/* ------------------------------------------ */
/* VLSI_PIO_RINGPTR: Ring Pointer Read-Back Register (u16, ro) */
/* _both_ ring pointers are indices relative to the _entire_ rx,tx-ring!
* i.e. the referenced descriptor is located
* at RINGBASE + PTR * sizeof(descr) for rx and tx
* therefore, the tx-pointer has offset MAX_RING_DESCR
*/
#define MAX_RING_DESCR 64 /* tx, rx rings may contain up to 64 descr each */
#define RINGPTR_RX_MASK (MAX_RING_DESCR-1)
#define RINGPTR_TX_MASK ((MAX_RING_DESCR-1)<<8)
#define RINGPTR_GET_RX(p) ((p)&RINGPTR_RX_MASK)
#define RINGPTR_GET_TX(p) (((p)&RINGPTR_TX_MASK)>>8)
/* ------------------------------------------ */
/* VLSI_PIO_RINGBASE: Ring Pointer Base Address Register (u16, ro) */
/* Contains [23:10] part of the ring base (bus-) address
* which must be 1k-alinged. [31:24] is taken from
* VLSI_PCI_MSTRPAGE above.
* The controller initiates non-burst PCI BM cycles to
* fetch and update the descriptors in the ring.
* Once fetched, the descriptor remains cached onchip
* until it gets closed and updated due to the ring
* processing state machine.
* The entire ring area is split in rx and tx areas with each
* area consisting of 64 descriptors of 8 bytes each.
* The rx(tx) ring is located at ringbase+0 (ringbase+64*8).
*/
#define BUS_TO_RINGBASE(p) (((p)>>10)&0x3fff)
/* ------------------------------------------ */
/* VLSI_PIO_RINGSIZE: Ring Size Register (u16, rw) */
/* bit mask to indicate the ring size to be used for rx and tx.
* possible values encoded bits
* 4 0000
* 8 0001
* 16 0011
* 32 0111
* 64 1111
* located at [15:12] for tx and [11:8] for rx ([7:0] unused)
*
* note: probably a good idea to have IRCFG_MSTR cleared when writing
* this so the state machines are stopped and the RINGPTR is reset!
*/
#define SIZE_TO_BITS(num) ((((num)-1)>>2)&0x0f)
#define TX_RX_TO_RINGSIZE(tx,rx) ((SIZE_TO_BITS(tx)<<12)|(SIZE_TO_BITS(rx)<<8))
#define RINGSIZE_TO_RXSIZE(rs) ((((rs)&0x0f00)>>6)+4)
#define RINGSIZE_TO_TXSIZE(rs) ((((rs)&0xf000)>>10)+4)
/* ------------------------------------------ */
/* VLSI_PIO_PROMPT: Ring Prompting Register (u16, write-to-start) */
/* writing any value kicks the ring processing state machines
* for both tx, rx rings as follows:
* - active rings (currently owning an active descriptor)
* ignore the prompt and continue
* - idle rings fetch the next descr from the ring and start
* their processing
*/
/* ------------------------------------------ */
/* VLSI_PIO_IRCFG: IR Config Register (u16, rw) */
/* notes:
* - not more than one SIR/MIR/FIR bit must be set at any time
* - SIR, MIR, FIR and CRC16 select the configuration which will
* be applied on next 0->1 transition of IRENABLE_PHYANDCLOCK (see below).
* - besides allowing the PCI interface to execute busmaster cycles
* and therefore the ring SM to operate, the MSTR bit has side-effects:
* when MSTR is cleared, the RINGPTR's get reset and the legacy UART mode
* (in contrast to busmaster access mode) gets enabled.
* - clearing ENRX or setting ENTX while data is received may stall the
* receive fifo until ENRX reenabled _and_ another packet arrives
* - SIRFILT means the chip performs the required unwrapping of hardware
* headers (XBOF's, BOF/EOF) and un-escaping in the _receive_ direction.
* Only the resulting IrLAP payload is copied to the receive buffers -
* but with the 16bit FCS still encluded. Question remains, whether it
* was already checked or we should do it before passing the packet to IrLAP?
*/
enum vlsi_pio_ircfg {
IRCFG_LOOP = 0x4000, /* enable loopback test mode */
IRCFG_ENTX = 0x1000, /* transmit enable */
IRCFG_ENRX = 0x0800, /* receive enable */
IRCFG_MSTR = 0x0400, /* master enable */
IRCFG_RXANY = 0x0200, /* receive any packet */
IRCFG_CRC16 = 0x0080, /* 16bit (not 32bit) CRC select for MIR/FIR */
IRCFG_FIR = 0x0040, /* FIR 4PPM encoding mode enable */
IRCFG_MIR = 0x0020, /* MIR HDLC encoding mode enable */
IRCFG_SIR = 0x0010, /* SIR encoding mode enable */
IRCFG_SIRFILT = 0x0008, /* enable SIR decode filter (receiver unwrapping) */
IRCFG_SIRTEST = 0x0004, /* allow SIR decode filter when not in SIR mode */
IRCFG_TXPOL = 0x0002, /* invert tx polarity when set */
IRCFG_RXPOL = 0x0001 /* invert rx polarity when set */
};
/* ------------------------------------------ */
/* VLSI_PIO_SIRFLAG: SIR Flag Register (u16, ro) */
/* register contains hardcoded BOF=0xc0 at [7:0] and EOF=0xc1 at [15:8]
* which is used for unwrapping received frames in SIR decode-filter mode
*/
/* ------------------------------------------ */
/* VLSI_PIO_IRENABLE: IR Enable Register (u16, rw/ro) */
/* notes:
* - IREN acts as gate for latching the configured IR mode information
* from IRCFG and IRPHYCTL when IREN=reset and applying them when
* IREN gets set afterwards.
* - ENTXST reflects IRCFG_ENTX
* - ENRXST = IRCFG_ENRX && (!IRCFG_ENTX || IRCFG_LOOP)
*/
enum vlsi_pio_irenable {
IRENABLE_PHYANDCLOCK = 0x8000, /* enable IR phy and gate the mode config (rw) */
IRENABLE_CFGER = 0x4000, /* mode configuration error (ro) */
IRENABLE_FIR_ON = 0x2000, /* FIR on status (ro) */
IRENABLE_MIR_ON = 0x1000, /* MIR on status (ro) */
IRENABLE_SIR_ON = 0x0800, /* SIR on status (ro) */
IRENABLE_ENTXST = 0x0400, /* transmit enable status (ro) */
IRENABLE_ENRXST = 0x0200, /* Receive enable status (ro) */
IRENABLE_CRC16_ON = 0x0100 /* 16bit (not 32bit) CRC enabled status (ro) */
};
#define IRENABLE_MASK 0xff00 /* Read mask */
/* ------------------------------------------ */
/* VLSI_PIO_PHYCTL: IR Physical Layer Current Control Register (u16, ro) */
/* read-back of the currently applied physical layer status.
* applied from VLSI_PIO_NPHYCTL at rising edge of IRENABLE_PHYANDCLOCK
* contents identical to VLSI_PIO_NPHYCTL (see below)
*/
/* ------------------------------------------ */
/* VLSI_PIO_NPHYCTL: IR Physical Layer Next Control Register (u16, rw) */
/* latched during IRENABLE_PHYANDCLOCK=0 and applied at 0-1 transition
*
* consists of BAUD[15:10], PLSWID[9:5] and PREAMB[4:0] bits defined as follows:
*
* SIR-mode: BAUD = (115.2kHz / baudrate) - 1
* PLSWID = (pulsetime * freq / (BAUD+1)) - 1
* where pulsetime is the requested IrPHY pulse width
* and freq is 8(16)MHz for 40(48)MHz primary input clock
* PREAMB: don't care for SIR
*
* The nominal SIR pulse width is 3/16 bit time so we have PLSWID=12
* fixed for all SIR speeds at 40MHz input clock (PLSWID=24 at 48MHz).
* IrPHY also allows shorter pulses down to the nominal pulse duration
* at 115.2kbaud (minus some tolerance) which is 1.41 usec.
* Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by two for 48MHz)
* we get the minimum acceptable PLSWID values according to the VLSI
* specification, which provides 1.5 usec pulse width for all speeds (except
* for 2.4kbaud getting 6usec). This is fine with IrPHY v1.3 specs and
* reduces the transceiver power which drains the battery. At 9.6kbaud for
* example this amounts to more than 90% battery power saving!
*
* MIR-mode: BAUD = 0
* PLSWID = 9(10) for 40(48) MHz input clock
* to get nominal MIR pulse width
* PREAMB = 1
*
* FIR-mode: BAUD = 0
* PLSWID: don't care
* PREAMB = 15
*/
#define PHYCTL_BAUD_SHIFT 10
#define PHYCTL_BAUD_MASK 0xfc00
#define PHYCTL_PLSWID_SHIFT 5
#define PHYCTL_PLSWID_MASK 0x03e0
#define PHYCTL_PREAMB_SHIFT 0
#define PHYCTL_PREAMB_MASK 0x001f
#define PHYCTL_TO_BAUD(bwp) (((bwp)&PHYCTL_BAUD_MASK)>>PHYCTL_BAUD_SHIFT)
#define PHYCTL_TO_PLSWID(bwp) (((bwp)&PHYCTL_PLSWID_MASK)>>PHYCTL_PLSWID_SHIFT)
#define PHYCTL_TO_PREAMB(bwp) (((bwp)&PHYCTL_PREAMB_MASK)>>PHYCTL_PREAMB_SHIFT)
#define BWP_TO_PHYCTL(b,w,p) ((((b)<<PHYCTL_BAUD_SHIFT)&PHYCTL_BAUD_MASK) \
| (((w)<<PHYCTL_PLSWID_SHIFT)&PHYCTL_PLSWID_MASK) \
| (((p)<<PHYCTL_PREAMB_SHIFT)&PHYCTL_PREAMB_MASK))
#define BAUD_BITS(br) ((115200/(br))-1)
static inline unsigned
calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect)
{
unsigned tmp;
if (widthselect) /* nominal 3/16 puls width */
return (clockselect) ? 12 : 24;
tmp = ((clockselect) ? 12 : 24) / (BAUD_BITS(baudrate)+1);
/* intermediate result of integer division needed here */
return (tmp>0) ? (tmp-1) : 0;
}
#define PHYCTL_SIR(br,ws,cs) BWP_TO_PHYCTL(BAUD_BITS(br),calc_width_bits((br),(ws),(cs)),0)
#define PHYCTL_MIR(cs) BWP_TO_PHYCTL(0,((cs)?9:10),1)
#define PHYCTL_FIR BWP_TO_PHYCTL(0,0,15)
/* quite ugly, I know. But implementing these calculations here avoids
* having magic numbers in the code and allows some playing with pulsewidths
* without risk to violate the standards.
* FWIW, here is the table for reference:
*
* baudrate BAUD min-PLSWID nom-PLSWID PREAMB
* 2400 47 0(0) 12(24) 0
* 9600 11 0(0) 12(24) 0
* 19200 5 1(2) 12(24) 0
* 38400 2 3(6) 12(24) 0
* 57600 1 5(10) 12(24) 0
* 115200 0 11(22) 12(24) 0
* MIR 0 - 9(10) 1
* FIR 0 - 0 15
*
* note: x(y) means x-value for 40MHz / y-value for 48MHz primary input clock
*/
/* ------------------------------------------ */
/* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) */
/* maximum acceptable length for received packets */
/* hw imposed limitation - register uses only [11:0] */
#define MAX_PACKET_LENGTH 0x0fff
/* IrLAP I-field (apparently not defined elsewhere) */
#define IRDA_MTU 2048
/* complete packet consists of A(1)+C(1)+I(<=IRDA_MTU) */
#define IRLAP_SKB_ALLOCSIZE (1+1+IRDA_MTU)
/* the buffers we use to exchange frames with the hardware need to be
* larger than IRLAP_SKB_ALLOCSIZE because we may have up to 4 bytes FCS
* appended and, in SIR mode, a lot of frame wrapping bytes. The worst
* case appears to be a SIR packet with I-size==IRDA_MTU and all bytes
* requiring to be escaped to provide transparency. Furthermore, the peer
* might ask for quite a number of additional XBOFs:
* up to 115+48 XBOFS 163
* regular BOF 1
* A-field 1
* C-field 1
* I-field, IRDA_MTU, all escaped 4096
* FCS (16 bit at SIR, escaped) 4
* EOF 1
* AFAICS nothing in IrLAP guarantees A/C field not to need escaping
* (f.e. 0xc0/0xc1 - i.e. BOF/EOF - are legal values there) so in the
* worst case we have 4269 bytes total frame size.
* However, the VLSI uses 12 bits only for all buffer length values,
* which limits the maximum useable buffer size <= 4095.
* Note this is not a limitation in the receive case because we use
* the SIR filtering mode where the hw unwraps the frame and only the
* bare packet+fcs is stored into the buffer - in contrast to the SIR
* tx case where we have to pass frame-wrapped packets to the hw.
* If this would ever become an issue in real life, the only workaround
* I see would be using the legacy UART emulation in SIR mode.
*/
#define XFER_BUF_SIZE MAX_PACKET_LENGTH
/* ------------------------------------------ */
/* VLSI_PIO_RCVBCNT: Receive Byte Count Register (u16, ro) */
/* receive packet counter gets incremented on every non-filtered
* byte which was put in the receive fifo and reset for each
* new packet. Used to decide whether we are just in the middle
* of receiving
*/
/* better apply the [11:0] mask when reading, as some docs say the
* reserved [15:12] would return 1 when reading - which is wrong AFAICS
*/
#define RCVBCNT_MASK 0x0fff
/******************************************************************/
/* descriptors for rx/tx ring
*
* accessed by hardware - don't change!
*
* the descriptor is owned by hardware, when the ACTIVE status bit
* is set and nothing (besides reading status to test the bit)
* shall be done. The bit gets cleared by hw, when the descriptor
* gets closed. Premature reaping of descriptors owned be the chip
* can be achieved by disabling IRCFG_MSTR
*
* Attention: Writing addr overwrites status!
*
* ### FIXME: depends on endianess (but there ain't no non-i586 ob800 ;-)
*/
struct ring_descr_hw {
volatile __le16 rd_count; /* tx/rx count [11:0] */
__le16 reserved;
union {
__le32 addr; /* [23:0] of the buffer's busaddress */
struct {
u8 addr_res[3];
volatile u8 status; /* descriptor status */
} __packed rd_s;
} __packed rd_u;
} __packed;
#define rd_addr rd_u.addr
#define rd_status rd_u.rd_s.status
/* ring descriptor status bits */
#define RD_ACTIVE 0x80 /* descriptor owned by hw (both TX,RX) */
/* TX ring descriptor status */
#define RD_TX_DISCRC 0x40 /* do not send CRC (for SIR) */
#define RD_TX_BADCRC 0x20 /* force a bad CRC */
#define RD_TX_PULSE 0x10 /* send indication pulse after this frame (MIR/FIR) */
#define RD_TX_FRCEUND 0x08 /* force underrun */
#define RD_TX_CLRENTX 0x04 /* clear ENTX after this frame */
#define RD_TX_UNDRN 0x01 /* TX fifo underrun (probably PCI problem) */
/* RX ring descriptor status */
#define RD_RX_PHYERR 0x40 /* physical encoding error */
#define RD_RX_CRCERR 0x20 /* CRC error (MIR/FIR) */
#define RD_RX_LENGTH 0x10 /* frame exceeds buffer length */
#define RD_RX_OVER 0x08 /* RX fifo overrun (probably PCI problem) */
#define RD_RX_SIRBAD 0x04 /* EOF missing: BOF follows BOF (SIR, filtered) */
#define RD_RX_ERROR 0x7c /* any error in received frame */
/* the memory required to hold the 2 descriptor rings */
#define HW_RING_AREA_SIZE (2 * MAX_RING_DESCR * sizeof(struct ring_descr_hw))
/******************************************************************/
/* sw-ring descriptors consists of a bus-mapped transfer buffer with
* associated skb and a pointer to the hw entry descriptor
*/
struct ring_descr {
struct ring_descr_hw *hw;
struct sk_buff *skb;
void *buf;
};
/* wrappers for operations on hw-exposed ring descriptors
* access to the hw-part of the descriptors must use these.
*/
static inline int rd_is_active(struct ring_descr *rd)
{
return (rd->hw->rd_status & RD_ACTIVE) != 0;
}
static inline void rd_activate(struct ring_descr *rd)
{
rd->hw->rd_status |= RD_ACTIVE;
}
static inline void rd_set_status(struct ring_descr *rd, u8 s)
{
rd->hw->rd_status = s; /* may pass ownership to the hardware */
}
static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s)
{
/* order is important for two reasons:
* - overlayed: writing addr overwrites status
* - we want to write status last so we have valid address in
* case status has RD_ACTIVE set
*/
if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) {
IRDA_ERROR("%s: pci busaddr inconsistency!\n", __func__);
dump_stack();
return;
}
a &= DMA_MASK_MSTRPAGE; /* clear highbyte to make sure we won't write
* to status - just in case MSTRPAGE_VALUE!=0
*/
rd->hw->rd_addr = cpu_to_le32(a);
wmb();
rd_set_status(rd, s); /* may pass ownership to the hardware */
}
static inline void rd_set_count(struct ring_descr *rd, u16 c)
{
rd->hw->rd_count = cpu_to_le16(c);
}
static inline u8 rd_get_status(struct ring_descr *rd)
{
return rd->hw->rd_status;
}
static inline dma_addr_t rd_get_addr(struct ring_descr *rd)
{
dma_addr_t a;
a = le32_to_cpu(rd->hw->rd_addr);
return (a & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24);
}
static inline u16 rd_get_count(struct ring_descr *rd)
{
return le16_to_cpu(rd->hw->rd_count);
}
/******************************************************************/
/* sw descriptor rings for rx, tx:
*
* operations follow producer-consumer paradigm, with the hw
* in the middle doing the processing.
* ring size must be power of two.
*
* producer advances r->tail after inserting for processing
* consumer advances r->head after removing processed rd
* ring is empty if head==tail / full if (tail+1)==head
*/
struct vlsi_ring {
struct pci_dev *pdev;
int dir;
unsigned len;
unsigned size;
unsigned mask;
atomic_t head, tail;
struct ring_descr *rd;
};
/* ring processing helpers */
static inline struct ring_descr *ring_last(struct vlsi_ring *r)
{
int t;
t = atomic_read(&r->tail) & r->mask;
return (((t+1) & r->mask) == (atomic_read(&r->head) & r->mask)) ? NULL : &r->rd[t];
}
static inline struct ring_descr *ring_put(struct vlsi_ring *r)
{
atomic_inc(&r->tail);
return ring_last(r);
}
static inline struct ring_descr *ring_first(struct vlsi_ring *r)
{
int h;
h = atomic_read(&r->head) & r->mask;
return (h == (atomic_read(&r->tail) & r->mask)) ? NULL : &r->rd[h];
}
static inline struct ring_descr *ring_get(struct vlsi_ring *r)
{
atomic_inc(&r->head);
return ring_first(r);
}
/******************************************************************/
/* our private compound VLSI-PCI-IRDA device information */
typedef struct vlsi_irda_dev {
struct pci_dev *pdev;
struct irlap_cb *irlap;
struct qos_info qos;
unsigned mode;
int baud, new_baud;
dma_addr_t busaddr;
void *virtaddr;
struct vlsi_ring *tx_ring, *rx_ring;
struct timeval last_rx;
spinlock_t lock;
struct mutex mtx;
u8 resume_ok;
struct proc_dir_entry *proc_entry;
} vlsi_irda_dev_t;
/********************************************************/
/* the remapped error flags we use for returning from frame
* post-processing in vlsi_process_tx/rx() after it was completed
* by the hardware. These functions either return the >=0 number
* of transferred bytes in case of success or the negative (-)
* of the or'ed error flags.
*/
#define VLSI_TX_DROP 0x0001
#define VLSI_TX_FIFO 0x0002
#define VLSI_RX_DROP 0x0100
#define VLSI_RX_OVER 0x0200
#define VLSI_RX_LENGTH 0x0400
#define VLSI_RX_FRAME 0x0800
#define VLSI_RX_CRC 0x1000
/********************************************************/
#endif /* IRDA_VLSI_FIR_H */

View file

@ -0,0 +1,53 @@
#ifndef W83977AF_H
#define W83977AF_H
#define W977_EFIO_BASE 0x370
#define W977_EFIO2_BASE 0x3f0
#define W977_DEVICE_IR 0x06
/*
* Enter extended function mode
*/
static inline void w977_efm_enter(unsigned int efio)
{
outb(0x87, efio);
outb(0x87, efio);
}
/*
* Select a device to configure
*/
static inline void w977_select_device(__u8 devnum, unsigned int efio)
{
outb(0x07, efio);
outb(devnum, efio+1);
}
/*
* Write a byte to a register
*/
static inline void w977_write_reg(__u8 reg, __u8 value, unsigned int efio)
{
outb(reg, efio);
outb(value, efio+1);
}
/*
* read a byte from a register
*/
static inline __u8 w977_read_reg(__u8 reg, unsigned int efio)
{
outb(reg, efio);
return inb(efio+1);
}
/*
* Exit extended function mode
*/
static inline void w977_efm_exit(unsigned int efio)
{
outb(0xAA, efio);
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,198 @@
/*********************************************************************
*
* Filename: w83977af_ir.h
* Version:
* Description:
* Status: Experimental.
* Author: Paul VanderSpek
* Created at: Thu Nov 19 13:55:34 1998
* Modified at: Tue Jan 11 13:08:19 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-2000 Dag Brattli, 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.
*
********************************************************************/
#ifndef W83977AF_IR_H
#define W83977AF_IR_H
#include <asm/io.h>
#include <linux/types.h>
/* Flags for configuration register CRF0 */
#define ENBNKSEL 0x01
#define APEDCRC 0x02
#define TXW4C 0x04
#define RXW4C 0x08
/* Bank 0 */
#define RBR 0x00 /* Receiver buffer register */
#define TBR 0x00 /* Transmitter buffer register */
#define ICR 0x01 /* Interrupt configuration register */
#define ICR_ERBRI 0x01 /* Receiver buffer register interrupt */
#define ICR_ETBREI 0x02 /* Transeiver empty interrupt */
#define ICR_EUSRI 0x04//* IR status interrupt */
#define ICR_EHSRI 0x04
#define ICR_ETXURI 0x04 /* Tx underrun */
#define ICR_EDMAI 0x10 /* DMA interrupt */
#define ICR_ETXTHI 0x20 /* Transmitter threshold interrupt */
#define ICR_EFSFI 0x40 /* Frame status FIFO interrupt */
#define ICR_ETMRI 0x80 /* Timer interrupt */
#define UFR 0x02 /* FIFO control register */
#define UFR_EN_FIFO 0x01 /* Enable FIFO's */
#define UFR_RXF_RST 0x02 /* Reset Rx FIFO */
#define UFR_TXF_RST 0x04 /* Reset Tx FIFO */
#define UFR_RXTL 0x80 /* Rx FIFO threshold (set to 16) */
#define UFR_TXTL 0x20 /* Tx FIFO threshold (set to 17) */
#define ISR 0x02 /* Interrupt status register */
#define ISR_RXTH_I 0x01 /* Receive threshold interrupt */
#define ISR_TXEMP_I 0x02 /* Transmitter empty interrupt */
#define ISR_FEND_I 0x04
#define ISR_DMA_I 0x10
#define ISR_TXTH_I 0x20 /* Transmitter threshold interrupt */
#define ISR_FSF_I 0x40
#define ISR_TMR_I 0x80 /* Timer interrupt */
#define UCR 0x03 /* Uart control register */
#define UCR_DLS8 0x03 /* 8N1 */
#define SSR 0x03 /* Sets select register */
#define SET0 UCR_DLS8 /* Make sure we keep 8N1 */
#define SET1 (0x80|UCR_DLS8) /* Make sure we keep 8N1 */
#define SET2 0xE0
#define SET3 0xE4
#define SET4 0xE8
#define SET5 0xEC
#define SET6 0xF0
#define SET7 0xF4
#define HCR 0x04
#define HCR_MODE_MASK ~(0xD0)
#define HCR_SIR 0x60
#define HCR_MIR_576 0x20
#define HCR_MIR_1152 0x80
#define HCR_FIR 0xA0
#define HCR_EN_DMA 0x04
#define HCR_EN_IRQ 0x08
#define HCR_TX_WT 0x08
#define USR 0x05 /* IR status register */
#define USR_RDR 0x01 /* Receive data ready */
#define USR_TSRE 0x40 /* Transmitter empty? */
#define AUDR 0x07
#define AUDR_SFEND 0x08 /* Set a frame end */
#define AUDR_RXBSY 0x20 /* Rx busy */
#define AUDR_UNDR 0x40 /* Transeiver underrun */
/* Set 2 */
#define ABLL 0x00 /* Advanced baud rate divisor latch (low byte) */
#define ABHL 0x01 /* Advanced baud rate divisor latch (high byte) */
#define ADCR1 0x02
#define ADCR1_ADV_SL 0x01
#define ADCR1_D_CHSW 0x08 /* the specs are wrong. its bit 3, not 4 */
#define ADCR1_DMA_F 0x02
#define ADCR2 0x04
#define ADCR2_TXFS32 0x01
#define ADCR2_RXFS32 0x04
#define RXFDTH 0x07
/* Set 3 */
#define AUID 0x00
/* Set 4 */
#define TMRL 0x00 /* Timer value register (low byte) */
#define TMRH 0x01 /* Timer value register (high byte) */
#define IR_MSL 0x02 /* Infrared mode select */
#define IR_MSL_EN_TMR 0x01 /* Enable timer */
#define TFRLL 0x04 /* Transmitter frame length (low byte) */
#define TFRLH 0x05 /* Transmitter frame length (high byte) */
#define RFRLL 0x06 /* Receiver frame length (low byte) */
#define RFRLH 0x07 /* Receiver frame length (high byte) */
/* Set 5 */
#define FS_FO 0x05 /* Frame status FIFO */
#define FS_FO_FSFDR 0x80 /* Frame status FIFO data ready */
#define FS_FO_LST_FR 0x40 /* Frame lost */
#define FS_FO_MX_LEX 0x10 /* Max frame len exceeded */
#define FS_FO_PHY_ERR 0x08 /* Physical layer error */
#define FS_FO_CRC_ERR 0x04
#define FS_FO_RX_OV 0x02 /* Receive overrun */
#define FS_FO_FSF_OV 0x01 /* Frame status FIFO overrun */
#define FS_FO_ERR_MSK 0x5f /* Error mask */
#define RFLFL 0x06
#define RFLFH 0x07
/* Set 6 */
#define IR_CFG2 0x00
#define IR_CFG2_DIS_CRC 0x02
/* Set 7 */
#define IRM_CR 0x07 /* Infrared module control register */
#define IRM_CR_IRX_MSL 0x40
#define IRM_CR_AF_MNT 0x80 /* Automatic format */
/* For storing entries in the status FIFO */
struct st_fifo_entry {
int status;
int len;
};
struct st_fifo {
struct st_fifo_entry entries[10];
int head;
int tail;
int len;
};
/* Private data for each instance */
struct w83977af_ir {
struct st_fifo st_fifo;
int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
int tx_len; /* Number of frames in tx_buff */
struct net_device *netdev; /* Yes! we are some kind of netdevice */
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos; /* QoS capabilities for this device */
chipio_t io; /* IrDA controller information */
iobuff_t tx_buff; /* Transmit buffer */
iobuff_t rx_buff; /* Receive buffer */
dma_addr_t tx_buff_dma;
dma_addr_t rx_buff_dma;
/* Note : currently locking is *very* incomplete, but this
* will get you started. Check in nsc-ircc.c for a proper
* locking strategy. - Jean II */
spinlock_t lock; /* For serializing operations */
__u32 new_speed;
};
static inline void switch_bank( int iobase, int set)
{
outb(set, iobase+SSR);
}
#endif