Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Esse commit está contido em:
404
drivers/net/irda/Kconfig
Arquivo normal
404
drivers/net/irda/Kconfig
Arquivo normal
@@ -0,0 +1,404 @@
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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 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 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 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 LITELINK_DONGLE
|
||||
tristate "Parallax LiteLink dongle"
|
||||
depends on 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 DONGLE && IRDA && EXPERIMENTAL
|
||||
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 DONGLE && IRDA && EXPERIMENTAL
|
||||
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 DONGLE && IRDA && EXPERIMENTAL
|
||||
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 DONGLE && IRDA && EXPERIMENTAL
|
||||
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.c>.
|
||||
|
||||
config ACT200L_DONGLE
|
||||
tristate "ACTiSYS IR-200L dongle"
|
||||
depends on DONGLE && IRDA && EXPERIMENTAL
|
||||
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".
|
||||
|
||||
comment "Old SIR device drivers"
|
||||
|
||||
config IRPORT_SIR
|
||||
tristate "IrPORT (IrDA serial driver)"
|
||||
depends on IRDA && BROKEN_ON_SMP
|
||||
---help---
|
||||
Say Y here if you want to build support for the IrPORT IrDA device
|
||||
driver. To compile it as a module, choose M here: the module will be
|
||||
called irport. IrPORT can be used instead of IrTTY and sometimes
|
||||
this can be better. One example is if your IrDA port does not
|
||||
have echo-canceling, which will work OK with IrPORT since this
|
||||
driver is working in half-duplex mode only. You don't need to use
|
||||
irattach with IrPORT, but you just insert it the same way as FIR
|
||||
drivers (insmod irport io=0x3e8 irq=11). Notice that IrPORT is a
|
||||
SIR device driver which means that speed is limited to 115200 bps.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
comment "Old Serial dongle support"
|
||||
|
||||
config DONGLE_OLD
|
||||
bool "Old Serial dongle support"
|
||||
depends on (IRTTY_OLD || IRPORT_SIR) && BROKEN_ON_SMP
|
||||
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_OLD
|
||||
tristate "ESI JetEye PC dongle"
|
||||
depends on DONGLE_OLD && 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_OLD
|
||||
tristate "ACTiSYS IR-220L and IR220L+ dongle"
|
||||
depends on DONGLE_OLD && 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_OLD
|
||||
tristate "Tekram IrMate 210B dongle"
|
||||
depends on DONGLE_OLD && 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 GIRBIL_DONGLE_OLD
|
||||
tristate "Greenwich GIrBIL dongle"
|
||||
depends on DONGLE_OLD && IRDA
|
||||
help
|
||||
Say Y here if you want to build support for the Greenwich GIrBIL
|
||||
dongle. 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 insert "irattach -d girbil" in the
|
||||
/etc/irda/drivers script.
|
||||
|
||||
config LITELINK_DONGLE_OLD
|
||||
tristate "Parallax LiteLink dongle"
|
||||
depends on DONGLE_OLD && 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 MCP2120_DONGLE_OLD
|
||||
tristate "Microchip MCP2120"
|
||||
depends on DONGLE_OLD && IRDA
|
||||
help
|
||||
Say Y here if you want to build support for the Microchip MCP2120
|
||||
dongle. 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 insert "irattach -d mcp2120" in the
|
||||
/etc/irda/drivers script.
|
||||
|
||||
You must build this dongle yourself. For more information see:
|
||||
<http://www.eyetap.org/~tangf/irda_sir_linux.html>
|
||||
|
||||
config OLD_BELKIN_DONGLE_OLD
|
||||
tristate "Old Belkin dongle"
|
||||
depends on DONGLE_OLD && IRDA
|
||||
help
|
||||
Say Y here if you want to build support for the Adaptec Airport 1000
|
||||
and 2000 dongles. To compile it as a module, choose M here: the module
|
||||
will be called old_belkin. Some information is contained in the
|
||||
comments at the top of <file:drivers/net/irda/old_belkin.c>.
|
||||
|
||||
config ACT200L_DONGLE_OLD
|
||||
tristate "ACTiSYS IR-200L dongle (EXPERIMENTAL)"
|
||||
depends on DONGLE_OLD && EXPERIMENTAL && IRDA
|
||||
help
|
||||
Say Y here if you want to build support for the ACTiSYS IR-200L
|
||||
dongle. 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 dongles you will have to start irattach like this:
|
||||
"irattach -d act200l".
|
||||
|
||||
config MA600_DONGLE_OLD
|
||||
tristate "Mobile Action MA600 dongle (EXPERIMENTAL)"
|
||||
depends on DONGLE_OLD && EXPERIMENTAL && 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 tested on IrCOMM. To activate support for MA600
|
||||
dongles you will have to insert "irattach -d ma600" in the
|
||||
/etc/irda/drivers script. Note: irutils 0.9.15 requires no
|
||||
modification. irutils 0.9.9 needs modification. For more
|
||||
information, download the following tar gzip file.
|
||||
|
||||
There is a pre-compiled module on
|
||||
<http://engsvr.ust.hk/~eetwl95/ma600.html>
|
||||
|
||||
config EP7211_IR
|
||||
tristate "EP7211 I/R support"
|
||||
depends on DONGLE_OLD && ARCH_EP7211 && IRDA
|
||||
|
||||
comment "FIR device drivers"
|
||||
|
||||
config USB_IRDA
|
||||
tristate "IrDA USB dongles"
|
||||
depends on IRDA && USB
|
||||
---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 pecularities. 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 (EXPERIMENTAL)"
|
||||
depends on IRDA && USB && EXPERIMENTAL
|
||||
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
|
||||
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
|
||||
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
|
||||
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 Au1000 SIR/FIR"
|
||||
depends on MIPS_AU1000 && IRDA
|
||||
|
||||
config SMC_IRCC_FIR
|
||||
tristate "SMSC IrCC (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && IRDA && ISA
|
||||
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 (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && IRDA && ISA
|
||||
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 Sourth 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 (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && 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
|
||||
|
||||
config VIA_FIR
|
||||
tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
|
||||
depends on IRDA && ISA && PCI
|
||||
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 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.
|
||||
|
||||
endmenu
|
||||
|
47
drivers/net/irda/Makefile
Arquivo normal
47
drivers/net/irda/Makefile
Arquivo normal
@@ -0,0 +1,47 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# Old SIR drivers
|
||||
obj-$(CONFIG_IRPORT_SIR) += irport.o
|
||||
# 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
|
||||
# Old dongle drivers for old SIR drivers
|
||||
obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o
|
||||
obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o
|
||||
obj-$(CONFIG_ACTISYS_DONGLE_OLD) += actisys.o
|
||||
obj-$(CONFIG_GIRBIL_DONGLE_OLD) += girbil.o
|
||||
obj-$(CONFIG_LITELINK_DONGLE_OLD) += litelink.o
|
||||
obj-$(CONFIG_OLD_BELKIN_DONGLE_OLD) += old_belkin.o
|
||||
obj-$(CONFIG_MCP2120_DONGLE_OLD) += mcp2120.o
|
||||
obj-$(CONFIG_ACT200L_DONGLE_OLD) += act200l.o
|
||||
obj-$(CONFIG_MA600_DONGLE_OLD) += ma600.o
|
||||
obj-$(CONFIG_EP7211_IR) += ep7211_ir.o
|
||||
obj-$(CONFIG_AU1000_FIR) += au1k_ir.o
|
||||
# New SIR drivers
|
||||
obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o
|
||||
# New dongles drivers for new SIR drivers
|
||||
obj-$(CONFIG_ESI_DONGLE) += esi-sir.o
|
||||
obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o
|
||||
obj-$(CONFIG_ACTISYS_DONGLE) += actisys-sir.o
|
||||
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
|
||||
|
||||
# The SIR helper module
|
||||
sir-dev-objs := sir_core.o sir_dev.o sir_dongle.o sir_kthread.o
|
257
drivers/net/irda/act200l-sir.c
Arquivo normal
257
drivers/net/irda/act200l-sir.c
Arquivo normal
@@ -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", __FUNCTION__ );
|
||||
|
||||
/* 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", __FUNCTION__ );
|
||||
|
||||
/* 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", __FUNCTION__ );
|
||||
|
||||
/* 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;
|
||||
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", __FUNCTION__ );
|
||||
|
||||
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", __FUNCTION__, 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);
|
297
drivers/net/irda/act200l.c
Arquivo normal
297
drivers/net/irda/act200l.c
Arquivo normal
@@ -0,0 +1,297 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
static int act200l_reset(struct irda_task *task);
|
||||
static void act200l_open(dongle_t *self, struct qos_info *qos);
|
||||
static void act200l_close(dongle_t *self);
|
||||
static int act200l_change_speed(struct irda_task *task);
|
||||
|
||||
/* 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_reg dongle = {
|
||||
.type = IRDA_ACT200L_DONGLE,
|
||||
.open = act200l_open,
|
||||
.close = act200l_close,
|
||||
.reset = act200l_reset,
|
||||
.change_speed = act200l_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init act200l_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit act200l_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void act200l_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
|
||||
|
||||
/* Power on the dongle */
|
||||
self->set_dtr_rts(self->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;
|
||||
}
|
||||
|
||||
static void act200l_close(dongle_t *self)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
|
||||
|
||||
/* Power off the dongle */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function act200l_change_speed (dev, speed)
|
||||
*
|
||||
* Set the speed for the ACTiSYS ACT-IR200L type dongle.
|
||||
*
|
||||
*/
|
||||
static int act200l_change_speed(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param;
|
||||
__u8 control[3];
|
||||
int ret = 0;
|
||||
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
|
||||
|
||||
self->speed_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
if (irda_task_execute(self, act200l_reset, NULL, task,
|
||||
(void *) speed))
|
||||
{
|
||||
/* Dongle need more time to reset */
|
||||
irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
|
||||
|
||||
/* Give reset 1 sec to finish */
|
||||
ret = msecs_to_jiffies(1000);
|
||||
}
|
||||
break;
|
||||
case IRDA_TASK_CHILD_WAIT:
|
||||
IRDA_WARNING("%s(), resetting dongle timed out!\n",
|
||||
__FUNCTION__);
|
||||
ret = -1;
|
||||
break;
|
||||
case IRDA_TASK_CHILD_DONE:
|
||||
/* Clear DTR and set RTS to enter command mode */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
|
||||
switch (speed) {
|
||||
case 9600:
|
||||
default:
|
||||
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 */
|
||||
self->write(self->dev, control, 3);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT);
|
||||
ret = msecs_to_jiffies(5);
|
||||
break;
|
||||
case IRDA_TASK_WAIT:
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function act200l_reset (driver)
|
||||
*
|
||||
* Reset the ACTiSYS ACT-IR200L type dongle.
|
||||
*/
|
||||
static int act200l_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__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", __FUNCTION__ );
|
||||
|
||||
self->reset_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
/* Power on the dongle */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT1);
|
||||
ret = msecs_to_jiffies(50);
|
||||
break;
|
||||
case IRDA_TASK_WAIT1:
|
||||
/* Reset the dongle : set RTS low for 25 ms */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT2);
|
||||
ret = msecs_to_jiffies(50);
|
||||
break;
|
||||
case IRDA_TASK_WAIT2:
|
||||
/* Clear DTR and set RTS to enter command mode */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
|
||||
/* Write control bytes */
|
||||
self->write(self->dev, control, 9);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT3);
|
||||
ret = msecs_to_jiffies(15);
|
||||
break;
|
||||
case IRDA_TASK_WAIT3:
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return 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 */
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize ACTiSYS ACT-IR200L module
|
||||
*
|
||||
*/
|
||||
module_init(act200l_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup ACTiSYS ACT-IR200L module
|
||||
*
|
||||
*/
|
||||
module_exit(act200l_cleanup);
|
246
drivers/net/irda/actisys-sir.c
Arquivo normal
246
drivers/net/irda/actisys-sir.c
Arquivo normal
@@ -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<6D> 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 (sizeof(baud_rates)/sizeof(baud_rates[0]))
|
||||
|
||||
static struct dongle_driver act220l = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "Actisys ACT-220L",
|
||||
.type = IRDA_ACTISYS_DONGLE,
|
||||
.open = actisys_open,
|
||||
.close = actisys_close,
|
||||
.reset = actisys_reset,
|
||||
.set_speed = actisys_change_speed,
|
||||
};
|
||||
|
||||
static struct dongle_driver act220l_plus = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "Actisys ACT-220L+",
|
||||
.type = IRDA_ACTISYS_PLUS_DONGLE,
|
||||
.open = actisys_open,
|
||||
.close = actisys_close,
|
||||
.reset = actisys_reset,
|
||||
.set_speed = actisys_change_speed,
|
||||
};
|
||||
|
||||
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", __FUNCTION__,
|
||||
speed, dev->speed);
|
||||
|
||||
/* dongle was already resetted from irda_request state machine,
|
||||
* we are in known state (dongle default)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Now, we can set the speed requested. Send RTS pulses until we
|
||||
* reach the target speed
|
||||
*/
|
||||
for (i = 0; i < MAX_SPEEDS; i++) {
|
||||
if (speed == baud_rates[i]) {
|
||||
dev->speed = 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);
|
288
drivers/net/irda/actisys.c
Arquivo normal
288
drivers/net/irda/actisys.c
Arquivo normal
@@ -0,0 +1,288 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Filename: actisys.c
|
||||
* Version: 1.0
|
||||
* 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)
|
||||
* Created at: Wed Oct 21 20:02:35 1998
|
||||
* Modified at: Fri Dec 17 09:10:43 1999
|
||||
* Modified by: Dag Brattli <dagb@cs.uit.no>
|
||||
*
|
||||
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
|
||||
* Copyright (c) 1999 Jean Tourrilhes
|
||||
*
|
||||
* 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<6D> 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...
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.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_change_speed(struct irda_task *task);
|
||||
static int actisys_reset(struct irda_task *task);
|
||||
static void actisys_open(dongle_t *self, struct qos_info *qos);
|
||||
static void actisys_close(dongle_t *self);
|
||||
|
||||
/* These are the baudrates supported, in the order available */
|
||||
/* Note : the 220L doesn't support 38400, but we will fix that below */
|
||||
static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
|
||||
#define MAX_SPEEDS 5
|
||||
|
||||
static struct dongle_reg dongle = {
|
||||
.type = IRDA_ACTISYS_DONGLE,
|
||||
.open = actisys_open,
|
||||
.close = actisys_close,
|
||||
.reset = actisys_reset,
|
||||
.change_speed = actisys_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct dongle_reg dongle_plus = {
|
||||
.type = IRDA_ACTISYS_PLUS_DONGLE,
|
||||
.open = actisys_open,
|
||||
.close = actisys_close,
|
||||
.reset = actisys_reset,
|
||||
.change_speed = actisys_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Function actisys_change_speed (task)
|
||||
*
|
||||
* There is two model of Actisys dongle we are dealing with,
|
||||
* the 220L and 220L+. At this point, only irattach knows with
|
||||
* kind the user has requested (it was an argument on irattach
|
||||
* command line).
|
||||
* So, we register a dongle of each sort and let irattach
|
||||
* pick the right one...
|
||||
*/
|
||||
static int __init actisys_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* First, register an Actisys 220L dongle */
|
||||
ret = irda_device_register_dongle(&dongle);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Now, register an Actisys 220L+ dongle */
|
||||
ret = irda_device_register_dongle(&dongle_plus);
|
||||
if (ret < 0) {
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit actisys_cleanup(void)
|
||||
{
|
||||
/* We have to remove both dongles */
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
irda_device_unregister_dongle(&dongle_plus);
|
||||
}
|
||||
|
||||
static void actisys_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
/* Power on the dongle */
|
||||
self->set_dtr_rts(self->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 (self->issue->type == IRDA_ACTISYS_DONGLE)
|
||||
qos->baud_rate.bits &= ~IR_38400;
|
||||
|
||||
qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
|
||||
}
|
||||
|
||||
static void actisys_close(dongle_t *self)
|
||||
{
|
||||
/* Power off the dongle */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param; /* Target speed */
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
|
||||
IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __FUNCTION__, speed,
|
||||
self->speed);
|
||||
|
||||
/* Go to a known state by reseting the dongle */
|
||||
|
||||
/* Reset the dongle : set DTR low for 10 us */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Go back to normal mode (we are now at 9600 b/s) */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/*
|
||||
* 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]) {
|
||||
self->speed = baud_rates[i];
|
||||
break;
|
||||
}
|
||||
/* Make sure previous pulse is finished */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Set RTS low for 10 us */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Set RTS high for 10 us */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
}
|
||||
|
||||
/* Check if life is sweet... */
|
||||
if (i >= MAX_SPEEDS)
|
||||
ret = -1; /* This should not happen */
|
||||
|
||||
/* Basta lavoro, on se casse d'ici... */
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
|
||||
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...
|
||||
* 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 irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
int ret = 0;
|
||||
|
||||
IRDA_ASSERT(task != NULL, return -1;);
|
||||
|
||||
self->reset_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
/* Set both DTR & RTS to power up the dongle */
|
||||
/* In theory redundant with power up in actisys_open() */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/* Sleep 50 ms to make sure capacitor is charged */
|
||||
ret = msecs_to_jiffies(50);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT);
|
||||
break;
|
||||
case IRDA_TASK_WAIT:
|
||||
/* Reset the dongle : set DTR low for 10 us */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
self->speed = 9600; /* That's the default */
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize Actisys module
|
||||
*
|
||||
*/
|
||||
module_init(actisys_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup Actisys module
|
||||
*
|
||||
*/
|
||||
module_exit(actisys_cleanup);
|
2277
drivers/net/irda/ali-ircc.c
Arquivo normal
2277
drivers/net/irda/ali-ircc.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
231
drivers/net/irda/ali-ircc.h
Arquivo normal
231
drivers/net/irda/ali-ircc.h
Arquivo normal
@@ -0,0 +1,231 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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; /* Lenght 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; /* Lenght 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 net_device_stats stats;
|
||||
|
||||
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;
|
||||
|
||||
struct pm_dev *dev;
|
||||
};
|
||||
|
||||
static inline void switch_bank(int iobase, int bank)
|
||||
{
|
||||
outb(bank, iobase+FIR_MCR);
|
||||
}
|
||||
|
||||
#endif /* ALI_IRCC_H */
|
127
drivers/net/irda/au1000_ircc.h
Arquivo normal
127
drivers/net/irda/au1000_ircc.h
Arquivo normal
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
*
|
||||
* BRIEF MODULE DESCRIPTION
|
||||
* Au1000 IrDA driver.
|
||||
*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: MontaVista Software, Inc.
|
||||
* ppopov@mvista.com or source@mvista.com
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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 AU1000_IRCC_H
|
||||
#define AU1000_IRCC_H
|
||||
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pm.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define NUM_IR_IFF 1
|
||||
#define NUM_IR_DESC 64
|
||||
#define RING_SIZE_4 0x0
|
||||
#define RING_SIZE_16 0x3
|
||||
#define RING_SIZE_64 0xF
|
||||
#define MAX_NUM_IR_DESC 64
|
||||
#define MAX_BUF_SIZE 2048
|
||||
|
||||
#define BPS_115200 0
|
||||
#define BPS_57600 1
|
||||
#define BPS_38400 2
|
||||
#define BPS_19200 5
|
||||
#define BPS_9600 11
|
||||
#define BPS_2400 47
|
||||
|
||||
/* Ring descriptor flags */
|
||||
#define AU_OWN (1<<7) /* tx,rx */
|
||||
|
||||
#define IR_DIS_CRC (1<<6) /* tx */
|
||||
#define IR_BAD_CRC (1<<5) /* tx */
|
||||
#define IR_NEED_PULSE (1<<4) /* tx */
|
||||
#define IR_FORCE_UNDER (1<<3) /* tx */
|
||||
#define IR_DISABLE_TX (1<<2) /* tx */
|
||||
#define IR_HW_UNDER (1<<0) /* tx */
|
||||
#define IR_TX_ERROR (IR_DIS_CRC|IR_BAD_CRC|IR_HW_UNDER)
|
||||
|
||||
#define IR_PHY_ERROR (1<<6) /* rx */
|
||||
#define IR_CRC_ERROR (1<<5) /* rx */
|
||||
#define IR_MAX_LEN (1<<4) /* rx */
|
||||
#define IR_FIFO_OVER (1<<3) /* rx */
|
||||
#define IR_SIR_ERROR (1<<2) /* rx */
|
||||
#define IR_RX_ERROR (IR_PHY_ERROR|IR_CRC_ERROR| \
|
||||
IR_MAX_LEN|IR_FIFO_OVER|IR_SIR_ERROR)
|
||||
|
||||
typedef struct db_dest {
|
||||
struct db_dest *pnext;
|
||||
volatile u32 *vaddr;
|
||||
dma_addr_t dma_addr;
|
||||
} db_dest_t;
|
||||
|
||||
|
||||
typedef struct ring_desc {
|
||||
u8 count_0; /* 7:0 */
|
||||
u8 count_1; /* 12:8 */
|
||||
u8 reserved;
|
||||
u8 flags;
|
||||
u8 addr_0; /* 7:0 */
|
||||
u8 addr_1; /* 15:8 */
|
||||
u8 addr_2; /* 23:16 */
|
||||
u8 addr_3; /* 31:24 */
|
||||
} ring_dest_t;
|
||||
|
||||
|
||||
/* Private data for each instance */
|
||||
struct au1k_private {
|
||||
|
||||
db_dest_t *pDBfree;
|
||||
db_dest_t db[2*NUM_IR_DESC];
|
||||
volatile ring_dest_t *rx_ring[NUM_IR_DESC];
|
||||
volatile ring_dest_t *tx_ring[NUM_IR_DESC];
|
||||
db_dest_t *rx_db_inuse[NUM_IR_DESC];
|
||||
db_dest_t *tx_db_inuse[NUM_IR_DESC];
|
||||
u32 rx_head;
|
||||
u32 tx_head;
|
||||
u32 tx_tail;
|
||||
u32 tx_full;
|
||||
|
||||
iobuff_t rx_buff;
|
||||
|
||||
struct net_device *netdev;
|
||||
struct net_device_stats stats;
|
||||
|
||||
struct timeval stamp;
|
||||
struct timeval now;
|
||||
struct qos_info qos;
|
||||
struct irlap_cb *irlap;
|
||||
|
||||
u8 open;
|
||||
u32 speed;
|
||||
u32 newspeed;
|
||||
|
||||
u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
|
||||
struct timer_list timer;
|
||||
|
||||
spinlock_t lock; /* For serializing operations */
|
||||
struct pm_dev *dev;
|
||||
};
|
||||
#endif /* AU1000_IRCC_H */
|
851
drivers/net/irda/au1k_ir.c
Arquivo normal
851
drivers/net/irda/au1k_ir.c
Arquivo normal
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
* Alchemy Semi Au1000 IrDA driver
|
||||
*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: MontaVista Software, Inc.
|
||||
* ppopov@mvista.com or source@mvista.com
|
||||
*
|
||||
* This program is free software; you can distribute it and/or modify it
|
||||
* under the terms of the GNU General Public License (Version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/au1000.h>
|
||||
#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100)
|
||||
#include <asm/pb1000.h>
|
||||
#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
|
||||
#include <asm/db1x00.h>
|
||||
#else
|
||||
#error au1k_ir: unsupported board
|
||||
#endif
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irmod.h>
|
||||
#include <net/irda/wrapper.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
#include "au1000_ircc.h"
|
||||
|
||||
static int au1k_irda_net_init(struct net_device *);
|
||||
static int au1k_irda_start(struct net_device *);
|
||||
static int au1k_irda_stop(struct net_device *dev);
|
||||
static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *);
|
||||
static int au1k_irda_rx(struct net_device *);
|
||||
static void au1k_irda_interrupt(int, void *, struct pt_regs *);
|
||||
static void au1k_tx_timeout(struct net_device *);
|
||||
static struct net_device_stats *au1k_irda_stats(struct net_device *);
|
||||
static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int);
|
||||
static int au1k_irda_set_speed(struct net_device *dev, int speed);
|
||||
|
||||
static void *dma_alloc(size_t, dma_addr_t *);
|
||||
static void dma_free(void *, size_t);
|
||||
|
||||
static int qos_mtt_bits = 0x07; /* 1 ms or more */
|
||||
static struct net_device *ir_devs[NUM_IR_IFF];
|
||||
static char version[] __devinitdata =
|
||||
"au1k_ircc:1.2 ppopov@mvista.com\n";
|
||||
|
||||
#define RUN_AT(x) (jiffies + (x))
|
||||
|
||||
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
|
||||
static BCSR * const bcsr = (BCSR *)0xAE000000;
|
||||
#endif
|
||||
|
||||
static DEFINE_SPINLOCK(ir_lock);
|
||||
|
||||
/*
|
||||
* IrDA peripheral bug. You have to read the register
|
||||
* twice to get the right value.
|
||||
*/
|
||||
u32 read_ir_reg(u32 addr)
|
||||
{
|
||||
readl(addr);
|
||||
return readl(addr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Buffer allocation/deallocation routines. The buffer descriptor returned
|
||||
* has the virtual and dma address of a buffer suitable for
|
||||
* both, receive and transmit operations.
|
||||
*/
|
||||
static db_dest_t *GetFreeDB(struct au1k_private *aup)
|
||||
{
|
||||
db_dest_t *pDB;
|
||||
pDB = aup->pDBfree;
|
||||
|
||||
if (pDB) {
|
||||
aup->pDBfree = pDB->pnext;
|
||||
}
|
||||
return pDB;
|
||||
}
|
||||
|
||||
static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB)
|
||||
{
|
||||
db_dest_t *pDBfree = aup->pDBfree;
|
||||
if (pDBfree)
|
||||
pDBfree->pnext = pDB;
|
||||
aup->pDBfree = pDB;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DMA memory allocation, derived from pci_alloc_consistent.
|
||||
However, the Au1000 data cache is coherent (when programmed
|
||||
so), therefore we return KSEG0 address, not KSEG1.
|
||||
*/
|
||||
static void *dma_alloc(size_t size, dma_addr_t * dma_handle)
|
||||
{
|
||||
void *ret;
|
||||
int gfp = GFP_ATOMIC | GFP_DMA;
|
||||
|
||||
ret = (void *) __get_free_pages(gfp, get_order(size));
|
||||
|
||||
if (ret != NULL) {
|
||||
memset(ret, 0, size);
|
||||
*dma_handle = virt_to_bus(ret);
|
||||
ret = (void *)KSEG0ADDR(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void dma_free(void *vaddr, size_t size)
|
||||
{
|
||||
vaddr = (void *)KSEG0ADDR(vaddr);
|
||||
free_pages((unsigned long) vaddr, get_order(size));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<NUM_IR_DESC; i++) {
|
||||
aup->rx_ring[i] = (volatile ring_dest_t *)
|
||||
(rx_base + sizeof(ring_dest_t)*i);
|
||||
}
|
||||
for (i=0; i<NUM_IR_DESC; i++) {
|
||||
aup->tx_ring[i] = (volatile ring_dest_t *)
|
||||
(tx_base + sizeof(ring_dest_t)*i);
|
||||
}
|
||||
}
|
||||
|
||||
static int au1k_irda_init(void)
|
||||
{
|
||||
static unsigned version_printed = 0;
|
||||
struct au1k_private *aup;
|
||||
struct net_device *dev;
|
||||
int err;
|
||||
|
||||
if (version_printed++ == 0) printk(version);
|
||||
|
||||
dev = alloc_irdadev(sizeof(struct au1k_private));
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */
|
||||
err = au1k_irda_net_init(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
err = register_netdev(dev);
|
||||
if (err)
|
||||
goto out1;
|
||||
ir_devs[0] = dev;
|
||||
printk(KERN_INFO "IrDA: Registered device %s\n", dev->name);
|
||||
return 0;
|
||||
|
||||
out1:
|
||||
aup = netdev_priv(dev);
|
||||
dma_free((void *)aup->db[0].vaddr,
|
||||
MAX_BUF_SIZE * 2*NUM_IR_DESC);
|
||||
dma_free((void *)aup->rx_ring[0],
|
||||
2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
|
||||
kfree(aup->rx_buff.head);
|
||||
out:
|
||||
free_netdev(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int au1k_irda_init_iobuf(iobuff_t *io, int size)
|
||||
{
|
||||
io->head = kmalloc(size, GFP_KERNEL);
|
||||
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 int au1k_irda_net_init(struct net_device *dev)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
int i, retval = 0, err;
|
||||
db_dest_t *pDB, *pDBfree;
|
||||
dma_addr_t temp;
|
||||
|
||||
err = au1k_irda_init_iobuf(&aup->rx_buff, 14384);
|
||||
if (err)
|
||||
goto out1;
|
||||
|
||||
dev->open = au1k_irda_start;
|
||||
dev->hard_start_xmit = au1k_irda_hard_xmit;
|
||||
dev->stop = au1k_irda_stop;
|
||||
dev->get_stats = au1k_irda_stats;
|
||||
dev->do_ioctl = au1k_irda_ioctl;
|
||||
dev->tx_timeout = au1k_tx_timeout;
|
||||
|
||||
irda_init_max_qos_capabilies(&aup->qos);
|
||||
|
||||
/* The only value we must override it the baudrate */
|
||||
aup->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
|
||||
IR_115200|IR_576000 |(IR_4000000 << 8);
|
||||
|
||||
aup->qos.min_turn_time.bits = qos_mtt_bits;
|
||||
irda_qos_bits_to_value(&aup->qos);
|
||||
|
||||
retval = -ENOMEM;
|
||||
|
||||
/* Tx ring follows rx ring + 512 bytes */
|
||||
/* we need a 1k aligned buffer */
|
||||
aup->rx_ring[0] = (ring_dest_t *)
|
||||
dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp);
|
||||
if (!aup->rx_ring[0])
|
||||
goto out2;
|
||||
|
||||
/* allocate the data buffers */
|
||||
aup->db[0].vaddr =
|
||||
(void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp);
|
||||
if (!aup->db[0].vaddr)
|
||||
goto out3;
|
||||
|
||||
setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512);
|
||||
|
||||
pDBfree = NULL;
|
||||
pDB = aup->db;
|
||||
for (i=0; i<(2*NUM_IR_DESC); i++) {
|
||||
pDB->pnext = pDBfree;
|
||||
pDBfree = pDB;
|
||||
pDB->vaddr =
|
||||
(u32 *)((unsigned)aup->db[0].vaddr + MAX_BUF_SIZE*i);
|
||||
pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr);
|
||||
pDB++;
|
||||
}
|
||||
aup->pDBfree = pDBfree;
|
||||
|
||||
/* attach a data buffer to each descriptor */
|
||||
for (i=0; i<NUM_IR_DESC; i++) {
|
||||
pDB = GetFreeDB(aup);
|
||||
if (!pDB) goto out;
|
||||
aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
|
||||
aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff);
|
||||
aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff);
|
||||
aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff);
|
||||
aup->rx_db_inuse[i] = pDB;
|
||||
}
|
||||
for (i=0; i<NUM_IR_DESC; i++) {
|
||||
pDB = GetFreeDB(aup);
|
||||
if (!pDB) goto out;
|
||||
aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff);
|
||||
aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff);
|
||||
aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff);
|
||||
aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff);
|
||||
aup->tx_ring[i]->count_0 = 0;
|
||||
aup->tx_ring[i]->count_1 = 0;
|
||||
aup->tx_ring[i]->flags = 0;
|
||||
aup->tx_db_inuse[i] = pDB;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
|
||||
/* power on */
|
||||
bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK;
|
||||
bcsr->resets |= BCSR_RESETS_IRDA_MODE_FULL;
|
||||
au_sync();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
out3:
|
||||
dma_free((void *)aup->rx_ring[0],
|
||||
2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
|
||||
out2:
|
||||
kfree(aup->rx_buff.head);
|
||||
out1:
|
||||
printk(KERN_ERR "au1k_init_module failed. Returns %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int au1k_init(struct net_device *dev)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
int i;
|
||||
u32 control;
|
||||
u32 ring_address;
|
||||
|
||||
/* bring the device out of reset */
|
||||
control = 0xe; /* coherent, clock enable, one half system clock */
|
||||
|
||||
#ifndef CONFIG_CPU_LITTLE_ENDIAN
|
||||
control |= 1;
|
||||
#endif
|
||||
aup->tx_head = 0;
|
||||
aup->tx_tail = 0;
|
||||
aup->rx_head = 0;
|
||||
|
||||
for (i=0; i<NUM_IR_DESC; i++) {
|
||||
aup->rx_ring[i]->flags = AU_OWN;
|
||||
}
|
||||
|
||||
writel(control, IR_INTERFACE_CONFIG);
|
||||
au_sync_delay(10);
|
||||
|
||||
writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); /* disable PHY */
|
||||
au_sync_delay(1);
|
||||
|
||||
writel(MAX_BUF_SIZE, IR_MAX_PKT_LEN);
|
||||
|
||||
ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]);
|
||||
writel(ring_address >> 26, IR_RING_BASE_ADDR_H);
|
||||
writel((ring_address >> 10) & 0xffff, IR_RING_BASE_ADDR_L);
|
||||
|
||||
writel(RING_SIZE_64<<8 | RING_SIZE_64<<12, IR_RING_SIZE);
|
||||
|
||||
writel(1<<2 | IR_ONE_PIN, IR_CONFIG_2); /* 48MHz */
|
||||
writel(0, IR_RING_ADDR_CMPR);
|
||||
|
||||
au1k_irda_set_speed(dev, 9600);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1k_irda_start(struct net_device *dev)
|
||||
{
|
||||
int retval;
|
||||
char hwname[32];
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
|
||||
if ((retval = au1k_init(dev))) {
|
||||
printk(KERN_ERR "%s: error in au1k_init\n", dev->name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if ((retval = request_irq(AU1000_IRDA_TX_INT, &au1k_irda_interrupt,
|
||||
0, dev->name, dev))) {
|
||||
printk(KERN_ERR "%s: unable to get IRQ %d\n",
|
||||
dev->name, dev->irq);
|
||||
return retval;
|
||||
}
|
||||
if ((retval = request_irq(AU1000_IRDA_RX_INT, &au1k_irda_interrupt,
|
||||
0, dev->name, dev))) {
|
||||
free_irq(AU1000_IRDA_TX_INT, dev);
|
||||
printk(KERN_ERR "%s: unable to get IRQ %d\n",
|
||||
dev->name, dev->irq);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Give self a hardware name */
|
||||
sprintf(hwname, "Au1000 SIR/FIR");
|
||||
aup->irlap = irlap_open(dev, &aup->qos, hwname);
|
||||
netif_start_queue(dev);
|
||||
|
||||
writel(read_ir_reg(IR_CONFIG_2) | 1<<8, IR_CONFIG_2); /* int enable */
|
||||
|
||||
aup->timer.expires = RUN_AT((3*HZ));
|
||||
aup->timer.data = (unsigned long)dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1k_irda_stop(struct net_device *dev)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
|
||||
/* disable interrupts */
|
||||
writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2);
|
||||
writel(0, IR_CONFIG_1);
|
||||
writel(0, IR_INTERFACE_CONFIG); /* disable clock */
|
||||
au_sync();
|
||||
|
||||
if (aup->irlap) {
|
||||
irlap_close(aup->irlap);
|
||||
aup->irlap = NULL;
|
||||
}
|
||||
|
||||
netif_stop_queue(dev);
|
||||
del_timer(&aup->timer);
|
||||
|
||||
/* disable the interrupt */
|
||||
free_irq(AU1000_IRDA_TX_INT, dev);
|
||||
free_irq(AU1000_IRDA_RX_INT, dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit au1k_irda_exit(void)
|
||||
{
|
||||
struct net_device *dev = ir_devs[0];
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
|
||||
unregister_netdev(dev);
|
||||
|
||||
dma_free((void *)aup->db[0].vaddr,
|
||||
MAX_BUF_SIZE * 2*NUM_IR_DESC);
|
||||
dma_free((void *)aup->rx_ring[0],
|
||||
2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t)));
|
||||
kfree(aup->rx_buff.head);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
struct net_device_stats *ps = &aup->stats;
|
||||
|
||||
ps->tx_packets++;
|
||||
ps->tx_bytes += pkt_len;
|
||||
|
||||
if (status & IR_TX_ERROR) {
|
||||
ps->tx_errors++;
|
||||
ps->tx_aborted_errors++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void au1k_tx_ack(struct net_device *dev)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
volatile ring_dest_t *ptxd;
|
||||
|
||||
ptxd = aup->tx_ring[aup->tx_tail];
|
||||
while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) {
|
||||
update_tx_stats(dev, ptxd->flags,
|
||||
ptxd->count_1<<8 | ptxd->count_0);
|
||||
ptxd->count_0 = 0;
|
||||
ptxd->count_1 = 0;
|
||||
au_sync();
|
||||
|
||||
aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1);
|
||||
ptxd = aup->tx_ring[aup->tx_tail];
|
||||
|
||||
if (aup->tx_full) {
|
||||
aup->tx_full = 0;
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
}
|
||||
|
||||
if (aup->tx_tail == aup->tx_head) {
|
||||
if (aup->newspeed) {
|
||||
au1k_irda_set_speed(dev, aup->newspeed);
|
||||
aup->newspeed = 0;
|
||||
}
|
||||
else {
|
||||
writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE,
|
||||
IR_CONFIG_1);
|
||||
au_sync();
|
||||
writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE,
|
||||
IR_CONFIG_1);
|
||||
writel(0, IR_RING_PROMPT);
|
||||
au_sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Au1000 transmit routine.
|
||||
*/
|
||||
static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
int speed = irda_get_next_speed(skb);
|
||||
volatile ring_dest_t *ptxd;
|
||||
u32 len;
|
||||
|
||||
u32 flags;
|
||||
db_dest_t *pDB;
|
||||
|
||||
if (speed != aup->speed && speed != -1) {
|
||||
aup->newspeed = speed;
|
||||
}
|
||||
|
||||
if ((skb->len == 0) && (aup->newspeed)) {
|
||||
if (aup->tx_tail == aup->tx_head) {
|
||||
au1k_irda_set_speed(dev, speed);
|
||||
aup->newspeed = 0;
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptxd = aup->tx_ring[aup->tx_head];
|
||||
flags = ptxd->flags;
|
||||
|
||||
if (flags & AU_OWN) {
|
||||
printk(KERN_DEBUG "%s: tx_full\n", dev->name);
|
||||
netif_stop_queue(dev);
|
||||
aup->tx_full = 1;
|
||||
return 1;
|
||||
}
|
||||
else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) {
|
||||
printk(KERN_DEBUG "%s: tx_full\n", dev->name);
|
||||
netif_stop_queue(dev);
|
||||
aup->tx_full = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
pDB = aup->tx_db_inuse[aup->tx_head];
|
||||
|
||||
#if 0
|
||||
if (read_ir_reg(IR_RX_BYTE_CNT) != 0) {
|
||||
printk("tx warning: rx byte cnt %x\n",
|
||||
read_ir_reg(IR_RX_BYTE_CNT));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aup->speed == 4000000) {
|
||||
/* FIR */
|
||||
memcpy((void *)pDB->vaddr, skb->data, skb->len);
|
||||
ptxd->count_0 = skb->len & 0xff;
|
||||
ptxd->count_1 = (skb->len >> 8) & 0xff;
|
||||
|
||||
}
|
||||
else {
|
||||
/* SIR */
|
||||
len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE);
|
||||
ptxd->count_0 = len & 0xff;
|
||||
ptxd->count_1 = (len >> 8) & 0xff;
|
||||
ptxd->flags |= IR_DIS_CRC;
|
||||
au_writel(au_readl(0xae00000c) & ~(1<<13), 0xae00000c);
|
||||
}
|
||||
ptxd->flags |= AU_OWN;
|
||||
au_sync();
|
||||
|
||||
writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1);
|
||||
writel(0, IR_RING_PROMPT);
|
||||
au_sync();
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);
|
||||
dev->trans_start = jiffies;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
update_rx_stats(struct net_device *dev, u32 status, u32 count)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
struct net_device_stats *ps = &aup->stats;
|
||||
|
||||
ps->rx_packets++;
|
||||
|
||||
if (status & IR_RX_ERROR) {
|
||||
ps->rx_errors++;
|
||||
if (status & (IR_PHY_ERROR|IR_FIFO_OVER))
|
||||
ps->rx_missed_errors++;
|
||||
if (status & IR_MAX_LEN)
|
||||
ps->rx_length_errors++;
|
||||
if (status & IR_CRC_ERROR)
|
||||
ps->rx_crc_errors++;
|
||||
}
|
||||
else
|
||||
ps->rx_bytes += count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Au1000 receive routine.
|
||||
*/
|
||||
static int au1k_irda_rx(struct net_device *dev)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
struct sk_buff *skb;
|
||||
volatile ring_dest_t *prxd;
|
||||
u32 flags, count;
|
||||
db_dest_t *pDB;
|
||||
|
||||
prxd = aup->rx_ring[aup->rx_head];
|
||||
flags = prxd->flags;
|
||||
|
||||
while (!(flags & AU_OWN)) {
|
||||
pDB = aup->rx_db_inuse[aup->rx_head];
|
||||
count = prxd->count_1<<8 | prxd->count_0;
|
||||
if (!(flags & IR_RX_ERROR)) {
|
||||
/* good frame */
|
||||
update_rx_stats(dev, flags, count);
|
||||
skb=alloc_skb(count+1,GFP_ATOMIC);
|
||||
if (skb == NULL) {
|
||||
aup->stats.rx_dropped++;
|
||||
continue;
|
||||
}
|
||||
skb_reserve(skb, 1);
|
||||
if (aup->speed == 4000000)
|
||||
skb_put(skb, count);
|
||||
else
|
||||
skb_put(skb, count-2);
|
||||
memcpy(skb->data, (void *)pDB->vaddr, count-2);
|
||||
skb->dev = dev;
|
||||
skb->mac.raw = skb->data;
|
||||
skb->protocol = htons(ETH_P_IRDA);
|
||||
netif_rx(skb);
|
||||
prxd->count_0 = 0;
|
||||
prxd->count_1 = 0;
|
||||
}
|
||||
prxd->flags |= AU_OWN;
|
||||
aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1);
|
||||
writel(0, IR_RING_PROMPT);
|
||||
au_sync();
|
||||
|
||||
/* next descriptor */
|
||||
prxd = aup->rx_ring[aup->rx_head];
|
||||
flags = prxd->flags;
|
||||
dev->last_rx = jiffies;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *) dev_id;
|
||||
|
||||
if (dev == NULL) {
|
||||
printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
writel(0, IR_INT_CLEAR); /* ack irda interrupts */
|
||||
|
||||
au1k_irda_rx(dev);
|
||||
au1k_tx_ack(dev);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The Tx ring has been full longer than the watchdog timeout
|
||||
* value. The transmitter must be hung?
|
||||
*/
|
||||
static void au1k_tx_timeout(struct net_device *dev)
|
||||
{
|
||||
u32 speed;
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
|
||||
printk(KERN_ERR "%s: tx timeout\n", dev->name);
|
||||
speed = aup->speed;
|
||||
aup->speed = 0;
|
||||
au1k_irda_set_speed(dev, speed);
|
||||
aup->tx_full = 0;
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the IrDA communications speed.
|
||||
*/
|
||||
static int
|
||||
au1k_irda_set_speed(struct net_device *dev, int speed)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
u32 control;
|
||||
int ret = 0, timeout = 10, i;
|
||||
volatile ring_dest_t *ptxd;
|
||||
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
|
||||
unsigned long irda_resets;
|
||||
#endif
|
||||
|
||||
if (speed == aup->speed)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&ir_lock, flags);
|
||||
|
||||
/* disable PHY first */
|
||||
writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE);
|
||||
|
||||
/* disable RX/TX */
|
||||
writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE),
|
||||
IR_CONFIG_1);
|
||||
au_sync_delay(1);
|
||||
while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) {
|
||||
mdelay(1);
|
||||
if (!timeout--) {
|
||||
printk(KERN_ERR "%s: rx/tx disable timeout\n",
|
||||
dev->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable DMA */
|
||||
writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1);
|
||||
au_sync_delay(1);
|
||||
|
||||
/*
|
||||
* After we disable tx/rx. the index pointers
|
||||
* go back to zero.
|
||||
*/
|
||||
aup->tx_head = aup->tx_tail = aup->rx_head = 0;
|
||||
for (i=0; i<NUM_IR_DESC; i++) {
|
||||
ptxd = aup->tx_ring[i];
|
||||
ptxd->flags = 0;
|
||||
ptxd->count_0 = 0;
|
||||
ptxd->count_1 = 0;
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_IR_DESC; i++) {
|
||||
ptxd = aup->rx_ring[i];
|
||||
ptxd->count_0 = 0;
|
||||
ptxd->count_1 = 0;
|
||||
ptxd->flags = AU_OWN;
|
||||
}
|
||||
|
||||
if (speed == 4000000) {
|
||||
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
|
||||
bcsr->resets |= BCSR_RESETS_FIR_SEL;
|
||||
#else /* Pb1000 and Pb1100 */
|
||||
writel(1<<13, CPLD_AUX1);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
|
||||
bcsr->resets &= ~BCSR_RESETS_FIR_SEL;
|
||||
#else /* Pb1000 and Pb1100 */
|
||||
writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1);
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (speed) {
|
||||
case 9600:
|
||||
writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG);
|
||||
writel(IR_SIR_MODE, IR_CONFIG_1);
|
||||
break;
|
||||
case 19200:
|
||||
writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG);
|
||||
writel(IR_SIR_MODE, IR_CONFIG_1);
|
||||
break;
|
||||
case 38400:
|
||||
writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG);
|
||||
writel(IR_SIR_MODE, IR_CONFIG_1);
|
||||
break;
|
||||
case 57600:
|
||||
writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG);
|
||||
writel(IR_SIR_MODE, IR_CONFIG_1);
|
||||
break;
|
||||
case 115200:
|
||||
writel(12<<5, IR_WRITE_PHY_CONFIG);
|
||||
writel(IR_SIR_MODE, IR_CONFIG_1);
|
||||
break;
|
||||
case 4000000:
|
||||
writel(0xF, IR_WRITE_PHY_CONFIG);
|
||||
writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
aup->speed = speed;
|
||||
writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE);
|
||||
au_sync();
|
||||
|
||||
control = read_ir_reg(IR_ENABLE);
|
||||
writel(0, IR_RING_PROMPT);
|
||||
au_sync();
|
||||
|
||||
if (control & (1<<14)) {
|
||||
printk(KERN_ERR "%s: configuration error\n", dev->name);
|
||||
}
|
||||
else {
|
||||
if (control & (1<<11))
|
||||
printk(KERN_DEBUG "%s Valid SIR config\n", dev->name);
|
||||
if (control & (1<<12))
|
||||
printk(KERN_DEBUG "%s Valid MIR config\n", dev->name);
|
||||
if (control & (1<<13))
|
||||
printk(KERN_DEBUG "%s Valid FIR config\n", dev->name);
|
||||
if (control & (1<<10))
|
||||
printk(KERN_DEBUG "%s TX enabled\n", dev->name);
|
||||
if (control & (1<<9))
|
||||
printk(KERN_DEBUG "%s RX enabled\n", dev->name);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ir_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
|
||||
{
|
||||
struct if_irda_req *rq = (struct if_irda_req *)ifreq;
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCSBANDWIDTH:
|
||||
if (capable(CAP_NET_ADMIN)) {
|
||||
/*
|
||||
* We are unable to set the speed if the
|
||||
* device is not running.
|
||||
*/
|
||||
if (aup->open)
|
||||
ret = au1k_irda_set_speed(dev,
|
||||
rq->ifr_baudrate);
|
||||
else {
|
||||
printk(KERN_ERR "%s ioctl: !netif_running\n",
|
||||
dev->name);
|
||||
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 = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct net_device_stats *au1k_irda_stats(struct net_device *dev)
|
||||
{
|
||||
struct au1k_private *aup = netdev_priv(dev);
|
||||
return &aup->stats;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
|
||||
MODULE_DESCRIPTION("Au1000 IrDA Device Driver");
|
||||
|
||||
module_init(au1k_irda_init);
|
||||
module_exit(au1k_irda_exit);
|
1789
drivers/net/irda/donauboe.c
Arquivo normal
1789
drivers/net/irda/donauboe.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
363
drivers/net/irda/donauboe.h
Arquivo normal
363
drivers/net/irda/donauboe.h
Arquivo normal
@@ -0,0 +1,363 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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 controler 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 resemblence */
|
||||
/* to the IrDA controller in the Toshiba RISC TMPR3922 chip */
|
||||
/* the documentation for this is freely available at */
|
||||
/* http://www.toshiba.com/taec/components/Generic/TMPR3922.shtml */
|
||||
/* 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 writting 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 */
|
||||
}
|
||||
__attribute__ ((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 net_device_stats stats;
|
||||
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
|
122
drivers/net/irda/ep7211_ir.c
Arquivo normal
122
drivers/net/irda/ep7211_ir.c
Arquivo normal
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* IR port driver for the Cirrus Logic EP7211 processor.
|
||||
*
|
||||
* Copyright 2001, Blue Mug Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/hardware.h>
|
||||
|
||||
#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
|
||||
#define MAX_DELAY 10000 /* 1 ms */
|
||||
|
||||
static void ep7211_ir_open(dongle_t *self, struct qos_info *qos);
|
||||
static void ep7211_ir_close(dongle_t *self);
|
||||
static int ep7211_ir_change_speed(struct irda_task *task);
|
||||
static int ep7211_ir_reset(struct irda_task *task);
|
||||
|
||||
static struct dongle_reg dongle = {
|
||||
.type = IRDA_EP7211_IR,
|
||||
.open = ep7211_ir_open,
|
||||
.close = ep7211_ir_close,
|
||||
.reset = ep7211_ir_reset,
|
||||
.change_speed = ep7211_ir_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void ep7211_ir_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
unsigned int syscon1, flags;
|
||||
|
||||
save_flags(flags); cli();
|
||||
|
||||
/* Turn on the SIR encoder. */
|
||||
syscon1 = clps_readl(SYSCON1);
|
||||
syscon1 |= SYSCON1_SIREN;
|
||||
clps_writel(syscon1, SYSCON1);
|
||||
|
||||
/* XXX: We should disable modem status interrupts on the first
|
||||
UART (interrupt #14). */
|
||||
|
||||
restore_flags(flags);
|
||||
}
|
||||
|
||||
static void ep7211_ir_close(dongle_t *self)
|
||||
{
|
||||
unsigned int syscon1, flags;
|
||||
|
||||
save_flags(flags); cli();
|
||||
|
||||
/* Turn off the SIR encoder. */
|
||||
syscon1 = clps_readl(SYSCON1);
|
||||
syscon1 &= ~SYSCON1_SIREN;
|
||||
clps_writel(syscon1, SYSCON1);
|
||||
|
||||
/* XXX: If we've disabled the modem status interrupts, we should
|
||||
reset them back to their original state. */
|
||||
|
||||
restore_flags(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function ep7211_ir_change_speed (task)
|
||||
*
|
||||
* Change speed of the EP7211 I/R port. We don't really have to do anything
|
||||
* for the EP7211 as long as the rate is being changed at the serial port
|
||||
* level.
|
||||
*/
|
||||
static int ep7211_ir_change_speed(struct irda_task *task)
|
||||
{
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function ep7211_ir_reset (task)
|
||||
*
|
||||
* Reset the EP7211 I/R. We don't really have to do anything.
|
||||
*
|
||||
*/
|
||||
static int ep7211_ir_reset(struct irda_task *task)
|
||||
{
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function ep7211_ir_init(void)
|
||||
*
|
||||
* Initialize EP7211 I/R module
|
||||
*
|
||||
*/
|
||||
static int __init ep7211_ir_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function ep7211_ir_cleanup(void)
|
||||
*
|
||||
* Cleanup EP7211 I/R module
|
||||
*
|
||||
*/
|
||||
static void __exit ep7211_ir_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jon McClintock <jonm@bluemug.com>");
|
||||
MODULE_DESCRIPTION("EP7211 I/R driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("irda-dongle-8"); /* IRDA_EP7211_IR */
|
||||
|
||||
module_init(ep7211_ir_init);
|
||||
module_exit(ep7211_ir_cleanup);
|
159
drivers/net/irda/esi-sir.c
Arquivo normal
159
drivers/net/irda/esi-sir.c
Arquivo normal
@@ -0,0 +1,159 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Filename: esi.c
|
||||
* Version: 1.6
|
||||
* Description: Driver for the Extended Systems JetEye PC dongle
|
||||
* Status: Experimental.
|
||||
* Author: Dag Brattli <dagb@cs.uit.no>
|
||||
* Created at: Sat Feb 21 18:54:38 1998
|
||||
* Modified at: Sun Oct 27 22:01:04 2002
|
||||
* Modified by: Martin Diehl <mad@mdiehl.de>
|
||||
*
|
||||
* Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>,
|
||||
* Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
|
||||
* Copyright (c) 2002 Martin Diehl, <mad@mdiehl.de>,
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
|
||||
#include "sir-dev.h"
|
||||
|
||||
static int esi_open(struct sir_dev *);
|
||||
static int esi_close(struct sir_dev *);
|
||||
static int esi_change_speed(struct sir_dev *, unsigned);
|
||||
static int esi_reset(struct sir_dev *);
|
||||
|
||||
static struct dongle_driver esi = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "JetEye PC ESI-9680 PC",
|
||||
.type = IRDA_ESI_DONGLE,
|
||||
.open = esi_open,
|
||||
.close = esi_close,
|
||||
.reset = esi_reset,
|
||||
.set_speed = esi_change_speed,
|
||||
};
|
||||
|
||||
static int __init esi_sir_init(void)
|
||||
{
|
||||
return irda_register_dongle(&esi);
|
||||
}
|
||||
|
||||
static void __exit esi_sir_cleanup(void)
|
||||
{
|
||||
irda_unregister_dongle(&esi);
|
||||
}
|
||||
|
||||
static int esi_open(struct sir_dev *dev)
|
||||
{
|
||||
struct qos_info *qos = &dev->qos;
|
||||
|
||||
/* 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);
|
||||
|
149
drivers/net/irda/esi.c
Arquivo normal
149
drivers/net/irda/esi.c
Arquivo normal
@@ -0,0 +1,149 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Filename: esi.c
|
||||
* Version: 1.5
|
||||
* 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: Fri Dec 17 09:14:04 1999
|
||||
* Modified by: Dag Brattli <dagb@cs.uit.no>
|
||||
*
|
||||
* Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>,
|
||||
* Copyright (c) 1998 Thomas Davis, <ratbert@radiks.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
static void esi_open(dongle_t *self, struct qos_info *qos);
|
||||
static void esi_close(dongle_t *self);
|
||||
static int esi_change_speed(struct irda_task *task);
|
||||
static int esi_reset(struct irda_task *task);
|
||||
|
||||
static struct dongle_reg dongle = {
|
||||
.type = IRDA_ESI_DONGLE,
|
||||
.open = esi_open,
|
||||
.close = esi_close,
|
||||
.reset = esi_reset,
|
||||
.change_speed = esi_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init esi_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit esi_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void esi_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
|
||||
qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
|
||||
}
|
||||
|
||||
static void esi_close(dongle_t *dongle)
|
||||
{
|
||||
/* Power off dongle */
|
||||
dongle->set_dtr_rts(dongle->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function esi_change_speed (task)
|
||||
*
|
||||
* Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle
|
||||
*
|
||||
*/
|
||||
static int esi_change_speed(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param;
|
||||
int dtr, rts;
|
||||
|
||||
switch (speed) {
|
||||
case 19200:
|
||||
dtr = TRUE;
|
||||
rts = FALSE;
|
||||
break;
|
||||
case 115200:
|
||||
dtr = rts = TRUE;
|
||||
break;
|
||||
case 9600:
|
||||
default:
|
||||
dtr = FALSE;
|
||||
rts = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Change speed of dongle */
|
||||
self->set_dtr_rts(self->dev, dtr, rts);
|
||||
self->speed = speed;
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function esi_reset (task)
|
||||
*
|
||||
* Reset dongle;
|
||||
*
|
||||
*/
|
||||
static int esi_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize ESI module
|
||||
*
|
||||
*/
|
||||
module_init(esi_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup ESI module
|
||||
*
|
||||
*/
|
||||
module_exit(esi_cleanup);
|
||||
|
258
drivers/net/irda/girbil-sir.c
Arquivo normal
258
drivers/net/irda/girbil-sir.c
Arquivo normal
@@ -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<6D> 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 emmited 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__, 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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__, 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);
|
250
drivers/net/irda/girbil.c
Arquivo normal
250
drivers/net/irda/girbil.c
Arquivo normal
@@ -0,0 +1,250 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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<6D> 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/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
static int girbil_reset(struct irda_task *task);
|
||||
static void girbil_open(dongle_t *self, struct qos_info *qos);
|
||||
static void girbil_close(dongle_t *self);
|
||||
static int girbil_change_speed(struct irda_task *task);
|
||||
|
||||
/* Control register 1 */
|
||||
#define GIRBIL_TXEN 0x01 /* Enable transmitter */
|
||||
#define GIRBIL_RXEN 0x02 /* Enable receiver */
|
||||
#define GIRBIL_ECAN 0x04 /* Cancel self emmited 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_reg dongle = {
|
||||
.type = IRDA_GIRBIL_DONGLE,
|
||||
.open = girbil_open,
|
||||
.close = girbil_close,
|
||||
.reset = girbil_reset,
|
||||
.change_speed = girbil_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init girbil_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit girbil_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void girbil_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
|
||||
qos->min_turn_time.bits = 0x03;
|
||||
}
|
||||
|
||||
static void girbil_close(dongle_t *self)
|
||||
{
|
||||
/* Power off dongle */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function girbil_change_speed (dev, speed)
|
||||
*
|
||||
* Set the speed for the Girbil type dongle.
|
||||
*
|
||||
*/
|
||||
static int girbil_change_speed(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param;
|
||||
__u8 control[2];
|
||||
int ret = 0;
|
||||
|
||||
self->speed_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
/* Need to reset the dongle and go to 9600 bps before
|
||||
programming */
|
||||
if (irda_task_execute(self, girbil_reset, NULL, task,
|
||||
(void *) speed))
|
||||
{
|
||||
/* Dongle need more time to reset */
|
||||
irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
|
||||
|
||||
/* Give reset 1 sec to finish */
|
||||
ret = msecs_to_jiffies(1000);
|
||||
}
|
||||
break;
|
||||
case IRDA_TASK_CHILD_WAIT:
|
||||
IRDA_WARNING("%s(), resetting dongle timed out!\n",
|
||||
__FUNCTION__);
|
||||
ret = -1;
|
||||
break;
|
||||
case IRDA_TASK_CHILD_DONE:
|
||||
/* Set DTR and Clear RTS to enter command mode */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
|
||||
switch (speed) {
|
||||
case 9600:
|
||||
default:
|
||||
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 */
|
||||
self->write(self->dev, control, 2);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT);
|
||||
ret = msecs_to_jiffies(100);
|
||||
break;
|
||||
case IRDA_TASK_WAIT:
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function girbil_reset (driver)
|
||||
*
|
||||
* This function resets the girbil dongle.
|
||||
*
|
||||
* Algorithm:
|
||||
* 0. set RTS, and wait at least 5 ms
|
||||
* 1. clear RTS
|
||||
*/
|
||||
static int girbil_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
|
||||
int ret = 0;
|
||||
|
||||
self->reset_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
/* Reset dongle */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT1);
|
||||
/* Sleep at least 5 ms */
|
||||
ret = msecs_to_jiffies(20);
|
||||
break;
|
||||
case IRDA_TASK_WAIT1:
|
||||
/* Set DTR and clear RTS to enter command mode */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT2);
|
||||
ret = msecs_to_jiffies(20);
|
||||
break;
|
||||
case IRDA_TASK_WAIT2:
|
||||
/* Write control byte */
|
||||
self->write(self->dev, &control, 1);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT3);
|
||||
ret = msecs_to_jiffies(20);
|
||||
break;
|
||||
case IRDA_TASK_WAIT3:
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return 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 */
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize Girbil module
|
||||
*
|
||||
*/
|
||||
module_init(girbil_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup Girbil module
|
||||
*
|
||||
*/
|
||||
module_exit(girbil_cleanup);
|
||||
|
1602
drivers/net/irda/irda-usb.c
Arquivo normal
1602
drivers/net/irda/irda-usb.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
163
drivers/net/irda/irda-usb.h
Arquivo normal
163
drivers/net/irda/irda-usb.h
Arquivo normal
@@ -0,0 +1,163 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Filename: irda-usb.h
|
||||
* Version: 0.9b
|
||||
* 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>
|
||||
*
|
||||
* 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
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* USB class definitions */
|
||||
#define USB_IRDA_HEADER 0x01
|
||||
#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
|
||||
#define USB_DT_IRDA 0x21
|
||||
|
||||
struct irda_class_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u16 bcdSpecRevision;
|
||||
__u8 bmDataSize;
|
||||
__u8 bmWindowSize;
|
||||
__u8 bmMinTurnaroundTime;
|
||||
__u16 wBaudRate;
|
||||
__u8 bmAdditionalBOFs;
|
||||
__u8 bIrdaRateSniff;
|
||||
__u8 bMaxUnicastList;
|
||||
} __attribute__ ((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
|
||||
|
||||
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 */
|
||||
|
||||
wait_queue_head_t wait_q; /* for timeouts */
|
||||
|
||||
struct urb *rx_urb[IU_MAX_RX_URBS]; /* 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 net_device_stats stats;
|
||||
struct irlap_cb *irlap; /* The link layer we are binded to */
|
||||
struct qos_info qos;
|
||||
hashbin_t *tx_list; /* Queued transmit skb's */
|
||||
char *speed_buff; /* Buffer for speed changes */
|
||||
|
||||
struct timeval stamp;
|
||||
struct timeval now;
|
||||
|
||||
spinlock_t lock; /* For serializing 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 */
|
||||
};
|
||||
|
1146
drivers/net/irda/irport.c
Arquivo normal
1146
drivers/net/irda/irport.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
80
drivers/net/irda/irport.h
Arquivo normal
80
drivers/net/irda/irport.h
Arquivo normal
@@ -0,0 +1,80 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Filename: irport.h
|
||||
* Version: 0.1
|
||||
* Description: Serial driver for IrDA
|
||||
* Status: Experimental.
|
||||
* Author: Dag Brattli <dagb@cs.uit.no>
|
||||
* Created at: Sun Aug 3 13:49:59 1997
|
||||
* Modified at: Fri Jan 14 10:21:10 2000
|
||||
* Modified by: Dag Brattli <dagb@cs.uit.no>
|
||||
*
|
||||
* Copyright (c) 1997, 1998-2000 Dag Brattli <dagb@cs.uit.no>
|
||||
* 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<6D> admit liability nor
|
||||
* provide warranty for any of this software. This material is
|
||||
* provided "AS-IS" and at no charge.
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#ifndef IRPORT_H
|
||||
#define IRPORT_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
#define SPEED_DEFAULT 9600
|
||||
#define SPEED_MAX 115200
|
||||
|
||||
/*
|
||||
* These are the supported serial types.
|
||||
*/
|
||||
#define PORT_UNKNOWN 0
|
||||
#define PORT_8250 1
|
||||
#define PORT_16450 2
|
||||
#define PORT_16550 3
|
||||
#define PORT_16550A 4
|
||||
#define PORT_CIRRUS 5
|
||||
#define PORT_16650 6
|
||||
#define PORT_MAX 6
|
||||
|
||||
#define FRAME_MAX_SIZE 2048
|
||||
|
||||
struct irport_cb {
|
||||
struct net_device *netdev; /* Yes! we are some kind of netdevice */
|
||||
struct net_device_stats stats;
|
||||
|
||||
struct irlap_cb *irlap; /* The link layer we are attached to */
|
||||
|
||||
chipio_t io; /* IrDA controller information */
|
||||
iobuff_t tx_buff; /* Transmit buffer */
|
||||
iobuff_t rx_buff; /* Receive buffer */
|
||||
|
||||
struct qos_info qos; /* QoS capabilities for this device */
|
||||
dongle_t *dongle; /* Dongle driver */
|
||||
|
||||
__u32 flags; /* Interface flags */
|
||||
__u32 new_speed;
|
||||
int mode;
|
||||
int index; /* Instance index */
|
||||
int transmitting; /* Are we transmitting ? */
|
||||
|
||||
spinlock_t lock; /* For serializing operations */
|
||||
|
||||
/* For piggyback drivers */
|
||||
void *priv;
|
||||
void (*change_speed)(void *priv, __u32 speed);
|
||||
int (*interrupt)(int irq, void *dev_id, struct pt_regs *regs);
|
||||
};
|
||||
|
||||
#endif /* IRPORT_H */
|
642
drivers/net/irda/irtty-sir.c
Arquivo normal
642
drivers/net/irda/irtty-sir.c
Arquivo normal
@@ -0,0 +1,642 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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<6D> 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/tty.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/delay.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 priv->tty->driver->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->driver->wait_until_sent) {
|
||||
lock_kernel();
|
||||
tty->driver->wait_until_sent(tty, msecs_to_jiffies(100));
|
||||
unlock_kernel();
|
||||
}
|
||||
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 termios old_termios;
|
||||
int cflag;
|
||||
|
||||
IRDA_ASSERT(priv != NULL, return -1;);
|
||||
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
|
||||
|
||||
tty = priv->tty;
|
||||
|
||||
lock_kernel();
|
||||
old_termios = *(tty->termios);
|
||||
cflag = tty->termios->c_cflag;
|
||||
|
||||
cflag &= ~CBAUD;
|
||||
|
||||
IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
|
||||
|
||||
switch (speed) {
|
||||
case 1200:
|
||||
cflag |= B1200;
|
||||
break;
|
||||
case 2400:
|
||||
cflag |= B2400;
|
||||
break;
|
||||
case 4800:
|
||||
cflag |= B4800;
|
||||
break;
|
||||
case 19200:
|
||||
cflag |= B19200;
|
||||
break;
|
||||
case 38400:
|
||||
cflag |= B38400;
|
||||
break;
|
||||
case 57600:
|
||||
cflag |= B57600;
|
||||
break;
|
||||
case 115200:
|
||||
cflag |= B115200;
|
||||
break;
|
||||
case 9600:
|
||||
default:
|
||||
cflag |= B9600;
|
||||
break;
|
||||
}
|
||||
|
||||
tty->termios->c_cflag = cflag;
|
||||
if (tty->driver->set_termios)
|
||||
tty->driver->set_termios(tty, &old_termios);
|
||||
unlock_kernel();
|
||||
|
||||
priv->io.speed = speed;
|
||||
|
||||
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->driver->tiocmset != NULL, return -1;);
|
||||
priv->tty->driver->tiocmset(priv->tty, NULL, 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->driver->write)
|
||||
return 0;
|
||||
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
|
||||
if (tty->driver->write_room) {
|
||||
writelen = tty->driver->write_room(tty);
|
||||
if (writelen > len)
|
||||
writelen = len;
|
||||
}
|
||||
else
|
||||
writelen = len;
|
||||
return tty->driver->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->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", __FUNCTION__);
|
||||
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_receive_room (tty)
|
||||
*
|
||||
* Used by the TTY to find out how much data we can receive at a time
|
||||
*
|
||||
*/
|
||||
static int irtty_receive_room(struct tty_struct *tty)
|
||||
{
|
||||
struct sirtty_cb *priv = tty->disc_data;
|
||||
|
||||
IRDA_ASSERT(priv != NULL, return 0;);
|
||||
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return 0;);
|
||||
|
||||
return 65536; /* We can handle an infinite amount of data. :-) */
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;);
|
||||
|
||||
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
|
||||
|
||||
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 termios old_termios;
|
||||
int cflag;
|
||||
|
||||
lock_kernel();
|
||||
old_termios = *(tty->termios);
|
||||
cflag = tty->termios->c_cflag;
|
||||
|
||||
if (stop)
|
||||
cflag &= ~CREAD;
|
||||
else
|
||||
cflag |= CREAD;
|
||||
|
||||
tty->termios->c_cflag = cflag;
|
||||
if (tty->driver->set_termios)
|
||||
tty->driver->set_termios(tty, &old_termios);
|
||||
unlock_kernel();
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
|
||||
/* serialize ldisc open/close with sir_dev */
|
||||
static DECLARE_MUTEX(irtty_sem);
|
||||
|
||||
/* 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 */
|
||||
down(&irtty_sem);
|
||||
|
||||
priv = dev->priv;
|
||||
if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
|
||||
up(&irtty_sem);
|
||||
return -ESTALE;
|
||||
}
|
||||
|
||||
tty = priv->tty;
|
||||
|
||||
if (tty->driver->start)
|
||||
tty->driver->start(tty);
|
||||
/* Make sure we can receive more data */
|
||||
irtty_stop_receiver(tty, FALSE);
|
||||
|
||||
up(&irtty_sem);
|
||||
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 */
|
||||
down(&irtty_sem);
|
||||
|
||||
priv = dev->priv;
|
||||
if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
|
||||
up(&irtty_sem);
|
||||
return -ESTALE;
|
||||
}
|
||||
|
||||
tty = priv->tty;
|
||||
|
||||
/* Make sure we don't receive more data */
|
||||
irtty_stop_receiver(tty, TRUE);
|
||||
if (tty->driver->stop)
|
||||
tty->driver->stop(tty);
|
||||
|
||||
up(&irtty_sem);
|
||||
|
||||
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", __FUNCTION__, cmd);
|
||||
|
||||
dev = priv->dev;
|
||||
IRDA_ASSERT(dev != NULL, return -1;);
|
||||
|
||||
switch (cmd) {
|
||||
case TCGETS:
|
||||
case TCGETA:
|
||||
err = n_tty_ioctl(tty, file, cmd, arg);
|
||||
break;
|
||||
|
||||
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 = -ENOIOCTLCMD;
|
||||
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->driver->stop)
|
||||
tty->driver->stop(tty);
|
||||
|
||||
if (tty->driver->flush_buffer)
|
||||
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 = kmalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
goto out_put;
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
priv->magic = IRTTY_MAGIC;
|
||||
priv->tty = tty;
|
||||
priv->dev = dev;
|
||||
|
||||
/* serialize with start_dev - in case we were racing with ifup */
|
||||
down(&irtty_sem);
|
||||
|
||||
dev->priv = priv;
|
||||
tty->disc_data = priv;
|
||||
|
||||
up(&irtty_sem);
|
||||
|
||||
IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, 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 */
|
||||
irtty_stop_receiver(tty, TRUE);
|
||||
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
|
||||
if (tty->driver->stop)
|
||||
tty->driver->stop(tty);
|
||||
|
||||
kfree(priv);
|
||||
|
||||
IRDA_DEBUG(0, "%s - %s: irda line discipline closed\n", __FUNCTION__, tty->name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------- */
|
||||
|
||||
static struct tty_ldisc 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,
|
||||
.receive_room = irtty_receive_room,
|
||||
.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_register_ldisc(N_IRDA, NULL))) {
|
||||
IRDA_ERROR("%s(), can't unregister line discipline (err = %d)\n",
|
||||
__FUNCTION__, 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");
|
||||
|
34
drivers/net/irda/irtty-sir.h
Arquivo normal
34
drivers/net/irda/irtty-sir.h
Arquivo normal
@@ -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
|
209
drivers/net/irda/litelink-sir.c
Arquivo normal
209
drivers/net/irda/litelink-sir.c
Arquivo normal
@@ -0,0 +1,209 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
/*
|
||||
* 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
/* 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);
|
179
drivers/net/irda/litelink.c
Arquivo normal
179
drivers/net/irda/litelink.c
Arquivo normal
@@ -0,0 +1,179 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
|
||||
#define MAX_DELAY 10000 /* 1 ms */
|
||||
|
||||
static void litelink_open(dongle_t *self, struct qos_info *qos);
|
||||
static void litelink_close(dongle_t *self);
|
||||
static int litelink_change_speed(struct irda_task *task);
|
||||
static int litelink_reset(struct irda_task *task);
|
||||
|
||||
/* These are the baudrates supported */
|
||||
static __u32 baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
|
||||
|
||||
static struct dongle_reg dongle = {
|
||||
.type = IRDA_LITELINK_DONGLE,
|
||||
.open = litelink_open,
|
||||
.close = litelink_close,
|
||||
.reset = litelink_reset,
|
||||
.change_speed = litelink_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init litelink_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit litelink_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void litelink_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
|
||||
qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
|
||||
}
|
||||
|
||||
static void litelink_close(dongle_t *self)
|
||||
{
|
||||
/* Power off dongle */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param;
|
||||
int i;
|
||||
|
||||
/* Clear RTS to reset dongle */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Cycle through avaiable baudrates until we reach the correct one */
|
||||
for (i=0; i<5 && baud_rates[i] != speed; i++) {
|
||||
/* Set DTR, clear RTS */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Set DTR, Set RTS */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
}
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function litelink_reset (task)
|
||||
*
|
||||
* Reset the Litelink type dongle.
|
||||
*
|
||||
*/
|
||||
static int litelink_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
|
||||
/* Power on dongle */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Clear RTS to reset dongle */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* This dongles speed defaults to 115200 bps */
|
||||
self->speed = 115200;
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
|
||||
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_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup Litelink module
|
||||
*
|
||||
*/
|
||||
module_exit(litelink_cleanup);
|
264
drivers/net/irda/ma600-sir.c
Arquivo normal
264
drivers/net/irda/ma600-sir.c
Arquivo normal
@@ -0,0 +1,264 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.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", __FUNCTION__);
|
||||
return irda_register_dongle(&ma600);
|
||||
}
|
||||
|
||||
static void __exit ma600_sir_cleanup(void)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__,
|
||||
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",
|
||||
__FUNCTION__, (unsigned) byte,
|
||||
(unsigned) get_control_byte(speed));
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
IRDA_DEBUG(2, "%s() control byte write read OK\n", __FUNCTION__);
|
||||
#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
|
||||
*/
|
||||
|
||||
int ma600_reset(struct sir_dev *dev)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
|
||||
/* 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);
|
||||
|
354
drivers/net/irda/ma600.c
Arquivo normal
354
drivers/net/irda/ma600.c
Arquivo normal
@@ -0,0 +1,354 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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:
|
||||
* Modified by:
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
/* define this macro for release version */
|
||||
//#define NDEBUG
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#undef IRDA_DEBUG
|
||||
#define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args))
|
||||
|
||||
#undef ASSERT
|
||||
#define ASSERT(expr, func) \
|
||||
if(!(expr)) { \
|
||||
printk( "Assertion failed! %s,%s,%s,line=%d\n",\
|
||||
#expr,__FILE__,__FUNCTION__,__LINE__); \
|
||||
func}
|
||||
#endif
|
||||
|
||||
/* convert hex value to ascii hex */
|
||||
static const char hexTbl[] = "0123456789ABCDEF";
|
||||
|
||||
|
||||
static void ma600_open(dongle_t *self, struct qos_info *qos);
|
||||
static void ma600_close(dongle_t *self);
|
||||
static int ma600_change_speed(struct irda_task *task);
|
||||
static int ma600_reset(struct irda_task *task);
|
||||
|
||||
/* 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_reg dongle = {
|
||||
.type = IRDA_MA600_DONGLE,
|
||||
.open = ma600_open,
|
||||
.close = ma600_close,
|
||||
.reset = ma600_reset,
|
||||
.change_speed = ma600_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init ma600_init(void)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit ma600_cleanup(void)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
/*
|
||||
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 void ma600_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
|
||||
qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400
|
||||
|IR_57600|IR_115200;
|
||||
qos->min_turn_time.bits = 0x01; /* Needs at least 1 ms */
|
||||
irda_qos_bits_to_value(qos);
|
||||
|
||||
//self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
// should wait 1 second
|
||||
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
// should wait 1 second
|
||||
}
|
||||
|
||||
static void ma600_close(dongle_t *self)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
|
||||
/* Power off dongle */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
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, state, speed)
|
||||
*
|
||||
* Set the speed for the MA600 type dongle. Warning, this
|
||||
* function must be called with a process context!
|
||||
*
|
||||
* Algorithm
|
||||
* 1. Reset
|
||||
* 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
|
||||
*/
|
||||
static int ma600_change_speed(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param;
|
||||
static __u8 byte;
|
||||
__u8 byte_echo;
|
||||
int ret = 0;
|
||||
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
|
||||
ASSERT(task != NULL, return -1;);
|
||||
|
||||
if (self->speed_task && self->speed_task != task) {
|
||||
IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
|
||||
return msecs_to_jiffies(10);
|
||||
} else {
|
||||
self->speed_task = task;
|
||||
}
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
case IRDA_TASK_CHILD_INIT:
|
||||
/*
|
||||
* Need to reset the dongle and go to 9600 bps before
|
||||
* programming
|
||||
*/
|
||||
if (irda_task_execute(self, ma600_reset, NULL, task,
|
||||
(void *) speed)) {
|
||||
/* Dongle need more time to reset */
|
||||
irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
|
||||
|
||||
/* give 1 second to finish */
|
||||
ret = msecs_to_jiffies(1000);
|
||||
} else {
|
||||
irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
|
||||
}
|
||||
break;
|
||||
|
||||
case IRDA_TASK_CHILD_WAIT:
|
||||
IRDA_WARNING("%s(), resetting dongle timed out!\n",
|
||||
__FUNCTION__);
|
||||
ret = -1;
|
||||
break;
|
||||
|
||||
case IRDA_TASK_CHILD_DONE:
|
||||
/* Set DTR, Clear RTS */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
|
||||
ret = msecs_to_jiffies(1); /* Sleep 1 ms */
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT);
|
||||
break;
|
||||
|
||||
case IRDA_TASK_WAIT:
|
||||
speed = (__u32) task->param;
|
||||
byte = get_control_byte(speed);
|
||||
|
||||
/* Write control byte */
|
||||
self->write(self->dev, &byte, sizeof(byte));
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT1);
|
||||
|
||||
/* Wait at least 10 ms */
|
||||
ret = msecs_to_jiffies(15);
|
||||
break;
|
||||
|
||||
case IRDA_TASK_WAIT1:
|
||||
/* Read control byte echo */
|
||||
self->read(self->dev, &byte_echo, sizeof(byte_echo));
|
||||
|
||||
if(byte != byte_echo) {
|
||||
/* if control byte != echo, I don't know what to do */
|
||||
printk(KERN_WARNING "%s() control byte written != read!\n", __FUNCTION__);
|
||||
printk(KERN_WARNING "control byte = 0x%c%c\n",
|
||||
hexTbl[(byte>>4)&0x0f], hexTbl[byte&0x0f]);
|
||||
printk(KERN_WARNING "byte echo = 0x%c%c\n",
|
||||
hexTbl[(byte_echo>>4) & 0x0f],
|
||||
hexTbl[byte_echo & 0x0f]);
|
||||
#ifndef NDEBUG
|
||||
} else {
|
||||
IRDA_DEBUG(2, "%s() control byte write read OK\n", __FUNCTION__);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set DTR, Set RTS */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT2);
|
||||
|
||||
/* Wait at least 10 ms */
|
||||
ret = msecs_to_jiffies(10);
|
||||
break;
|
||||
|
||||
case IRDA_TASK_WAIT2:
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function ma600_reset (driver)
|
||||
*
|
||||
* This function resets the ma600 dongle. Warning, this function
|
||||
* must be called with a process context!!
|
||||
*
|
||||
* Algorithm:
|
||||
* 0. DTR=0, RTS=1 and wait 10 ms
|
||||
* 1. DTR=1, RTS=1 and wait 10 ms
|
||||
* 2. 9600 bps now
|
||||
*/
|
||||
int ma600_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
int ret = 0;
|
||||
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
|
||||
|
||||
ASSERT(task != NULL, return -1;);
|
||||
|
||||
if (self->reset_task && self->reset_task != task) {
|
||||
IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
|
||||
return msecs_to_jiffies(10);
|
||||
} else
|
||||
self->reset_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
/* Clear DTR and Set RTS */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT1);
|
||||
ret = msecs_to_jiffies(10); /* Sleep 10 ms */
|
||||
break;
|
||||
case IRDA_TASK_WAIT1:
|
||||
/* Set DTR and RTS */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT2);
|
||||
ret = msecs_to_jiffies(10); /* Sleep 10 ms */
|
||||
break;
|
||||
case IRDA_TASK_WAIT2:
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize MA600 module
|
||||
*
|
||||
*/
|
||||
module_init(ma600_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup MA600 module
|
||||
*
|
||||
*/
|
||||
module_exit(ma600_cleanup);
|
||||
|
230
drivers/net/irda/mcp2120-sir.c
Arquivo normal
230
drivers/net/irda/mcp2120-sir.c
Arquivo normal
@@ -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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__, 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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__, 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);
|
240
drivers/net/irda/mcp2120.c
Arquivo normal
240
drivers/net/irda/mcp2120.c
Arquivo normal
@@ -0,0 +1,240 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
*
|
||||
* 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/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
static int mcp2120_reset(struct irda_task *task);
|
||||
static void mcp2120_open(dongle_t *self, struct qos_info *qos);
|
||||
static void mcp2120_close(dongle_t *self);
|
||||
static int mcp2120_change_speed(struct irda_task *task);
|
||||
|
||||
#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_reg dongle = {
|
||||
.type = IRDA_MCP2120_DONGLE,
|
||||
.open = mcp2120_open,
|
||||
.close = mcp2120_close,
|
||||
.reset = mcp2120_reset,
|
||||
.change_speed = mcp2120_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init mcp2120_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit mcp2120_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void mcp2120_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
|
||||
qos->min_turn_time.bits = 0x01;
|
||||
}
|
||||
|
||||
static void mcp2120_close(dongle_t *self)
|
||||
{
|
||||
/* Power off dongle */
|
||||
/* reset and inhibit mcp2120 */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
//self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function mcp2120_change_speed (dev, speed)
|
||||
*
|
||||
* Set the speed for the MCP2120.
|
||||
*
|
||||
*/
|
||||
static int mcp2120_change_speed(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param;
|
||||
__u8 control[2];
|
||||
int ret = 0;
|
||||
|
||||
self->speed_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
/* Need to reset the dongle and go to 9600 bps before
|
||||
programming */
|
||||
//printk("Dmcp2120_change_speed irda_task_init\n");
|
||||
if (irda_task_execute(self, mcp2120_reset, NULL, task,
|
||||
(void *) speed))
|
||||
{
|
||||
/* Dongle need more time to reset */
|
||||
irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
|
||||
|
||||
/* Give reset 1 sec to finish */
|
||||
ret = msecs_to_jiffies(1000);
|
||||
}
|
||||
break;
|
||||
case IRDA_TASK_CHILD_WAIT:
|
||||
IRDA_WARNING("%s(), resetting dongle timed out!\n",
|
||||
__FUNCTION__);
|
||||
ret = -1;
|
||||
break;
|
||||
case IRDA_TASK_CHILD_DONE:
|
||||
/* Set DTR to enter command mode */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
udelay(500);
|
||||
|
||||
switch (speed) {
|
||||
case 9600:
|
||||
default:
|
||||
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 */
|
||||
self->write(self->dev, control, 2);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT);
|
||||
ret = msecs_to_jiffies(100);
|
||||
//printk("mcp2120_change_speed irda_child_done\n");
|
||||
break;
|
||||
case IRDA_TASK_WAIT:
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
//printk("mcp2120_change_speed irda_task_wait\n");
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return 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).
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static int mcp2120_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
int ret = 0;
|
||||
|
||||
self->reset_task = task;
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
//printk("mcp2120_reset irda_task_init\n");
|
||||
/* Reset dongle by setting RTS*/
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT1);
|
||||
ret = msecs_to_jiffies(50);
|
||||
break;
|
||||
case IRDA_TASK_WAIT1:
|
||||
//printk("mcp2120_reset irda_task_wait1\n");
|
||||
/* clear RTS and wait for at least 30 ms. */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT2);
|
||||
ret = msecs_to_jiffies(50);
|
||||
break;
|
||||
case IRDA_TASK_WAIT2:
|
||||
//printk("mcp2120_reset irda_task_wait2\n");
|
||||
/* Go back to normal mode */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
|
||||
MODULE_DESCRIPTION("Microchip MCP2120");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize MCP2120 module
|
||||
*
|
||||
*/
|
||||
module_init(mcp2120_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup MCP2120 module
|
||||
*
|
||||
*/
|
||||
module_exit(mcp2120_cleanup);
|
2222
drivers/net/irda/nsc-ircc.c
Arquivo normal
2222
drivers/net/irda/nsc-ircc.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
280
drivers/net/irda/nsc-ircc.h
Arquivo normal
280
drivers/net/irda/nsc-ircc.h
Arquivo normal
@@ -0,0 +1,280 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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<6D> 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>
|
||||
|
||||
/* 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 /* Auxillary 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; /* Lenght 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; /* Lenght 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 net_device_stats stats;
|
||||
|
||||
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 pm_dev *dev;
|
||||
};
|
||||
|
||||
static inline void switch_bank(int iobase, int bank)
|
||||
{
|
||||
outb(bank, iobase+BSR);
|
||||
}
|
||||
|
||||
#endif /* NSC_IRCC_H */
|
156
drivers/net/irda/old_belkin-sir.c
Arquivo normal
156
drivers/net/irda/old_belkin-sir.c
Arquivo normal
@@ -0,0 +1,156 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
// #include <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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__);
|
||||
|
||||
/* 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);
|
164
drivers/net/irda/old_belkin.c
Arquivo normal
164
drivers/net/irda/old_belkin.c
Arquivo normal
@@ -0,0 +1,164 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.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 ;-)
|
||||
*/
|
||||
|
||||
/* Let's guess */
|
||||
#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
|
||||
|
||||
static void old_belkin_open(dongle_t *self, struct qos_info *qos);
|
||||
static void old_belkin_close(dongle_t *self);
|
||||
static int old_belkin_change_speed(struct irda_task *task);
|
||||
static int old_belkin_reset(struct irda_task *task);
|
||||
|
||||
/* These are the baudrates supported */
|
||||
/* static __u32 baud_rates[] = { 9600 }; */
|
||||
|
||||
static struct dongle_reg dongle = {
|
||||
.type = IRDA_OLD_BELKIN_DONGLE,
|
||||
.open = old_belkin_open,
|
||||
.close = old_belkin_close,
|
||||
.reset = old_belkin_reset,
|
||||
.change_speed = old_belkin_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init old_belkin_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit old_belkin_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void old_belkin_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static void old_belkin_close(dongle_t *self)
|
||||
{
|
||||
/* Power off dongle */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function old_belkin_change_speed (task)
|
||||
*
|
||||
* With only one speed available, not much to do...
|
||||
*/
|
||||
static int old_belkin_change_speed(struct irda_task *task)
|
||||
{
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function old_belkin_reset (task)
|
||||
*
|
||||
* Reset the Old-Belkin type dongle.
|
||||
*
|
||||
*/
|
||||
static int old_belkin_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
|
||||
/* Power on dongle */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/* Sleep a minimum of 15 us */
|
||||
udelay(MIN_DELAY);
|
||||
|
||||
/* This dongles speed "defaults" to 9600 bps ;-) */
|
||||
self->speed = 9600;
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize Old-Belkin module
|
||||
*
|
||||
*/
|
||||
module_init(old_belkin_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup Old-Belkin module
|
||||
*
|
||||
*/
|
||||
module_exit(old_belkin_cleanup);
|
1045
drivers/net/irda/sa1100_ir.c
Arquivo normal
1045
drivers/net/irda/sa1100_ir.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
202
drivers/net/irda/sir-dev.h
Arquivo normal
202
drivers/net/irda/sir-dev.h
Arquivo normal
@@ -0,0 +1,202 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* sir.h: include file for irda-sir device abstraction layer
|
||||
*
|
||||
* Copyright (c) 2002 Martin Diehl
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#ifndef IRDA_SIR_H
|
||||
#define IRDA_SIR_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h> // iobuff_t
|
||||
|
||||
/* FIXME: unify irda_request with sir_fsm! */
|
||||
|
||||
struct irda_request {
|
||||
struct list_head lh_request;
|
||||
unsigned long pending;
|
||||
void (*func)(void *);
|
||||
void *data;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
struct sir_fsm {
|
||||
struct semaphore sem;
|
||||
struct irda_request rq;
|
||||
unsigned state, substate;
|
||||
int param;
|
||||
int result;
|
||||
};
|
||||
|
||||
#define SIRDEV_STATE_WAIT_TX_COMPLETE 0x0100
|
||||
|
||||
/* substates for wait_tx_complete */
|
||||
#define SIRDEV_STATE_WAIT_XMIT 0x0101
|
||||
#define SIRDEV_STATE_WAIT_UNTIL_SENT 0x0102
|
||||
#define SIRDEV_STATE_TX_DONE 0x0103
|
||||
|
||||
#define SIRDEV_STATE_DONGLE_OPEN 0x0300
|
||||
|
||||
/* 0x0301-0x03ff reserved for individual dongle substates */
|
||||
|
||||
#define SIRDEV_STATE_DONGLE_CLOSE 0x0400
|
||||
|
||||
/* 0x0401-0x04ff reserved for individual dongle substates */
|
||||
|
||||
#define SIRDEV_STATE_SET_DTR_RTS 0x0500
|
||||
|
||||
#define SIRDEV_STATE_SET_SPEED 0x0700
|
||||
#define SIRDEV_STATE_DONGLE_CHECK 0x0800
|
||||
#define SIRDEV_STATE_DONGLE_RESET 0x0900
|
||||
|
||||
/* 0x0901-0x09ff reserved for individual dongle substates */
|
||||
|
||||
#define SIRDEV_STATE_DONGLE_SPEED 0x0a00
|
||||
/* 0x0a01-0x0aff reserved for individual dongle substates */
|
||||
|
||||
#define SIRDEV_STATE_PORT_SPEED 0x0b00
|
||||
#define SIRDEV_STATE_DONE 0x0c00
|
||||
#define SIRDEV_STATE_ERROR 0x0d00
|
||||
#define SIRDEV_STATE_COMPLETE 0x0e00
|
||||
|
||||
#define SIRDEV_STATE_DEAD 0xffff
|
||||
|
||||
|
||||
struct sir_dev;
|
||||
|
||||
struct dongle_driver {
|
||||
|
||||
struct module *owner;
|
||||
|
||||
const char *driver_name;
|
||||
|
||||
IRDA_DONGLE type;
|
||||
|
||||
int (*open)(struct sir_dev *dev);
|
||||
int (*close)(struct sir_dev *dev);
|
||||
int (*reset)(struct sir_dev *dev);
|
||||
int (*set_speed)(struct sir_dev *dev, unsigned speed);
|
||||
|
||||
struct list_head dongle_list;
|
||||
};
|
||||
|
||||
struct sir_driver {
|
||||
|
||||
struct module *owner;
|
||||
|
||||
const char *driver_name;
|
||||
|
||||
int qos_mtt_bits;
|
||||
|
||||
int (*chars_in_buffer)(struct sir_dev *dev);
|
||||
void (*wait_until_sent)(struct sir_dev *dev);
|
||||
int (*set_speed)(struct sir_dev *dev, unsigned speed);
|
||||
int (*set_dtr_rts)(struct sir_dev *dev, int dtr, int rts);
|
||||
|
||||
int (*do_write)(struct sir_dev *dev, const unsigned char *ptr, size_t len);
|
||||
|
||||
int (*start_dev)(struct sir_dev *dev);
|
||||
int (*stop_dev)(struct sir_dev *dev);
|
||||
};
|
||||
|
||||
|
||||
/* exported */
|
||||
|
||||
extern int irda_register_dongle(struct dongle_driver *new);
|
||||
extern int irda_unregister_dongle(struct dongle_driver *drv);
|
||||
|
||||
extern struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name);
|
||||
extern int sirdev_put_instance(struct sir_dev *self);
|
||||
|
||||
extern int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type);
|
||||
extern void sirdev_write_complete(struct sir_dev *dev);
|
||||
extern int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count);
|
||||
|
||||
/* low level helpers for SIR device/dongle setup */
|
||||
extern int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len);
|
||||
extern int sirdev_raw_read(struct sir_dev *dev, char *buf, int len);
|
||||
extern int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts);
|
||||
|
||||
/* not exported */
|
||||
|
||||
extern int sirdev_get_dongle(struct sir_dev *self, IRDA_DONGLE type);
|
||||
extern int sirdev_put_dongle(struct sir_dev *self);
|
||||
|
||||
extern void sirdev_enable_rx(struct sir_dev *dev);
|
||||
extern int sirdev_schedule_request(struct sir_dev *dev, int state, unsigned param);
|
||||
extern int __init irda_thread_create(void);
|
||||
extern void __exit irda_thread_join(void);
|
||||
|
||||
/* inline helpers */
|
||||
|
||||
static inline int sirdev_schedule_speed(struct sir_dev *dev, unsigned speed)
|
||||
{
|
||||
return sirdev_schedule_request(dev, SIRDEV_STATE_SET_SPEED, speed);
|
||||
}
|
||||
|
||||
static inline int sirdev_schedule_dongle_open(struct sir_dev *dev, int dongle_id)
|
||||
{
|
||||
return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_OPEN, dongle_id);
|
||||
}
|
||||
|
||||
static inline int sirdev_schedule_dongle_close(struct sir_dev *dev)
|
||||
{
|
||||
return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_CLOSE, 0);
|
||||
}
|
||||
|
||||
static inline int sirdev_schedule_dtr_rts(struct sir_dev *dev, int dtr, int rts)
|
||||
{
|
||||
int dtrrts;
|
||||
|
||||
dtrrts = ((dtr) ? 0x02 : 0x00) | ((rts) ? 0x01 : 0x00);
|
||||
return sirdev_schedule_request(dev, SIRDEV_STATE_SET_DTR_RTS, dtrrts);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode)
|
||||
{
|
||||
return sirdev_schedule_request(dev, SIRDEV_STATE_SET_MODE, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
struct sir_dev {
|
||||
struct net_device *netdev;
|
||||
struct net_device_stats stats;
|
||||
|
||||
struct irlap_cb *irlap;
|
||||
|
||||
struct qos_info qos;
|
||||
|
||||
char hwname[32];
|
||||
|
||||
struct sir_fsm fsm;
|
||||
atomic_t enable_rx;
|
||||
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 */
|
56
drivers/net/irda/sir_core.c
Arquivo normal
56
drivers/net/irda/sir_core.c
Arquivo normal
@@ -0,0 +1,56 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* sir_core.c: module core for irda-sir abstraction layer
|
||||
*
|
||||
* Copyright (c) 2002 Martin Diehl
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
|
||||
#include "sir-dev.h"
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
|
||||
MODULE_DESCRIPTION("IrDA SIR core");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
EXPORT_SYMBOL(irda_register_dongle);
|
||||
EXPORT_SYMBOL(irda_unregister_dongle);
|
||||
|
||||
EXPORT_SYMBOL(sirdev_get_instance);
|
||||
EXPORT_SYMBOL(sirdev_put_instance);
|
||||
|
||||
EXPORT_SYMBOL(sirdev_set_dongle);
|
||||
EXPORT_SYMBOL(sirdev_write_complete);
|
||||
EXPORT_SYMBOL(sirdev_receive);
|
||||
|
||||
EXPORT_SYMBOL(sirdev_raw_write);
|
||||
EXPORT_SYMBOL(sirdev_raw_read);
|
||||
EXPORT_SYMBOL(sirdev_set_dtr_rts);
|
||||
|
||||
static int __init sir_core_init(void)
|
||||
{
|
||||
return irda_thread_create();
|
||||
}
|
||||
|
||||
static void __exit sir_core_exit(void)
|
||||
{
|
||||
irda_thread_join();
|
||||
}
|
||||
|
||||
module_init(sir_core_init);
|
||||
module_exit(sir_core_exit);
|
||||
|
677
drivers/net/irda/sir_dev.c
Arquivo normal
677
drivers/net/irda/sir_dev.c
Arquivo normal
@@ -0,0 +1,677 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp_lock.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"
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
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", __FUNCTION__, 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;
|
||||
}
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
|
||||
{
|
||||
int ret = -ENXIO;
|
||||
if (dev->drv->set_dtr_rts != 0)
|
||||
ret = dev->drv->set_dtr_rts(dev, dtr, rts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* 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",
|
||||
__FUNCTION__, 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",
|
||||
__FUNCTION__, actual);
|
||||
if ((skb=dev->tx_skb) != NULL) {
|
||||
dev->tx_skb = NULL;
|
||||
dev_kfree_skb_any(skb);
|
||||
dev->stats.tx_errors++;
|
||||
dev->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", __FUNCTION__);
|
||||
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", __FUNCTION__);
|
||||
|
||||
if ((skb=dev->tx_skb) != NULL) {
|
||||
dev->tx_skb = NULL;
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
if (unlikely(dev->new_speed > 0)) {
|
||||
IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__);
|
||||
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",
|
||||
__FUNCTION__, 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);
|
||||
}
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!dev->irlap) {
|
||||
IRDA_WARNING("%s - too early: %p / %zd!\n",
|
||||
__FUNCTION__, 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->stats.rx_dropped++;
|
||||
IRDA_DEBUG(0, "%s; rx-drop: %zd\n", __FUNCTION__, 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->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;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/* callbacks from network layer */
|
||||
|
||||
static struct net_device_stats *sirdev_get_stats(struct net_device *ndev)
|
||||
{
|
||||
struct sir_dev *dev = ndev->priv;
|
||||
|
||||
return (dev) ? &dev->stats : NULL;
|
||||
}
|
||||
|
||||
static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct sir_dev *dev = ndev->priv;
|
||||
unsigned long flags;
|
||||
int actual = 0;
|
||||
int err;
|
||||
s32 speed;
|
||||
|
||||
IRDA_ASSERT(dev != NULL, return 0;);
|
||||
|
||||
netif_stop_queue(ndev);
|
||||
|
||||
IRDA_DEBUG(3, "%s(), skb->len = %d\n", __FUNCTION__, 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 1;
|
||||
}
|
||||
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 0;
|
||||
} 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", __FUNCTION__);
|
||||
}
|
||||
|
||||
/* 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->stats.collisions++;
|
||||
|
||||
actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
|
||||
|
||||
if (likely(actual > 0)) {
|
||||
dev->tx_skb = skb;
|
||||
ndev->trans_start = jiffies;
|
||||
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",
|
||||
__FUNCTION__, actual);
|
||||
dev_kfree_skb_any(skb);
|
||||
dev->stats.tx_errors++;
|
||||
dev->stats.tx_dropped++;
|
||||
netif_wake_queue(ndev);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->tx_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 = ndev->priv;
|
||||
int ret = 0;
|
||||
|
||||
IRDA_ASSERT(dev != NULL, return -1;);
|
||||
|
||||
IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, 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 = __dev_alloc_skb(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)
|
||||
{
|
||||
if (dev->rx_buff.skb)
|
||||
kfree_skb(dev->rx_buff.skb);
|
||||
if (dev->tx_buff.head)
|
||||
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 = ndev->priv;
|
||||
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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__, 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 = ndev->priv;
|
||||
const struct sir_driver *drv;
|
||||
|
||||
// IRDA_DEBUG(0, "%s\n", __FUNCTION__);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------- */
|
||||
|
||||
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", __FUNCTION__, 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", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
dev = ndev->priv;
|
||||
|
||||
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);
|
||||
init_MUTEX(&dev->fsm.sem);
|
||||
|
||||
INIT_LIST_HEAD(&dev->fsm.rq.lh_request);
|
||||
dev->fsm.rq.pending = 0;
|
||||
init_timer(&dev->fsm.rq.timer);
|
||||
|
||||
dev->drv = drv;
|
||||
dev->netdev = ndev;
|
||||
|
||||
SET_MODULE_OWNER(ndev);
|
||||
|
||||
/* Override the network functions we need to use */
|
||||
ndev->hard_start_xmit = sirdev_hard_xmit;
|
||||
ndev->open = sirdev_open;
|
||||
ndev->stop = sirdev_close;
|
||||
ndev->get_stats = sirdev_get_stats;
|
||||
ndev->do_ioctl = sirdev_ioctl;
|
||||
|
||||
if (register_netdev(ndev)) {
|
||||
IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
|
||||
goto out_freenetdev;
|
||||
}
|
||||
|
||||
return dev;
|
||||
|
||||
out_freenetdev:
|
||||
free_netdev(ndev);
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sirdev_put_instance(struct sir_dev *dev)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
IRDA_DEBUG(0, "%s\n", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__, 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;
|
||||
}
|
||||
|
134
drivers/net/irda/sir_dongle.c
Arquivo normal
134
drivers/net/irda/sir_dongle.c
Arquivo normal
@@ -0,0 +1,134 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* sir_dongle.c: manager for serial dongle protocol drivers
|
||||
*
|
||||
* Copyright (c) 2002 Martin Diehl
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/kmod.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
|
||||
#include "sir-dev.h"
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* dongle registration and attachment
|
||||
*
|
||||
*/
|
||||
|
||||
static LIST_HEAD(dongle_list); /* list of registered dongle drivers */
|
||||
static DECLARE_MUTEX(dongle_list_lock); /* protects the list */
|
||||
|
||||
int irda_register_dongle(struct dongle_driver *new)
|
||||
{
|
||||
struct list_head *entry;
|
||||
struct dongle_driver *drv;
|
||||
|
||||
IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n",
|
||||
__FUNCTION__, new->driver_name, new->type);
|
||||
|
||||
down(&dongle_list_lock);
|
||||
list_for_each(entry, &dongle_list) {
|
||||
drv = list_entry(entry, struct dongle_driver, dongle_list);
|
||||
if (new->type == drv->type) {
|
||||
up(&dongle_list_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
list_add(&new->dongle_list, &dongle_list);
|
||||
up(&dongle_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irda_unregister_dongle(struct dongle_driver *drv)
|
||||
{
|
||||
down(&dongle_list_lock);
|
||||
list_del(&drv->dongle_list);
|
||||
up(&dongle_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
|
||||
{
|
||||
struct list_head *entry;
|
||||
const struct dongle_driver *drv = NULL;
|
||||
int err = -EINVAL;
|
||||
|
||||
#ifdef CONFIG_KMOD
|
||||
request_module("irda-dongle-%d", type);
|
||||
#endif
|
||||
|
||||
if (dev->dongle_drv != NULL)
|
||||
return -EBUSY;
|
||||
|
||||
/* serialize access to the list of registered dongles */
|
||||
down(&dongle_list_lock);
|
||||
|
||||
list_for_each(entry, &dongle_list) {
|
||||
drv = list_entry(entry, struct dongle_driver, dongle_list);
|
||||
if (drv->type == type)
|
||||
break;
|
||||
else
|
||||
drv = NULL;
|
||||
}
|
||||
|
||||
if (!drv) {
|
||||
err = -ENODEV;
|
||||
goto out_unlock; /* no such dongle */
|
||||
}
|
||||
|
||||
/* handling of SMP races with dongle module removal - three cases:
|
||||
* 1) dongle driver was already unregistered - then we haven't found the
|
||||
* requested dongle above and are already out here
|
||||
* 2) the module is already marked deleted but the driver is still
|
||||
* registered - then the try_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 */
|
||||
|
||||
up(&dongle_list_lock);
|
||||
return 0;
|
||||
|
||||
out_reject:
|
||||
dev->dongle_drv = NULL;
|
||||
module_put(drv->owner);
|
||||
out_unlock:
|
||||
up(&dongle_list_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
int sirdev_put_dongle(struct sir_dev *dev)
|
||||
{
|
||||
const struct dongle_driver *drv = dev->dongle_drv;
|
||||
|
||||
if (drv) {
|
||||
if (drv->close)
|
||||
drv->close(dev); /* close this dongle instance */
|
||||
|
||||
dev->dongle_drv = NULL; /* unlink the dongle driver */
|
||||
module_put(drv->owner);/* decrement driver's module refcount */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
502
drivers/net/irda/sir_kthread.c
Arquivo normal
502
drivers/net/irda/sir_kthread.c
Arquivo normal
@@ -0,0 +1,502 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* sir_kthread.c: dedicated thread to process scheduled
|
||||
* sir device setup requests
|
||||
*
|
||||
* 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/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
|
||||
#include "sir-dev.h"
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* kIrDAd kernel thread and config state machine
|
||||
*
|
||||
*/
|
||||
|
||||
struct irda_request_queue {
|
||||
struct list_head request_list;
|
||||
spinlock_t lock;
|
||||
task_t *thread;
|
||||
struct completion exit;
|
||||
wait_queue_head_t kick, done;
|
||||
atomic_t num_pending;
|
||||
};
|
||||
|
||||
static struct irda_request_queue irda_rq_queue;
|
||||
|
||||
static int irda_queue_request(struct irda_request *rq)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!test_and_set_bit(0, &rq->pending)) {
|
||||
spin_lock_irqsave(&irda_rq_queue.lock, flags);
|
||||
list_add_tail(&rq->lh_request, &irda_rq_queue.request_list);
|
||||
wake_up(&irda_rq_queue.kick);
|
||||
atomic_inc(&irda_rq_queue.num_pending);
|
||||
spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void irda_request_timer(unsigned long data)
|
||||
{
|
||||
struct irda_request *rq = (struct irda_request *)data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&irda_rq_queue.lock, flags);
|
||||
list_add_tail(&rq->lh_request, &irda_rq_queue.request_list);
|
||||
wake_up(&irda_rq_queue.kick);
|
||||
spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
|
||||
}
|
||||
|
||||
static int irda_queue_delayed_request(struct irda_request *rq, unsigned long delay)
|
||||
{
|
||||
int ret = 0;
|
||||
struct timer_list *timer = &rq->timer;
|
||||
|
||||
if (!test_and_set_bit(0, &rq->pending)) {
|
||||
timer->expires = jiffies + delay;
|
||||
timer->function = irda_request_timer;
|
||||
timer->data = (unsigned long)rq;
|
||||
atomic_inc(&irda_rq_queue.num_pending);
|
||||
add_timer(timer);
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void run_irda_queue(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct list_head *entry, *tmp;
|
||||
struct irda_request *rq;
|
||||
|
||||
spin_lock_irqsave(&irda_rq_queue.lock, flags);
|
||||
list_for_each_safe(entry, tmp, &irda_rq_queue.request_list) {
|
||||
rq = list_entry(entry, struct irda_request, lh_request);
|
||||
list_del_init(entry);
|
||||
spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
|
||||
|
||||
clear_bit(0, &rq->pending);
|
||||
rq->func(rq->data);
|
||||
|
||||
if (atomic_dec_and_test(&irda_rq_queue.num_pending))
|
||||
wake_up(&irda_rq_queue.done);
|
||||
|
||||
spin_lock_irqsave(&irda_rq_queue.lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
|
||||
}
|
||||
|
||||
static int irda_thread(void *startup)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
daemonize("kIrDAd");
|
||||
|
||||
irda_rq_queue.thread = current;
|
||||
|
||||
complete((struct completion *)startup);
|
||||
|
||||
while (irda_rq_queue.thread != NULL) {
|
||||
|
||||
/* We use TASK_INTERRUPTIBLE, rather than
|
||||
* TASK_UNINTERRUPTIBLE. Andrew Morton made this
|
||||
* change ; he told me that it is safe, because "signal
|
||||
* blocking is now handled in daemonize()", he added
|
||||
* that the problem is that "uninterruptible sleep
|
||||
* contributes to load average", making user worry.
|
||||
* Jean II */
|
||||
set_task_state(current, TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&irda_rq_queue.kick, &wait);
|
||||
if (list_empty(&irda_rq_queue.request_list))
|
||||
schedule();
|
||||
else
|
||||
__set_task_state(current, TASK_RUNNING);
|
||||
remove_wait_queue(&irda_rq_queue.kick, &wait);
|
||||
|
||||
/* make swsusp happy with our thread */
|
||||
if (current->flags & PF_FREEZE)
|
||||
refrigerator(PF_FREEZE);
|
||||
|
||||
run_irda_queue();
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,35)
|
||||
reparent_to_init();
|
||||
#endif
|
||||
complete_and_exit(&irda_rq_queue.exit, 0);
|
||||
/* never reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void flush_irda_queue(void)
|
||||
{
|
||||
if (atomic_read(&irda_rq_queue.num_pending)) {
|
||||
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
if (!list_empty(&irda_rq_queue.request_list))
|
||||
run_irda_queue();
|
||||
|
||||
set_task_state(current, TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&irda_rq_queue.done, &wait);
|
||||
if (atomic_read(&irda_rq_queue.num_pending))
|
||||
schedule();
|
||||
else
|
||||
__set_task_state(current, TASK_RUNNING);
|
||||
remove_wait_queue(&irda_rq_queue.done, &wait);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 irda_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", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
fsm->substate = next_state;
|
||||
} while (delay == 0);
|
||||
return delay;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function irda_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 irda_config_fsm(void *data)
|
||||
{
|
||||
struct sir_dev *dev = data;
|
||||
struct sir_fsm *fsm = &dev->fsm;
|
||||
int next_state;
|
||||
int ret = -1;
|
||||
unsigned delay;
|
||||
|
||||
IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies);
|
||||
|
||||
do {
|
||||
IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n",
|
||||
__FUNCTION__, 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 = irda_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->reset) {
|
||||
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", __FUNCTION__);
|
||||
fsm->result = -EINVAL;
|
||||
/* fall thru */
|
||||
|
||||
case SIRDEV_STATE_ERROR:
|
||||
IRDA_ERROR("%s - error: %d\n", __FUNCTION__, 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);
|
||||
|
||||
irda_queue_delayed_request(&fsm->rq, 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;
|
||||
int xmit_was_down;
|
||||
|
||||
IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param);
|
||||
|
||||
if (down_trylock(&fsm->sem)) {
|
||||
if (in_interrupt() || in_atomic() || irqs_disabled()) {
|
||||
IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__);
|
||||
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", __FUNCTION__);
|
||||
up(&fsm->sem);
|
||||
return -ESTALE; /* or better EPIPE? */
|
||||
}
|
||||
|
||||
xmit_was_down = netif_queue_stopped(dev->netdev);
|
||||
netif_stop_queue(dev->netdev);
|
||||
atomic_set(&dev->enable_rx, 0);
|
||||
|
||||
fsm->state = initial_state;
|
||||
fsm->param = param;
|
||||
fsm->result = 0;
|
||||
|
||||
INIT_LIST_HEAD(&fsm->rq.lh_request);
|
||||
fsm->rq.pending = 0;
|
||||
fsm->rq.func = irda_config_fsm;
|
||||
fsm->rq.data = dev;
|
||||
|
||||
if (!irda_queue_request(&fsm->rq)) { /* returns 0 on error! */
|
||||
atomic_set(&dev->enable_rx, 1);
|
||||
if (!xmit_was_down)
|
||||
netif_wake_queue(dev->netdev);
|
||||
up(&fsm->sem);
|
||||
return -EAGAIN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init irda_thread_create(void)
|
||||
{
|
||||
struct completion startup;
|
||||
int pid;
|
||||
|
||||
spin_lock_init(&irda_rq_queue.lock);
|
||||
irda_rq_queue.thread = NULL;
|
||||
INIT_LIST_HEAD(&irda_rq_queue.request_list);
|
||||
init_waitqueue_head(&irda_rq_queue.kick);
|
||||
init_waitqueue_head(&irda_rq_queue.done);
|
||||
atomic_set(&irda_rq_queue.num_pending, 0);
|
||||
|
||||
init_completion(&startup);
|
||||
pid = kernel_thread(irda_thread, &startup, CLONE_FS|CLONE_FILES);
|
||||
if (pid <= 0)
|
||||
return -EAGAIN;
|
||||
else
|
||||
wait_for_completion(&startup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit irda_thread_join(void)
|
||||
{
|
||||
if (irda_rq_queue.thread) {
|
||||
flush_irda_queue();
|
||||
init_completion(&irda_rq_queue.exit);
|
||||
irda_rq_queue.thread = NULL;
|
||||
wake_up(&irda_rq_queue.kick);
|
||||
wait_for_completion(&irda_rq_queue.exit);
|
||||
}
|
||||
}
|
||||
|
2396
drivers/net/irda/smsc-ircc2.c
Arquivo normal
2396
drivers/net/irda/smsc-ircc2.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
194
drivers/net/irda/smsc-ircc2.h
Arquivo normal
194
drivers/net/irda/smsc-ircc2.h
Arquivo normal
@@ -0,0 +1,194 @@
|
||||
/*********************************************************************
|
||||
* $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#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
Arquivo normal
100
drivers/net/irda/smsc-sio.h
Arquivo normal
@@ -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
|
1184
drivers/net/irda/stir4200.c
Arquivo normal
1184
drivers/net/irda/stir4200.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
232
drivers/net/irda/tekram-sir.c
Arquivo normal
232
drivers/net/irda/tekram-sir.c
Arquivo normal
@@ -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<6D> 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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__);
|
||||
|
||||
/* 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", __FUNCTION__);
|
||||
|
||||
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", __FUNCTION__, 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", __FUNCTION__);
|
||||
|
||||
/* 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);
|
282
drivers/net/irda/tekram.c
Arquivo normal
282
drivers/net/irda/tekram.c
Arquivo normal
@@ -0,0 +1,282 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Filename: tekram.c
|
||||
* Version: 1.2
|
||||
* 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: Fri Dec 17 09:13:09 1999
|
||||
* Modified by: Dag Brattli <dagb@cs.uit.no>
|
||||
*
|
||||
* Copyright (c) 1998-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<6D> 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/tty.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
||||
static void tekram_open(dongle_t *self, struct qos_info *qos);
|
||||
static void tekram_close(dongle_t *self);
|
||||
static int tekram_change_speed(struct irda_task *task);
|
||||
static int tekram_reset(struct irda_task *task);
|
||||
|
||||
#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_reg dongle = {
|
||||
.type = IRDA_TEKRAM_DONGLE,
|
||||
.open = tekram_open,
|
||||
.close = tekram_close,
|
||||
.reset = tekram_reset,
|
||||
.change_speed = tekram_change_speed,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init tekram_init(void)
|
||||
{
|
||||
return irda_device_register_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void __exit tekram_cleanup(void)
|
||||
{
|
||||
irda_device_unregister_dongle(&dongle);
|
||||
}
|
||||
|
||||
static void tekram_open(dongle_t *self, struct qos_info *qos)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void tekram_close(dongle_t *self)
|
||||
{
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
|
||||
|
||||
/* Power off dongle */
|
||||
self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
|
||||
if (self->reset_task)
|
||||
irda_task_delete(self->reset_task);
|
||||
if (self->speed_task)
|
||||
irda_task_delete(self->speed_task);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
* 5. clear RTS (return to NORMAL Operation)
|
||||
* 6. wait at least 50 us, new setting (baud rate, etc) takes effect here
|
||||
* after
|
||||
*/
|
||||
static int tekram_change_speed(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
__u32 speed = (__u32) task->param;
|
||||
__u8 byte;
|
||||
int ret = 0;
|
||||
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
|
||||
|
||||
IRDA_ASSERT(task != NULL, return -1;);
|
||||
|
||||
if (self->speed_task && self->speed_task != task) {
|
||||
IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ );
|
||||
return msecs_to_jiffies(10);
|
||||
} else
|
||||
self->speed_task = task;
|
||||
|
||||
switch (speed) {
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
case IRDA_TASK_CHILD_INIT:
|
||||
/*
|
||||
* Need to reset the dongle and go to 9600 bps before
|
||||
* programming
|
||||
*/
|
||||
if (irda_task_execute(self, tekram_reset, NULL, task,
|
||||
(void *) speed))
|
||||
{
|
||||
/* Dongle need more time to reset */
|
||||
irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
|
||||
|
||||
/* Give reset 1 sec to finish */
|
||||
ret = msecs_to_jiffies(1000);
|
||||
} else
|
||||
irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
|
||||
break;
|
||||
case IRDA_TASK_CHILD_WAIT:
|
||||
IRDA_WARNING("%s(), resetting dongle timed out!\n",
|
||||
__FUNCTION__);
|
||||
ret = -1;
|
||||
break;
|
||||
case IRDA_TASK_CHILD_DONE:
|
||||
/* Set DTR, Clear RTS */
|
||||
self->set_dtr_rts(self->dev, TRUE, FALSE);
|
||||
|
||||
/* Wait at least 7us */
|
||||
udelay(14);
|
||||
|
||||
/* Write control byte */
|
||||
self->write(self->dev, &byte, 1);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT);
|
||||
|
||||
/* Wait at least 100 ms */
|
||||
ret = msecs_to_jiffies(150);
|
||||
break;
|
||||
case IRDA_TASK_WAIT:
|
||||
/* Set DTR, Set RTS */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->speed_task = NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return 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
|
||||
*/
|
||||
int tekram_reset(struct irda_task *task)
|
||||
{
|
||||
dongle_t *self = (dongle_t *) task->instance;
|
||||
int ret = 0;
|
||||
|
||||
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
|
||||
|
||||
IRDA_ASSERT(task != NULL, return -1;);
|
||||
|
||||
if (self->reset_task && self->reset_task != task) {
|
||||
IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ );
|
||||
return msecs_to_jiffies(10);
|
||||
} else
|
||||
self->reset_task = task;
|
||||
|
||||
/* Power off dongle */
|
||||
//self->set_dtr_rts(self->dev, FALSE, FALSE);
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
switch (task->state) {
|
||||
case IRDA_TASK_INIT:
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT1);
|
||||
|
||||
/* Sleep 50 ms */
|
||||
ret = msecs_to_jiffies(50);
|
||||
break;
|
||||
case IRDA_TASK_WAIT1:
|
||||
/* Clear DTR, Set RTS */
|
||||
self->set_dtr_rts(self->dev, FALSE, TRUE);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_WAIT2);
|
||||
|
||||
/* Should sleep 1 ms */
|
||||
ret = msecs_to_jiffies(1);
|
||||
break;
|
||||
case IRDA_TASK_WAIT2:
|
||||
/* Set DTR, Set RTS */
|
||||
self->set_dtr_rts(self->dev, TRUE, TRUE);
|
||||
|
||||
/* Wait at least 50 us */
|
||||
udelay(75);
|
||||
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
break;
|
||||
default:
|
||||
IRDA_ERROR("%s(), unknown state %d\n",
|
||||
__FUNCTION__, task->state);
|
||||
irda_task_next_state(task, IRDA_TASK_DONE);
|
||||
self->reset_task = NULL;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/*
|
||||
* Function init_module (void)
|
||||
*
|
||||
* Initialize Tekram module
|
||||
*
|
||||
*/
|
||||
module_init(tekram_init);
|
||||
|
||||
/*
|
||||
* Function cleanup_module (void)
|
||||
*
|
||||
* Cleanup Tekram module
|
||||
*
|
||||
*/
|
||||
module_exit(tekram_cleanup);
|
1676
drivers/net/irda/via-ircc.c
Arquivo normal
1676
drivers/net/irda/via-ircc.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
853
drivers/net/irda/via-ircc.h
Arquivo normal
853
drivers/net/irda/via-ircc.h
Arquivo normal
@@ -0,0 +1,853 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
* 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; /* Lenght 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; /* Lenght 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 net_device_stats stats;
|
||||
|
||||
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;
|
||||
struct pm_dev *dev;
|
||||
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;
|
||||
}; //Switch
|
||||
}
|
||||
|
||||
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 */
|
1912
drivers/net/irda/vlsi_ir.c
Arquivo normal
1912
drivers/net/irda/vlsi_ir.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
798
drivers/net/irda/vlsi_ir.h
Arquivo normal
798
drivers/net/irda/vlsi_ir.h
Arquivo normal
@@ -0,0 +1,798 @@
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
********************************************************************/
|
||||
|
||||
#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
|
||||
|
||||
/* in recent 2.5 interrupt handlers have non-void return value */
|
||||
#ifndef IRQ_RETVAL
|
||||
typedef void irqreturn_t;
|
||||
#define IRQ_NONE
|
||||
#define IRQ_HANDLED
|
||||
#define IRQ_RETVAL(x)
|
||||
#endif
|
||||
|
||||
/* some stuff need to check kernelversion. Not all 2.5 stuff was present
|
||||
* in early 2.5.x - the test is merely to separate 2.4 from 2.5
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
|
||||
|
||||
/* PDE() introduced in 2.5.4 */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#define PDE(inode) ((inode)->u.generic_ip)
|
||||
#endif
|
||||
|
||||
/* irda crc16 calculation exported in 2.5.42 */
|
||||
#define irda_calc_crc16(fcs,buf,len) (GOOD_FCS)
|
||||
|
||||
/* we use this for unified pci device name access */
|
||||
#define PCIDEV_NAME(pdev) ((pdev)->name)
|
||||
|
||||
#else /* 2.5 or later */
|
||||
|
||||
/* recent 2.5/2.6 stores pci device names at varying places ;-) */
|
||||
#ifdef CONFIG_PCI_NAMES
|
||||
/* human readable name */
|
||||
#define PCIDEV_NAME(pdev) ((pdev)->pretty_name)
|
||||
#else
|
||||
/* whatever we get from the associated struct device - bus:slot:dev.fn id */
|
||||
#define PCIDEV_NAME(pdev) (pci_name(pdev))
|
||||
#endif
|
||||
|
||||
#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 transfered 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 u16 rd_count; /* tx/rx count [11:0] */
|
||||
u16 reserved;
|
||||
union {
|
||||
u32 addr; /* [23:0] of the buffer's busaddress */
|
||||
struct {
|
||||
u8 addr_res[3];
|
||||
volatile u8 status; /* descriptor status */
|
||||
} rd_s __attribute__((packed));
|
||||
} rd_u __attribute((packed));
|
||||
} __attribute__ ((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", __FUNCTION__);
|
||||
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 net_device_stats stats;
|
||||
|
||||
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 semaphore sem;
|
||||
|
||||
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 transfered 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 */
|
||||
|
53
drivers/net/irda/w83977af.h
Arquivo normal
53
drivers/net/irda/w83977af.h
Arquivo normal
@@ -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
|
1379
drivers/net/irda/w83977af_ir.c
Arquivo normal
1379
drivers/net/irda/w83977af_ir.c
Arquivo normal
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
199
drivers/net/irda/w83977af_ir.h
Arquivo normal
199
drivers/net/irda/w83977af_ir.h
Arquivo normal
@@ -0,0 +1,199 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* 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<6D> 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 net_device_stats stats;
|
||||
|
||||
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
|
Referência em uma nova issue
Block a user