From e3e5a683c0199de1171bf737f4f95a8b4e1e2da4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:20:46 -0500 Subject: [PATCH] Linux 2.2.15pre5 o Support newer SCSI devices that lack READ6 (Jens Axboe) and WRITE6 commands. o Fix for the lanmedia bug I added when merging (Andrew Stanley-Jones) o Qnxfs now builds with gcc 2.7.2 (Arjan van de Ven, Anders Larsen) o Gemtek radio documentation update (Jonas Munsin) o Sparc 32bit hook fixes (Jakub Jelinek) o Make 1284 probing more reliable (Tim Waugh) o ISDN4linux update (Karsten Keil) o Small irda fixes (Dag Brattli) o Channel bonding (Thomas Davis) o Fix an IDE probing problem with CRW9624's (Mark Lord) o Fix cases where things write to user space in TASK_INTERRUPTIBLE as well as some other odd quirks (Ben LaHaise et al) o Fix problem with Acer 50x drive and Linux ATAPI violation (Mark Lord) o Page alloc change + debug traps (Rik Van Riel) o Add 5LUN blacklist for the LASOUND CDX7405 (Brendan Miller) --- CREDITS | 7 + Documentation/Configure.help | 105 +- Documentation/isdn/README.HiSax | 4 + Documentation/networking/bonding.txt | 128 +++ MAINTAINERS | 6 + Makefile | 2 +- arch/ppc/kernel/prom.c | 2 +- arch/sparc64/kernel/sys32.S | 18 +- arch/sparc64/kernel/sys_sparc32.c | 50 +- arch/sparc64/kernel/systbls.S | 12 +- drivers/block/ide-cd.c | 98 +- drivers/block/ide-probe.c | 1 + drivers/char/Config.in | 2 +- drivers/char/n_tty.c | 4 + drivers/char/radio-gemtek.c | 4 +- drivers/isdn/Config.in | 115 +- drivers/isdn/avmb1/c4.c | 1316 +++++++++++++++++++++ drivers/isdn/eicon/eicon_idi.c | 9 +- drivers/isdn/eicon/eicon_mod.c | 13 +- drivers/isdn/hisax/Makefile | 4 + drivers/isdn/hisax/config.c | 32 +- drivers/isdn/hisax/hfc_sx.c | 1584 ++++++++++++++++++++++++++ drivers/isdn/hisax/hfc_sx.h | 216 ++++ drivers/isdn/hisax/hisax.h | 63 +- drivers/isdn/hisax/isar.c | 668 +++++++++-- drivers/isdn/hisax/isar.h | 36 +- drivers/isdn/hisax/isdnl1.c | 27 +- drivers/isdn/hisax/l3_1tr6.c | 8 +- drivers/isdn/hisax/l3dss1.c | 32 +- drivers/isdn/hisax/l3dss1.h | 7 +- drivers/isdn/hisax/md5sums.asc | 16 +- drivers/isdn/hisax/sedlbauer.c | 13 +- drivers/isdn/isdn_common.c | 104 +- drivers/isdn/isdn_common.h | 7 +- drivers/isdn/isdn_net.c | 78 +- drivers/isdn/isdn_ppp.c | 20 +- drivers/isdn/isdn_tty.c | 108 +- drivers/isdn/isdn_tty.h | 14 +- drivers/isdn/isdn_ttyfax.c | 1118 +++++++++--------- drivers/misc/parport_pc.c | 5 - drivers/net/Config.in | 1 + drivers/net/Makefile | 8 + drivers/net/Space.c | 6 +- drivers/net/bonding.c | 353 ++++++ drivers/net/dmfe.c | 2 +- drivers/net/irda/nsc-ircc.c | 39 +- drivers/net/lmc/lmc_main.c | 14 +- drivers/net/olympic.c | 28 +- drivers/net/olympic.h | 2 + drivers/pnp/parport_probe.c | 16 + drivers/scsi/aic7xxx.c | 6 +- drivers/scsi/scsi.c | 1 + drivers/scsi/sd.c | 9 +- fs/qnx4/dir.c | 4 +- include/linux/if_bonding.h | 59 + include/linux/isdn.h | 45 +- include/linux/isdnif.h | 55 +- include/linux/qnx4_fs.h | 6 +- include/net/irda/nsc-ircc.h | 20 +- kernel/exit.c | 2 + mm/page_alloc.c | 9 + net/core/dev.c | 3 + net/ipv4/tcp.c | 9 +- net/irda/irda_device.c | 12 +- 64 files changed, 5775 insertions(+), 990 deletions(-) create mode 100644 Documentation/networking/bonding.txt create mode 100644 drivers/isdn/avmb1/c4.c create mode 100644 drivers/isdn/hisax/hfc_sx.c create mode 100644 drivers/isdn/hisax/hfc_sx.h create mode 100644 drivers/net/bonding.c create mode 100644 include/linux/if_bonding.h diff --git a/CREDITS b/CREDITS index a41f9d40d19b..b843fbc7d92f 100644 --- a/CREDITS +++ b/CREDITS @@ -1901,6 +1901,13 @@ D: Optics Storage 8000AT cdrom driver S: Cliffwood, New Jersey 07721 S: USA +N: Andrew Stanley-Jones +E: asj@lanmedia.com +D: LanMedia Corp. Device WAN card device driver +S: #102, 686 W. Maude Ave +S: Sunyvale, CA 94086 +S: USA + N: Henrik Storner E: storner@image.dk W: http://www.image.dk/~storner/ diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 890e17086119..e8ad07be6418 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -5490,6 +5490,31 @@ CONFIG_COSA The module will be called cosa.o. For general information about modules read Documentation/modules.txt. +Lan Media sync serial boards support +CONFIG_LANMEDIA + This is a driver for the following Lan Media family of serial boards. + + LMC 1000 board allows you to connect synchronous serial devices (for + example base-band modems, or any other device with the X.21, V.24, + V.35 or V.36 interface) to your Linux box. + + LMC 1200 with on board DSU board allows you to connect your Linux + box dirrectly to a T1 or E1 circuit. + + LMC 5200 board provides a HSSI interface capable of runnig up to + 52 mbits per second. + + LMC 5245 board connects directly to a T3 circuit saving the + additional external hardware. + + To change setting such as syncPPP vs cisco HDLC or clock source you + will need lmcctl. It it available at ftp.lanmedia.com. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called lmc.o. For general information about + modules read Documentation/modules.txt. + Red Creek Hardware VPN (EXPERIMENTAL) CONFIG_RCPCI This is a driver for hardware which provides a Virtual Private @@ -10304,11 +10329,16 @@ CONFIG_HISAX_NO_LLC If you have trouble with some ugly exchanges try to select this option. +Disable keypad protocol option +CONFIG_HISAX_NO_KEYPAD + If you like to send special dialstrings including * or # without + using the keypad protocol, select this option. + HiSax Support for german 1TR6 CONFIG_HISAX_1TR6 Enable this if you have a old german 1TR6 line. -HiSax Support for Teles 16.0/8.0 +Teles 16.0/8.0 CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 and many compatibles. @@ -10317,7 +10347,7 @@ CONFIG_HISAX_16_0 different cards, a different D-channel protocol, or non-standard IRQ/port/shmem settings. -HiSax Support for Teles 16.3 or PNP or PCMCIA +Teles 16.3 or PNP or PCMCIA CONFIG_HISAX_16_3 This enables HiSax support for the Teles ISDN-cards S0-16.3 the Teles/Creatix PnP and the Teles PCMCIA. @@ -10326,17 +10356,17 @@ CONFIG_HISAX_16_3 different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Teles PCI +Teles PCI CONFIG_HISAX_TELESPCI This enables HiSax support for the Teles PCI. See Documentation/isdn/README.HiSax on how to configure it. -HiSax Support for Teles S0Box +Teles S0Box CONFIG_HISAX_S0BOX This enables HiSax support for the Teles/Creatix parallel port S0BOX. See Documentation/isdn/README.HiSax on how to configure it. -HiSax Support for AVM A1 (Fritz) +AVM A1 (Fritz) CONFIG_HISAX_AVM_A1 This enables HiSax support for the AVM A1 (aka "Fritz"). @@ -10344,17 +10374,17 @@ CONFIG_HISAX_AVM_A1 different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for AVM PnP/PCI (Fritz!PNP/PCI) +AVM PnP/PCI (Fritz!PNP/PCI) CONFIG_HISAX_FRITZPCI This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". See Documentation/isdn/README.HiSax on how to configure it. -HiSax Support for AVM A1 PCMCIA (Fritz) +AVM A1 PCMCIA (Fritz) CONFIG_HISAX_AVM_A1_PCMCIA This enables HiSax support for the AVM A1 "Fritz!PCMCIA"). See Documentation/isdn/README.HiSax on how to configure it. -HiSax Support for Elsa cards +Elsa cards CONFIG_HISAX_ELSA This enables HiSax support for the Elsa Mircolink ISA cards, for the Elsa Quickstep series cards and Elsa PCMCIA. @@ -10363,7 +10393,7 @@ CONFIG_HISAX_ELSA different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for ITK ix1-micro Revision 2 +ITK ix1-micro Revision 2 CONFIG_HISAX_IX1MICROR2 This enables HiSax support for the ITK ix1-micro Revision 2 card. @@ -10371,7 +10401,7 @@ CONFIG_HISAX_IX1MICROR2 different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Eicon.Diehl Diva cards +Eicon.Diehl Diva cards CONFIG_HISAX_DIEHLDIVA This enables HiSax support for the Eicon.Diehl Diva none PRO versions passive ISDN cards. @@ -10380,16 +10410,16 @@ CONFIG_HISAX_DIEHLDIVA different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for ASUSCOM cards +ASUSCOM ISA cards CONFIG_HISAX_ASUSCOM This enables HiSax support for the AsusCom and their OEM versions - passive ISDN cards. + passive ISDN ISA cards. See Documentation/isdn/README.HiSax on how to configure it using the different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for TELEINT cards +TELEINT cards CONFIG_HISAX_TELEINT This enables HiSax support for the TELEINT SA1 semiactiv ISDN card. @@ -10397,7 +10427,7 @@ CONFIG_HISAX_TELEINT different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for HFC-S based cards +HFC-S based cards CONFIG_HISAX_HFCS This enables HiSax support for the HFC-S 2BDS0 based cards, like teles 16.3c. @@ -10406,7 +10436,7 @@ CONFIG_HISAX_HFCS different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Sedlbauer cards +Sedlbauer cards CONFIG_HISAX_SEDLBAUER This enables HiSax support for the Sedlbauer passive ISDN cards. @@ -10414,21 +10444,21 @@ CONFIG_HISAX_SEDLBAUER different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for USR Sportster internal TA +USR Sportster internal TA CONFIG_HISAX_SPORTSTER This enables HiSax support for the USR Sportster internal TA card. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for MIC card +MIC card CONFIG_HISAX_MIC This enables HiSax support for the ITH MIC card. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for NETjet card +NETjet card CONFIG_HISAX_NETJET This enables HiSax support for the NetJet from Traverse Technologies. @@ -10436,62 +10466,67 @@ CONFIG_HISAX_NETJET See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Niccy PnP/PCI card +Niccy PnP/PCI card CONFIG_HISAX_NICCY This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Siemens I-Surf card +Siemens I-Surf card CONFIG_HISAX_ISURF This enables HiSax support for the Siemens I-Talk/I-Surf card with ISAR chip. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for HST Saphir card +HST Saphir card CONFIG_HISAX_HSTSAPHIR This enables HiSax support for the HST Saphir card. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Telekom A4T card +Telekom A4T card CONFIG_HISAX_BKM_A4T This enables HiSax support for the Telekom A4T card. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Scitel Quadro card +Scitel Quadro card CONFIG_HISAX_SCT_QUADRO This enables HiSax support for the Scitel Quadro card. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Gazel cards +Gazel cards CONFIG_HISAX_GAZEL This enables HiSax support for the Gazel cards. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for HFC PCI-Bus cards +HFC PCI-Bus cards CONFIG_HISAX_HFC_PCI This enables HiSax support for the HFC-S PCI 2BDS0 based cards. For more informations see under Documentation/isdn/README.hfc-pci. -HiSax Support for Winbond W6692 based cards +Winbond W6692 based cards CONFIG_HISAX_W6692 This enables HiSax support for Winbond W6692 based PCI ISDN cards. See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Am7930 (EXPERIMENTAL) +HFC-S+, HFC-SP, HFC-PCMCIA cards (EXPERIMENTAL) +CONFIG_HISAX_HFC_SX + This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA cards. + This code is not finished yet. + +Am7930 (EXPERIMENTAL) CONFIG_HISAX_AMD7930 This enables HiSax support for the AMD7930 chips on some SPARCs. This code is not finished yet. @@ -11248,11 +11283,6 @@ CONFIG_RADIO_RTRACK2 Choose Y here if you have this FM radio card, and then fill in the port address below. - If you have GemTeks combined (PnP) sound- and radio card you must use - this driver as a module and setup the card with isapnptools. You must - also pass the module a suitable io parameter, 0x248 has been reported - to be used by these cards. - In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at @@ -11436,6 +11466,12 @@ CONFIG_RADIO_GEMTEK Choose Y here if you have this FM radio card, and then fill in the port address below. + If you have GemTeks combined (PnP) sound- and radio card you might want + to use this driver as a module and setup the card with isapnptools. You + must also pass the module a suitable io parameter. If you have trouble + getting the driver to work with the card as a module, please try building + it into the kernel by answering Y. + In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at @@ -11450,8 +11486,9 @@ CONFIG_RADIO_GEMTEK GemTek i/o port CONFIG_RADIO_GEMTEK_PORT - Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is - 0x34c, if you haven't changed the jumper setting on the card. + Enter either 0x20c, 0x30c, 0x24c or 0x34c here. 0x20c and 0x248 have + been reported to work with the combined sound/radio card. The card + default is 0x34c, if you haven't changed the jumper setting on the card. Trust FM Radio Card CONFIG_RADIO_TRUST diff --git a/Documentation/isdn/README.HiSax b/Documentation/isdn/README.HiSax index ee95d85f4147..0416782255fc 100644 --- a/Documentation/isdn/README.HiSax +++ b/Documentation/isdn/README.HiSax @@ -64,6 +64,7 @@ Scitel Quadro Gazel ISDN cards HFC-PCI based cards Winbond W6692 based cards +HFC-S+, HFC-SP/PCMCIA cards Note: PCF, PCF-Pro: up to now, only the ISDN part is supported PCC-8: not tested yet @@ -72,6 +73,7 @@ Note: PCF, PCF-Pro: up to now, only the ISDN part is supported Teles PCI is EXPERIMENTAL Teles S0Box is EXPERIMENTAL Eicon.Diehl Diva U interface not tested + HFC-S+, HFC-SP/PCMCIA are experimental If you know other passive cards with the Siemens chipset, please let me know. To use the PNP cards you need the isapnptools. @@ -184,6 +186,7 @@ Card types: 34 Gazel ISDN cards (PCI) none 35 HFC 2BDS0 PCI none 36 W6692 based PCI cards none + 37 HFC 2BDS0 S+, SP/PCMCIA irq,io (pcmcia must be set with cardmgr) At the moment IRQ sharing is only possible with PCI cards. Please make sure @@ -288,6 +291,7 @@ type 34 Gazel ISDN cards (PCI) no parameter 35 HFC 2BDS0 PCI no parameter 36 W6692 based PCI cards none + 37 HFC 2BDS0 S+,SP/PCMCIA pa=irq, pb=io Running the driver ------------------ diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt new file mode 100644 index 000000000000..44c31defb36c --- /dev/null +++ b/Documentation/networking/bonding.txt @@ -0,0 +1,128 @@ +Installation: + +Apply patch. (if your reading this in +/usr/src/linux/Documentation/network/bonding.txt, then it's already +applied.) + +Run make menuconfig/xconfig/config, and select 'bonding device' in +network devices. + +Build the new kernel/modules. + +Get update ifenslave.c (included in tar file.) (location to be determined.) + +install ifenslave.c; do: + gcc -O2 -o ifenslave ifenslave.c + cp ifenslave /sbin/ifenslave + +Modify /etc/conf.modules by adding the line: + alias bond0 bonding + +If you running a RH5.0 or newer distribution, do: + +cd /etc/sysconfig/network-scripts +cp ifcfg-eth0 ifcfg-bond0 +edit ifcfg-bond0, and make it look the following: + +DEVICE=bond0 +USERCTL=no +ONBOOT=yes +BOOTPROTO=none +BROADCAST=XXX.XXX.XXX.255 +NETWORK=XXX.XXX.XXX.0 +NETMASK=255.255.255.0 +IPADDR=XXX.XXX.XXX.XXX + +(put the approiate values for you network in where the XXX's are at.) + +Then, edit ifcfg-eth0/ifcfg-eth1 (and all the other slave devices), and make them +look like this: + +DEVICE=eth0 +USERCTL=no +ONBOOT=yes +MASTER=bond0 +SLAVE=yes +BOOTPROTO=none + +Reboot, and the network should come up bonded together. + +For other distributions, you need to do something like: + +/sbin/ifconfig bond0 addresss netmask xxx.xxx.xxx.xxx broadcast xxx.xxx.xxx.xxx up +/sbin/ifenslave bond0 eth0 +/sbin/ifenslave bond0 eth1 + +When properly configured, it will look this: + +[root]# /sbin/ifconfig +bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 + inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 + UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 + RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0 + TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0 + collisions:0 txqueuelen:0 + +eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 + inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 + UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 + RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 + TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 + collisions:0 txqueuelen:100 + Interrupt:10 Base address:0x1080 + +eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 + inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 + UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 + RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 + TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + Interrupt:9 Base address:0x1400 + +Questions: + +1. Is it SMP safe? + + Yes. The old 2.0.xx channel bonding patch wasn't SMP safe. +This one was designed from the start to be SMP safe. + +2. What type of cards can it work with it? + + Any Ethernet type cards (ie, you can even mix cards - a tulip +and a 3com 3c905, for example). You can even bond together Gigabit +Ethernet cards! + +3. How many bond devices can I have? + + Just one at this time. + +4. How many slaves can a bond device have? + + Limited by the number of cards you can place in your system. + +5. What happens when a slave dies? + + Currently, the ethernet drivers don't really handle this +situation very well. The tulip driver never stalls; it just starts to +throw packets away! + +6. If this was fixed, can bonding be used for High Availability? + + Yes! + +7. Which switches/systems does it work with? + + Cisco 5500 series (look for EtherChannel support). + SunTrunking software. + +8. Where does the bond0 device get it's mac address from? + + It's taken from the first slave device. If you remove that +first slave device, the MAC address continues to be associated with +it. If you wish to remove that MAC address, you have to ifconfig +bond0 down, and then modprobe -r bonding. If you wish, you can also +assign a MAC address when you ifconfig the bond0 device. + +9. Which transmit policy is used? + + Round robin, based on order of enslaving. \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index 315991534942..76ec2ba2260d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -476,6 +476,12 @@ L: nfs-devel@linux.kernel.org (Linux NFS) W: http://csua.berkeley.edu/~gam3/knfsd S: Maintained +LANMEDIA WAN CARD DRIVER +P: Andrew Stanley-Jones +M: asj@lanmedia.com +W: http://www.lanmedia.com/ +S: Supported + LAPB module P: Henner Eisen M: eis@baty.hanse.de diff --git a/Makefile b/Makefile index 9656f087af2b..e1652de79499 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 15 -EXTRAVERSION = pre4 +EXTRAVERSION = pre5 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 552265f116ff..fa1d8cd410e6 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -608,6 +608,7 @@ prom_init(int r3, int r4, prom_entry pp) else prom_print(RELOC("...failed\n")); } +#endif /* CONFIG_SMP */ /* If OpenFirmware version >= 3, then use quiesce call */ if (RELOC(prom_version) >= 3) { @@ -617,7 +618,6 @@ prom_init(int r3, int r4, prom_entry pp) phys = offset + KERNELBASE; } -#endif return phys; } diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index fd1ff6a0b62c..0d28d1ef0194 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -1,4 +1,4 @@ -/* $Id: sys32.S,v 1.8 1998/10/28 08:10:37 jj Exp $ +/* $Id: sys32.S,v 1.8.2.1 2000/01/24 11:36:55 jj Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * @@ -20,7 +20,7 @@ sys32_mmap: .align 32 .globl sys32_lseek - .globl sys32_chmod, sys32_chown, sys32_lchown, sys32_mknod + .globl sys32_chmod, sys32_mknod sys32_lseek: sra %o1, 0, %o1 sethi %hi(sys_lseek), %g1 @@ -32,20 +32,6 @@ sys32_chmod: orcc %g2, %lo(0xffff), %g2 jmpl %g1 + %lo(sys_chmod), %g0 and %o1, %g2, %o1 -sys32_chown: - sethi %hi(0xffff), %g2 - sethi %hi(sys_chown), %g1 - orcc %g2, %lo(0xffff), %g2 - and %o1, %g2, %o1 - jmpl %g1 + %lo(sys_chown), %g0 - and %o2, %g2, %o2 -sys32_lchown: - sethi %hi(0xffff), %g2 - sethi %hi(sys_lchown), %g1 - orcc %g2, %lo(0xffff), %g2 - and %o1, %g2, %o1 - jmpl %g1 + %lo(sys_lchown), %g0 - and %o2, %g2, %o2 sys32_mknod: sethi %hi(0xffff), %g2 sethi %hi(sys_mknod), %g1 diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index b142fd21460b..4f0e4a29e65d 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.107.2.5 1999/11/12 11:17:47 davem Exp $ +/* $Id: sys_sparc32.c,v 1.107.2.7 2000/01/24 11:36:50 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1890,15 +1890,14 @@ sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) return ret; } +#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid) +#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid) + extern asmlinkage int sys_setreuid(uid_t ruid, uid_t euid); asmlinkage int sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) { - uid_t sruid, seuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - return sys_setreuid(sruid, seuid); + return sys_setreuid(low2highuid(ruid), low2highuid(euid)); } extern asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); @@ -1907,12 +1906,7 @@ asmlinkage int sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, __kernel_uid_t32 suid) { - uid_t sruid, seuid, ssuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); - return sys_setresuid(sruid, seuid, ssuid); + return sys_setresuid(low2highuid(ruid), low2highuid(euid), low2highuid(suid)); } extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); @@ -1935,11 +1929,7 @@ extern asmlinkage int sys_setregid(gid_t rgid, gid_t egid); asmlinkage int sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) { - gid_t srgid, segid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - return sys_setregid(srgid, segid); + return sys_setregid(low2highgid(rgid), low2highgid(egid)); } extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); @@ -1948,12 +1938,7 @@ asmlinkage int sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, __kernel_gid_t32 sgid) { - gid_t srgid, segid, ssgid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); - return sys_setresgid(srgid, segid, ssgid); + return sys_setresgid(low2highgid(rgid), low2highgid(egid), low2highgid(sgid)); } extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); @@ -1975,6 +1960,25 @@ asmlinkage int sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, _ return ret; } +extern asmlinkage long sys_chown(const char *, uid_t,gid_t); +extern asmlinkage long sys_lchown(const char *, uid_t,gid_t); +extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t); + +asmlinkage long sys32_chown16(const char * filename, u16 user, u16 group) +{ + return sys_chown(filename, low2highuid(user), low2highgid(group)); +} + +asmlinkage long sys32_lchown16(const char * filename, u16 user, u16 group) +{ + return sys_lchown(filename, low2highuid(user), low2highgid(group)); +} + +asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group) +{ + return sys_fchown(fd, low2highuid(user), low2highgid(group)); +} + struct tms32 { __kernel_clock_t32 tms_utime; __kernel_clock_t32 tms_stime; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 0e73485dd866..4f1cb7577f4a 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.53.2.1 1999/09/22 11:37:39 jj Exp $ +/* $Id: systbls.S,v 1.53.2.3 2000/01/24 22:14:40 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -21,8 +21,8 @@ sys_call_table32: /*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link -/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod -/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod +/*15*/ .word sys32_chmod, sys32_lchown16, sparc_brk, sys_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice @@ -43,7 +43,7 @@ sys_call_table32: .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall /*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd -/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod +/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod .word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate /*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_nis_syscall @@ -143,7 +143,7 @@ sunos_sys_table: .word sys_close, sunos_wait4, sys_creat .word sys_link, sys_unlink, sunos_execv .word sys_chdir, sunos_nosys, sys32_mknod - .word sys32_chmod, sys32_lchown, sunos_brk + .word sys32_chmod, sys32_lchown16, sunos_brk .word sunos_nosys, sys32_lseek, sunos_getpid .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_getuid, sunos_nosys, sys_ptrace @@ -179,7 +179,7 @@ sunos_sys_table: .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg .word sunos_nosys, sys32_gettimeofday, sys32_getrusage .word sunos_getsockopt, sunos_nosys, sunos_readv - .word sunos_writev, sys32_settimeofday, sys_fchown + .word sunos_writev, sys32_settimeofday, sys32_fchown16 .word sys_fchmod, sys32_recvfrom, sys32_setreuid .word sys_setregid, sys_rename, sys_truncate .word sys_ftruncate, sys_flock, sunos_nosys diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index a34282f5b8ae..6a63a001204b 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -2567,14 +2567,51 @@ int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock) return cdrom_lockdoor (drive, lock, NULL); } +/* + * the buffer struct used by ide_cdrom_get_capabilities() + */ +struct get_capabilities_buf { + char pad[8]; + struct atapi_capabilities_page cap; /* this is 4 bytes short of ATAPI standard */ + char extra_cap[4]; /* Acer 50X needs the regulation size buffer */ +}; + +static +int ide_cdrom_get_capabilities (ide_drive_t *drive, struct get_capabilities_buf *buf) +{ + int stat, attempts = 3, buflen = sizeof(*buf); + + /* + * Most drives don't care about the buffer size; they return as much info as there's room for. + * But some older drives (?) had trouble with the standard size, preferring 4 bytes less. + * And the modern Acer 50X rejects anything smaller than the standard size. + */ + if (!(drive->id && !strcmp(drive->id->model,"ATAPI CD ROM DRIVE 50X MAX"))) + buflen -= sizeof(buf->extra_cap); /* for all drives except Acer 50X */ + + do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, (char *)buf, buflen, NULL); + if (stat == 0) { + /* + * The ACER/AOpen 24X cdrom has the speed fields byte-swapped from the standard. + */ + if (!(drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4))) { + buf->cap.curspeed = ntohs(buf->cap.curspeed); + buf->cap.maxspeed = ntohs(buf->cap.maxspeed); + } + CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf->cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS(drive)->max_speed = (((unsigned int)buf->cap.maxspeed) + (176/2)) / 176; + return 0; + } + } while (--attempts); + return stat; +} + static int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) { - int stat, attempts = 3; - struct { - char pad[8]; - struct atapi_capabilities_page cap; - } buf; + int stat; + struct get_capabilities_buf buf; ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct atapi_request_sense reqbuf; stat=cdrom_select_speed (drive, speed, &reqbuf); @@ -2582,25 +2619,9 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) return stat; /* Now with that done, update the speed fields */ - do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ - if (attempts-- <= 0) - return 0; - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, - (char *)&buf, sizeof (buf), NULL); - } while (stat); - - /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ - if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { - CDROM_STATE_FLAGS (drive)->current_speed = - (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = - (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; - } else { - CDROM_STATE_FLAGS (drive)->current_speed = - (ntohs(buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = - (ntohs(buf.cap.maxspeed) + (176/2)) / 176; - } + if (ide_cdrom_get_capabilities(drive,&buf)) + return 0; + cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed; return 0; } @@ -2894,11 +2915,8 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) static int ide_cdrom_probe_capabilities (ide_drive_t *drive) { - int stat, nslots = 0, attempts = 3; - struct { - char pad[8]; - struct atapi_capabilities_page cap; - } buf; + int stat, nslots = 0; + struct get_capabilities_buf buf; if (CDROM_CONFIG_FLAGS (drive)->nec260) { CDROM_CONFIG_FLAGS (drive)->no_eject = 0; @@ -2906,13 +2924,8 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) return nslots; } - do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ - if (attempts-- <= 0) - return 0; - stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, - (char *)&buf, sizeof (buf), NULL); - } while (stat); - + if (ide_cdrom_get_capabilities(drive,&buf)) + return 0; if (buf.cap.lock == 0) CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1; if (buf.cap.eject) @@ -2955,19 +2968,6 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) } } - /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ - if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { - CDROM_STATE_FLAGS (drive)->current_speed = - (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = - (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; - } else { - CDROM_STATE_FLAGS (drive)->current_speed = - (ntohs(buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = - (ntohs(buf.cap.maxspeed) + (176/2)) / 176; - } - printk ("%s: ATAPI %dX %s", drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed, (CDROM_CONFIG_FLAGS (drive)->dvd) ? "DVD-ROM" : "CD-ROM"); diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 0f41b4da2b03..243ba23a7858 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -279,6 +279,7 @@ static int do_probe (ide_drive_t *drive, byte cmd) drive->name, drive->present, drive->media, (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI"); #endif + delay_50ms(); /* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */ SELECT_DRIVE(hwif,drive); delay_50ms(); if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) { diff --git a/drivers/char/Config.in b/drivers/char/Config.in index d44592186e9d..c28389334f71 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -141,7 +141,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then - hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c + hex ' GemTek i/o port (0x20c, 0x24c, 0x248, 0x30c, or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi dep_tristate 'Trust FM Radio' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_TRUST" = "y" ]; then diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 3c4190ab7bfe..21f5635af4fc 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1094,7 +1094,9 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file, nr -= num; if (nr == 0) break; + current->state = TASK_RUNNING; get_user(c, b); + current->state = TASK_INTERRUPTIBLE; if (opost(c, tty) < 0) break; b++; nr--; @@ -1102,7 +1104,9 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file, if (tty->driver.flush_chars) tty->driver.flush_chars(tty); } else { + current->state = TASK_RUNNING; c = tty->driver.write(tty, 1, b, nr); + current->state = TASK_INTERRUPTIBLE; if (c < 0) { retval = c; goto break_out; diff --git a/drivers/char/radio-gemtek.c b/drivers/char/radio-gemtek.c index 717ccbdbae0a..b89b5f88e861 100644 --- a/drivers/char/radio-gemtek.c +++ b/drivers/char/radio-gemtek.c @@ -282,7 +282,7 @@ __initfunc(int gemtek_init(struct video_init *v)) MODULE_AUTHOR("Jonas Munsin"); MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (or 0x248 for the combined sound/radiocard))"); +MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard))."); EXPORT_NO_SYMBOLS; @@ -290,7 +290,7 @@ int init_module(void) { if(io==-1) { - printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (or io=0x248 for the combined sound/radiocard)\n"); + printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x20c or io=0x248 for the combined sound/radiocard)\n"); return -EINVAL; } return gemtek_init(NULL); diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 64422d49690f..c4c073691975 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -12,68 +12,87 @@ bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then bool ' Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX fi -bool ' Support isdn diversion services' CONFIG_ISDN_DIVERSION if [ "$CONFIG_X25" != "n" ]; then bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25 fi -dep_tristate ' ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN -dep_tristate ' isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN -dep_tristate ' PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN -dep_tristate ' HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN + +mainmenu_option next_comment +comment 'ISDN feature submodules' + dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN + bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION +endmenu + +comment 'low-level hardware drivers' + +mainmenu_option next_comment +comment 'Passive ISDN cards' +dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then - bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO + comment ' D-channel protocol features' + bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO if [ "$CONFIG_HISAX_EURO" != "n" ]; then - bool ' Support for german chargeinfo' CONFIG_DE_AOC - bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE - bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC + bool ' Support for german chargeinfo' CONFIG_DE_AOC + bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE + bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC + bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD fi - bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 - bool ' HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0 - bool ' HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 - bool ' HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI - bool ' HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX - bool ' HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1 - bool ' HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI - bool ' HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA - bool ' HiSax Support for Elsa cards' CONFIG_HISAX_ELSA - bool ' HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2 - bool ' HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA - bool ' HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM - bool ' HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT - bool ' HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS - bool ' HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER - bool ' HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER - bool ' HiSax Support for MIC card' CONFIG_HISAX_MIC - bool ' HiSax Support for NETjet card' CONFIG_HISAX_NETJET - bool ' HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY - bool ' HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF - bool ' HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR - bool ' HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T - bool ' HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO - bool ' HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL - bool ' HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI - bool ' HiSax Support for Winbond W6692 based cards' CONFIG_HISAX_W6692 + bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 + comment ' HiSax supported cards' + bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0 + bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 + bool ' Teles PCI' CONFIG_HISAX_TELESPCI + bool ' Teles S0Box' CONFIG_HISAX_S0BOX + bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1 + bool ' AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI + bool ' AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA + bool ' Elsa cards' CONFIG_HISAX_ELSA + bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2 + bool ' Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA + bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM + bool ' TELEINT cards' CONFIG_HISAX_TELEINT + bool ' HFC-S based cards' CONFIG_HISAX_HFCS + bool ' Sedlbauer cards' CONFIG_HISAX_SEDLBAUER + bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER + bool ' MIC card' CONFIG_HISAX_MIC + bool ' NETjet card' CONFIG_HISAX_NETJET + bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY + bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF + bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR + bool ' Telekom A4T card' CONFIG_HISAX_BKM_A4T + bool ' Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO + bool ' Gazel cards' CONFIG_HISAX_GAZEL + bool ' HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI + bool ' Winbond W6692 based cards' CONFIG_HISAX_W6692 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then -# bool ' HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU + bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX +# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - bool ' HiSax Support for Am7930' CONFIG_HISAX_AMD7930 + bool ' Am7930' CONFIG_HISAX_AMD7930 fi fi fi +endmenu + +mainmenu_option next_comment +comment 'Active ISDN cards' +dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN +dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - dep_tristate ' Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN - dep_tristate ' IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN + dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN + dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN fi -dep_tristate ' Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN +dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then - bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA fi -dep_tristate ' AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN +dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then - bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA - bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI - bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA - bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA - bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI - bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON + bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA + bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI + bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA + bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA + bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI + bool ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 + bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON fi +endmenu diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c new file mode 100644 index 000000000000..417707026def --- /dev/null +++ b/drivers/isdn/avmb1/c4.c @@ -0,0 +1,1316 @@ +/* + * $Id: c4.c,v 1.2 2000/01/21 20:52:58 keil Exp $ + * + * Module for AVM C4 card. + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: c4.c,v $ + * Revision 1.2 2000/01/21 20:52:58 keil + * pci_find_subsys as local function for 2.2.X kernel + * + * Revision 1.1 2000/01/20 10:51:37 calle + * Added driver for C4. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "capicmd.h" +#include "capiutil.h" +#include "capilli.h" +#include "avmcard.h" + +static char *revision = "$Revision: 1.2 $"; + +#undef CONFIG_C4_DEBUG +#undef CONFIG_C4_POLLDEBUG + +/* ------------------------------------------------------------- */ + +#ifndef PCI_VENDOR_ID_DEC +#define PCI_VENDOR_ID_DEC 0x1011 +#endif + +#ifndef PCI_DEVICE_ID_DEC_21285 +#define PCI_DEVICE_ID_DEC_21285 0x1065 +#endif + +#ifndef PCI_VENDOR_ID_AVM +#define PCI_VENDOR_ID_AVM 0x1244 +#endif + +#ifndef PCI_DEVICE_ID_AVM_C4 +#define PCI_DEVICE_ID_AVM_C4 0x0800 +#endif + +/* ------------------------------------------------------------- */ + +int suppress_pollack = 0; + +MODULE_AUTHOR("Carsten Paeth "); + +MODULE_PARM(suppress_pollack, "0-1i"); + +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface *di; + +/* ------------------------------------------------------------- */ + +static void c4_dispatch_tx(avmcard *card); + +/* ------------------------------------------------------------- */ + +#define DC21285_DRAM_A0MR 0x40000000 +#define DC21285_DRAM_A1MR 0x40004000 +#define DC21285_DRAM_A2MR 0x40008000 +#define DC21285_DRAM_A3MR 0x4000C000 + +#define CAS_OFFSET 0x88 + +#define DC21285_ARMCSR_BASE 0x42000000 + +#define PCI_OUT_INT_STATUS 0x30 +#define PCI_OUT_INT_MASK 0x34 +#define MAILBOX_0 0x50 +#define MAILBOX_1 0x54 +#define MAILBOX_2 0x58 +#define MAILBOX_3 0x5C +#define DOORBELL 0x60 +#define DOORBELL_SETUP 0x64 + +#define CHAN_1_CONTROL 0x90 +#define CHAN_2_CONTROL 0xB0 +#define DRAM_TIMING 0x10C +#define DRAM_ADDR_SIZE_0 0x110 +#define DRAM_ADDR_SIZE_1 0x114 +#define DRAM_ADDR_SIZE_2 0x118 +#define DRAM_ADDR_SIZE_3 0x11C +#define SA_CONTROL 0x13C +#define XBUS_CYCLE 0x148 +#define XBUS_STROBE 0x14C +#define DBELL_PCI_MASK 0x150 +#define DBELL_SA_MASK 0x154 + +#define SDRAM_SIZE 0x1000000 + +/* ------------------------------------------------------------- */ + +#define MBOX_PEEK_POKE MAILBOX_0 + +#define DBELL_ADDR 0x01 +#define DBELL_DATA 0x02 +#define DBELL_RNWR 0x40 +#define DBELL_INIT 0x80 + +/* ------------------------------------------------------------- */ + +#define MBOX_UP_ADDR MAILBOX_0 +#define MBOX_UP_LEN MAILBOX_1 +#define MBOX_DOWN_ADDR MAILBOX_2 +#define MBOX_DOWN_LEN MAILBOX_3 + +#define DBELL_UP_HOST 0x00000100 +#define DBELL_UP_ARM 0x00000200 +#define DBELL_DOWN_HOST 0x00000400 +#define DBELL_DOWN_ARM 0x00000800 +#define DBELL_RESET_HOST 0x40000000 +#define DBELL_RESET_ARM 0x80000000 + +/* ------------------------------------------------------------- */ + +#define DRAM_TIMING_DEF 0x001A01A5 +#define DRAM_AD_SZ_DEF0 0x00000045 +#define DRAM_AD_SZ_NULL 0x00000000 + +#define SA_CTL_ALLRIGHT 0x64AA0271 + +#define INIT_XBUS_CYCLE 0x100016DB +#define INIT_XBUS_STROBE 0xF1F1F1F1 + +/* ------------------------------------------------------------- */ + +#define RESET_TIMEOUT (15*HZ) /* 15 sec */ +#define PEEK_POKE_TIMEOUT (HZ/10) /* 0.1 sec */ + +/* ------------------------------------------------------------- */ + +#define c4outmeml(addr, value) writel(value, addr) +#define c4inmeml(addr) readl(addr) +#define c4outmemw(addr, value) writew(value, addr) +#define c4inmemw(addr) readw(addr) +#define c4outmemb(addr, value) writeb(value, addr) +#define c4inmemb(addr) readb(addr) + +/* ------------------------------------------------------------- */ + +static inline int wait_for_doorbell(avmcard *card, unsigned long t) +{ + unsigned long stop; + + stop = jiffies + t; + while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { + if (!time_before(jiffies, stop)) + return -1; + } + return 0; +} + +static int c4_poke(avmcard *card, unsigned long off, unsigned long value) +{ + + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + c4outmeml(card->mbase+MBOX_PEEK_POKE, off); + c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); + + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + c4outmeml(card->mbase+MBOX_PEEK_POKE, value); + c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR); + + return 0; +} + +static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep) +{ + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + c4outmeml(card->mbase+MBOX_PEEK_POKE, off); + c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR); + + if (wait_for_doorbell(card, HZ/10) < 0) + return -1; + + *valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE); + + return 0; +} + +/* ------------------------------------------------------------- */ + +static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file) +{ + __u32 val; + unsigned char *dp; + int left, retval; + __u32 loadoff = 0; + + dp = t4file->data; + left = t4file->len; + while (left >= sizeof(__u32)) { + if (t4file->user) { + retval = copy_from_user(&val, dp, sizeof(val)); + if (retval) + return -EFAULT; + } else { + memcpy(&val, dp, sizeof(val)); + } + if (c4_poke(card, loadoff, val)) { + printk(KERN_ERR "%s: corrupted firmware file ?\n", + card->name); + return -EIO; + } + left -= sizeof(__u32); + dp += sizeof(__u32); + loadoff += sizeof(__u32); + } + if (left) { + val = 0; + if (t4file->user) { + retval = copy_from_user(&val, dp, left); + if (retval) + return -EFAULT; + } else { + memcpy(&val, dp, left); + } + if (c4_poke(card, loadoff, val)) { + printk(KERN_ERR "%s: corrupted firmware file ?\n", + card->name); + return -EIO; + } + } + return 0; +} + +/* ------------------------------------------------------------- */ + +static inline void _put_byte(void **pp, __u8 val) +{ + __u8 *s = *pp; + *s++ = val; + *pp = s; +} + +static inline void _put_word(void **pp, __u32 val) +{ + __u8 *s = *pp; + *s++ = val & 0xff; + *s++ = (val >> 8) & 0xff; + *s++ = (val >> 16) & 0xff; + *s++ = (val >> 24) & 0xff; + *pp = s; +} + +static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) +{ + unsigned i = len; + _put_word(pp, i); + while (i-- > 0) + _put_byte(pp, *dp++); +} + +static inline __u8 _get_byte(void **pp) +{ + __u8 *s = *pp; + __u8 val; + val = *s++; + *pp = s; + return val; +} + +static inline __u32 _get_word(void **pp) +{ + __u8 *s = *pp; + __u32 val; + val = *s++; + val |= (*s++ << 8); + val |= (*s++ << 16); + val |= (*s++ << 24); + *pp = s; + return val; +} + +static inline __u32 _get_slice(void **pp, unsigned char *dp) +{ + unsigned int len, i; + + len = i = _get_word(pp); + while (i-- > 0) *dp++ = _get_byte(pp); + return len; +} + +/* ------------------------------------------------------------- */ + +static void c4_reset(avmcard *card) +{ + unsigned long stop; + + c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); + + stop = jiffies + HZ*10; + while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { + if (!time_before(jiffies, stop)) + return; + c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); + } + + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); +} + +/* ------------------------------------------------------------- */ + +static int c4_detect(avmcard *card) +{ + unsigned long stop, dummy; + + c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); + if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c) + return 1; + + c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); + + stop = jiffies + HZ*10; + while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { + if (!time_before(jiffies, stop)) + return 2; + c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); + } + + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); + c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); + + c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa); + if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3; + + c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55); + if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4; + + if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5; + if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6; + if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT)) + return 7; + if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE)) + return 8; + if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE)) + return 8; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9; + + udelay(1000); + + if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10; + if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11; + if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12; + if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13; + + if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14; + if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15; + if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16; + if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17; + + udelay(1000); + + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF)) + return 18; + + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0)) + return 19; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL)) + return 20; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL)) + return 21; + if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL)) + return 22; + + /* Transputer test */ + + if ( c4_poke(card, 0x000000, 0x11111111) + || c4_poke(card, 0x400000, 0x22222222) + || c4_poke(card, 0x800000, 0x33333333) + || c4_poke(card, 0xC00000, 0x44444444)) + return 23; + + if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111 + || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222 + || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333 + || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444) + return 24; + + if ( c4_poke(card, 0x000000, 0x55555555) + || c4_poke(card, 0x400000, 0x66666666) + || c4_poke(card, 0x800000, 0x77777777) + || c4_poke(card, 0xC00000, 0x88888888)) + return 25; + + if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555 + || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666 + || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777 + || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888) + return 26; + + return 0; +} + +/* ------------------------------------------------------------- */ + +static void c4_dispatch_tx(avmcard *card) +{ + avmcard_dmainfo *dma = card->dma; + unsigned long flags; + struct sk_buff *skb; + __u8 cmd, subcmd; + __u16 len; + __u32 txlen; + void *p; + + save_flags(flags); + cli(); + + if (card->csr & DBELL_DOWN_ARM) { /* tx busy */ + restore_flags(flags); + return; + } + + skb = skb_dequeue(&dma->send_queue); + if (!skb) { +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: tx underrun\n", card->name); +#endif + restore_flags(flags); + return; + } + + len = CAPIMSG_LEN(skb->data); + + if (len) { + cmd = CAPIMSG_COMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); + + p = dma->sendbuf; + + if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { + __u16 dlen = CAPIMSG_DATALEN(skb->data); + _put_byte(&p, SEND_DATA_B3_REQ); + _put_slice(&p, skb->data, len); + _put_slice(&p, skb->data + len, dlen); + } else { + _put_byte(&p, SEND_MESSAGE); + _put_slice(&p, skb->data, len); + } + txlen = (__u8 *)p - (__u8 *)dma->sendbuf; +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); +#endif + } else { + txlen = skb->len-2; +#ifdef CONFIG_C4_POLLDEBUG + if (skb->data[2] == SEND_POLLACK) + printk(KERN_INFO "%s: ack to c4\n", card->name); +#endif +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", + card->name, skb->data[2], txlen); +#endif + memcpy(dma->sendbuf, skb->data+2, skb->len-2); + } + txlen = (txlen + 3) & ~3; + + c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf)); + c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen); + + card->csr |= DBELL_DOWN_ARM; + + c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM); + + restore_flags(flags); + dev_kfree_skb(skb); +} + +/* ------------------------------------------------------------- */ + +static void queue_pollack(avmcard *card) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(3, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost poll ack\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_POLLACK); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +static void c4_handle_rx(avmcard *card) +{ + avmcard_dmainfo *dma = card->dma; + struct capi_ctr *ctrl; + avmctrl_info *cinfo; + struct sk_buff *skb; + void *p = dma->recvbuf; + __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; + __u8 b1cmd = _get_byte(&p); + __u32 cidx; + + +#ifdef CONFIG_C4_DEBUG + printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name, + b1cmd, (unsigned long)dma->recvlen); +#endif + + switch (b1cmd) { + case RECEIVE_DATA_B3_IND: + + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + DataB3Len = _get_slice(&p, card->databuf); + cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + + if (MsgLen < 30) { /* not CAPI 64Bit */ + memset(card->msgbuf+MsgLen, 0, 30-MsgLen); + MsgLen = 30; + CAPIMSG_SETLEN(card->msgbuf, 30); + } + if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_MESSAGE: + + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + + if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_NEW_NCCI: + + ApplId = _get_word(&p); + NCCI = _get_word(&p); + WindowSize = _get_word(&p); + cidx = (NCCI&0x7f) - card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + + ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); + + break; + + case RECEIVE_FREE_NCCI: + + ApplId = _get_word(&p); + NCCI = _get_word(&p); + + if (NCCI != 0xffffffff) { + cidx = (NCCI&0x7f) - card->cardnr; + if (cidx > 3) cidx = 0; + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->free_ncci(ctrl, ApplId, NCCI); + } else { + for (cidx=0; cidx < 4; cidx++) { + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->appl_released(ctrl, ApplId); + } + } + break; + + case RECEIVE_START: +#ifdef CONFIG_C4_POLLDEBUG + printk(KERN_INFO "%s: poll from c4\n", card->name); +#endif + if (!suppress_pollack) + queue_pollack(card); + for (cidx=0; cidx < 4; cidx++) { + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->resume_output(ctrl); + } + break; + + case RECEIVE_STOP: + for (cidx=0; cidx < 4; cidx++) { + ctrl = card->ctrlinfo[cidx].capi_ctrl; + ctrl->suspend_output(ctrl); + } + break; + + case RECEIVE_INIT: + + cidx = card->nlogcontr++; + cinfo = &card->ctrlinfo[cidx]; + ctrl = cinfo->capi_ctrl; + cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); + b1_parse_version(cinfo); + printk(KERN_INFO "%s: %s-card (%s) now active\n", + card->name, + cinfo->version[VER_CARDTYPE], + cinfo->version[VER_DRIVER]); + ctrl->ready(cinfo->capi_ctrl); + break; + + case RECEIVE_TASK_READY: + ApplId = (unsigned) _get_word(&p); + MsgLen = _get_slice(&p, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: task %d \"%s\" ready.\n", + card->name, ApplId, card->msgbuf); + break; + + case RECEIVE_DEBUGMSG: + MsgLen = _get_slice(&p, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); + break; + + default: + printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n", + card->name, b1cmd); + return; + } +} + +/* ------------------------------------------------------------- */ + +static void c4_handle_interrupt(avmcard *card) +{ + __u32 status = c4inmeml(card->mbase+DOORBELL); + + if (status & DBELL_RESET_HOST) { + int i; + c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); + printk(KERN_ERR "%s: unexpected reset\n", card->name); + for (i=0; i < 4; i++) { + avmctrl_info *cinfo = &card->ctrlinfo[i]; + memset(cinfo->version, 0, sizeof(cinfo->version)); + if (cinfo->capi_ctrl) + cinfo->capi_ctrl->reseted(cinfo->capi_ctrl); + } + return; + } + + status &= (DBELL_UP_HOST | DBELL_DOWN_HOST); + if (!status) + return; + c4outmeml(card->mbase+DOORBELL, status); + + if ((status & DBELL_UP_HOST) != 0) { + card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN); + c4outmeml(card->mbase+MBOX_UP_LEN, 0); + c4_handle_rx(card); + card->dma->recvlen = 0; + c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf)); + c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); + } + + if ((status & DBELL_DOWN_HOST) != 0) { + card->csr &= ~DBELL_DOWN_ARM; + c4_dispatch_tx(card); + } else if (card->csr & DBELL_DOWN_HOST) { + if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) { + card->csr &= ~DBELL_DOWN_ARM; + c4_dispatch_tx(card); + } + } +} + +static void c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "%s: interrupt: wrong device\n", card->name); + return; + } + if (card->interrupt) { + printk(KERN_ERR "%s: reentering interrupt hander\n", + card->name); + return; + } + + card->interrupt = 1; + + c4_handle_interrupt(card); + + card->interrupt = 0; +} + +/* ------------------------------------------------------------- */ + +static void c4_send_init(avmcard *card) +{ + struct sk_buff *skb; + void *p; + + skb = alloc_skb(15, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost register appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_INIT); + _put_word(&p, AVM_NAPPS); + _put_word(&p, AVM_NCCI_PER_CHANNEL*30); + _put_word(&p, card->cardnr - 1); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); +} + +static int c4_send_config(avmcard *card, capiloaddatapart * config) +{ + struct sk_buff *skb; + __u8 val[sizeof(__u32)]; + void *p; + unsigned char *dp; + int left, retval; + + skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, can't send config.\n", + card->name); + return -ENOMEM; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_CONFIG); + _put_word(&p, 1); + _put_byte(&p, SEND_CONFIG); + _put_word(&p, config->len); /* 12 */ + + dp = config->data; + left = config->len; + while (left >= sizeof(__u32)) { + if (config->user) { + retval = copy_from_user(val, dp, sizeof(val)); + if (retval) { + dev_kfree_skb(skb); + return -EFAULT; + } + } else { + memcpy(val, dp, sizeof(val)); + } + _put_byte(&p, SEND_CONFIG); + _put_byte(&p, val[0]); + _put_byte(&p, val[1]); + _put_byte(&p, val[2]); + _put_byte(&p, val[3]); + left -= sizeof(val); + dp += sizeof(val); + } + if (left) { + memset(val, 0, sizeof(val)); + if (config->user) { + retval = copy_from_user(&val, dp, left); + if (retval) { + dev_kfree_skb(skb); + return -EFAULT; + } + } else { + memcpy(&val, dp, left); + } + _put_byte(&p, SEND_CONFIG); + _put_byte(&p, val[0]); + _put_byte(&p, val[1]); + _put_byte(&p, val[2]); + _put_byte(&p, val[3]); + } + + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + + return 0; +} + +static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + unsigned long flags; + int retval; + + if ((retval = c4_load_t4file(card, &data->firmware))) { + printk(KERN_ERR "%s: failed to load t4file!!\n", + card->name); + c4_reset(card); + return retval; + } + + save_flags(flags); + cli(); + + card->csr = 0; + c4outmeml(card->mbase+MBOX_UP_LEN, 0); + c4outmeml(card->mbase+MBOX_DOWN_LEN, 0); + c4outmeml(card->mbase+DOORBELL, DBELL_INIT); + udelay(1000); + c4outmeml(card->mbase+DOORBELL, + DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST); + + c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08); + + card->dma->recvlen = 0; + c4outmeml(card->mbase+MBOX_UP_ADDR, virt_to_phys(card->dma->recvbuf)); + c4outmeml(card->mbase+MBOX_UP_LEN, sizeof(card->dma->recvbuf)); + c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); + restore_flags(flags); + + if (data->configuration.len > 0 && data->configuration.data) + c4_send_config(card, &data->configuration); + + c4_send_init(card); + + return 0; +} + + +void c4_reset_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; + avmctrl_info *cinfo; + int i; + + c4_reset(card); + + for (i=0; i < 4; i++) { + cinfo = &card->ctrlinfo[i]; + memset(cinfo->version, 0, sizeof(cinfo->version)); + if (cinfo->capi_ctrl) + cinfo->capi_ctrl->reseted(cinfo->capi_ctrl); + } +} + +static void c4_remove_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; + avmctrl_info *cinfo; + int i; + + c4_reset(card); + + for (i=0; i <= 4; i++) { + cinfo = &card->ctrlinfo[i]; + if (cinfo->capi_ctrl) + di->detach_ctr(cinfo->capi_ctrl); + } + + free_irq(card->irq, card); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + release_region(card->port, AVMB1_PORTLEN); + ctrl->driverdata = 0; + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + + MOD_DEC_USE_COUNT; +} + +/* ------------------------------------------------------------- */ + + +void c4_register_appl(struct capi_ctr *ctrl, + __u16 appl, + capi_register_params *rp) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + struct sk_buff *skb; + int want = rp->level3cnt; + int nconn; + void *p; + + if (ctrl->cnr == card->cardnr) { + + if (want > 0) nconn = want; + else nconn = ctrl->profile.nbchannel * 4 * -want; + if (nconn == 0) nconn = ctrl->profile.nbchannel * 4; + + skb = alloc_skb(23, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost register appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_REGISTER); + _put_word(&p, appl); + _put_word(&p, 1024 * (nconn+1)); + _put_word(&p, nconn); + _put_word(&p, rp->datablkcnt); + _put_word(&p, rp->datablklen); + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + } + + ctrl->appl_registered(ctrl, appl); +} + +/* ------------------------------------------------------------- */ + +void c4_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + struct sk_buff *skb; + void *p; + + if (ctrl->cnr == card->cardnr) { + skb = alloc_skb(7, GFP_ATOMIC); + if (!skb) { + printk(KERN_CRIT "%s: no memory, lost release appl.\n", + card->name); + return; + } + p = skb->data; + _put_byte(&p, 0); + _put_byte(&p, 0); + _put_byte(&p, SEND_RELEASE); + _put_word(&p, appl); + + skb_put(skb, (__u8 *)p - (__u8 *)skb->data); + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); + } +} + +/* ------------------------------------------------------------- */ + + +static void c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + skb_queue_tail(&card->dma->send_queue, skb); + c4_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +static char *c4_procinfo(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + + if (!cinfo) + return ""; + sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", + cinfo->cardname[0] ? cinfo->cardname : "-", + cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", + cinfo->card ? cinfo->card->port : 0x0, + cinfo->card ? cinfo->card->irq : 0, + cinfo->card ? cinfo->card->membase : 0 + ); + return cinfo->infobuf; +} + +static int c4_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + __u8 flag; + int len = 0; + char *s; + + len += sprintf(page+len, "%-16s %s\n", "name", card->name); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase); + switch (card->cardtype) { + case avm_b1isa: s = "B1 ISA"; break; + case avm_b1pci: s = "B1 PCI"; break; + case avm_b1pcmcia: s = "B1 PCMCIA"; break; + case avm_m1: s = "M1"; break; + case avm_m2: s = "M2"; break; + case avm_t1isa: s = "T1 ISA (HEMA)"; break; + case avm_t1pci: s = "T1 PCI"; break; + case avm_c4: s = "C4"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if ((s = cinfo->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = cinfo->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = cinfo->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[3]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", + "protocol", + (flag & 0x01) ? " DSS1" : "", + (flag & 0x02) ? " CT1" : "", + (flag & 0x04) ? " VN3" : "", + (flag & 0x08) ? " NI1" : "", + (flag & 0x10) ? " AUSTEL" : "", + (flag & 0x20) ? " ESS" : "", + (flag & 0x40) ? " 1TR6" : "" + ); + } + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[5]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s\n", + "linetype", + (flag & 0x01) ? " point to point" : "", + (flag & 0x02) ? " point to multipoint" : "", + (flag & 0x08) ? " leased line without D-channel" : "", + (flag & 0x04) ? " leased line with D-channel" : "" + ); + } + len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/* ------------------------------------------------------------- */ + +static int c4_add_card(struct capi_driver *driver, struct capicardparams *p) +{ + unsigned long page_offset, base; + avmctrl_info *cinfo; + avmcard *card; + int retval; + int i; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + return -ENOMEM; + } + memset(card, 0, sizeof(avmcard)); + card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC); + if (!card->dma) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + kfree(card); + return -ENOMEM; + } + memset(card->dma, 0, sizeof(avmcard_dmainfo)); + cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -ENOMEM; + } + memset(cinfo, 0, sizeof(avmctrl_info)*4); + card->ctrlinfo = cinfo; + for (i=0; i < 4; i++) { + cinfo = &card->ctrlinfo[i]; + cinfo->card = card; + } + sprintf(card->name, "c4-%x", p->port); + card->port = p->port; + card->irq = p->irq; + card->membase = p->membase; + card->cardtype = avm_c4; + + if (check_region(card->port, AVMB1_PORTLEN)) { + printk(KERN_WARNING + "%s: ports 0x%03x-0x%03x in use.\n", + driver->name, card->port, card->port + AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EBUSY; + } + + base = card->membase & PAGE_MASK; + page_offset = card->membase - base; + card->mbase = ioremap_nocache(base, page_offset + 64); + + if ((retval = c4_detect(card)) != 0) { + printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", + driver->name, card->port, retval); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EIO; + } + c4_reset(card); + + request_region(p->port, AVMB1_PORTLEN, card->name); + + retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card); + if (retval) { + printk(KERN_ERR "%s: unable to get IRQ %d.\n", + driver->name, card->irq); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + release_region(card->port, AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EBUSY; + } + + for (i=0; i < 4; i++) { + cinfo = &card->ctrlinfo[i]; + cinfo->card = card; + cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo); + if (!cinfo->capi_ctrl) { + printk(KERN_ERR "%s: attach controller failed (%d).\n", + driver->name, i); + for (i--; i >= 0; i--) { + cinfo = &card->ctrlinfo[i]; + di->detach_ctr(cinfo->capi_ctrl); + } + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card->dma); + kfree(card->ctrlinfo); + kfree(card); + return -EBUSY; + } + if (i == 0) + card->cardnr = cinfo->capi_ctrl->cnr; + } + + skb_queue_head_init(&card->dma->send_queue); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* ------------------------------------------------------------- */ + +static struct capi_driver c4_driver = { + "c4", + "0.0", + c4_load_firmware, + c4_reset_ctr, + c4_remove_ctr, + c4_register_appl, + c4_release_appl, + c4_send_message, + + c4_procinfo, + c4_read_proc, + 0, /* use standard driver_read_proc */ + + 0, /* no add_card function */ +}; + +#ifdef MODULE +#define c4_init init_module +void cleanup_module(void); +#endif + +#ifndef PCI_ANY_ID +#define PCI_ANY_ID (~0) +#endif + +static struct pci_dev * +pci_find_subsys(unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from) +{ + unsigned short subsystem_vendor, subsystem_device; + + while ((from = pci_find_device(vendor, device, from))) { + pci_read_config_word(from, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); + pci_read_config_word(from, PCI_SUBSYSTEM_ID, &subsystem_device); + if ((ss_vendor == PCI_ANY_ID || subsystem_vendor == ss_vendor) && + (ss_device == PCI_ANY_ID || subsystem_device == ss_device)) + return from; + } + return NULL; +} + +static int ncards = 0; + +int c4_init(void) +{ + struct capi_driver *driver = &c4_driver; + struct pci_dev *dev = NULL; + char *p; + int retval; + + if ((p = strchr(revision, ':'))) { + strncpy(driver->revision, p + 1, sizeof(driver->revision)); + p = strchr(driver->revision, '$'); + *p = 0; + } + + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); + + di = attach_capi_driver(driver); + + if (!di) { + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driver->name); + return -EIO; + } + +#ifdef CONFIG_PCI + if (!pci_present()) { + printk(KERN_ERR "%s: no PCI bus present\n", driver->name); + detach_capi_driver(driver); + return -EIO; + } + + while ((dev = pci_find_subsys( + PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, + PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) { + struct capicardparams param; + + param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; + param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK; + + printk(KERN_INFO + "%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n", + driver->name, param.port, param.irq, param.membase); + retval = c4_add_card(driver, ¶m); + if (retval != 0) { + printk(KERN_ERR + "%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n", + driver->name, param.port, param.irq, param.membase); +#ifdef MODULE + cleanup_module(); +#endif + return retval; + } + ncards++; + } + if (ncards) { + printk(KERN_INFO "%s: %d C4 card(s) detected\n", + driver->name, ncards); + return 0; + } + printk(KERN_ERR "%s: NO C4 card detected\n", driver->name); + return -ESRCH; +#else + printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name); + return -EIO; +#endif +} + +#ifdef MODULE +void cleanup_module(void) +{ + detach_capi_driver(&c4_driver); +} +#endif diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index a0ae536bcf50..1758297fe2ed 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.27 1999/11/29 13:12:03 armin Exp $ +/* $Id: eicon_idi.c,v 1.28 2000/01/20 19:55:34 keil Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * IDI interface @@ -26,6 +26,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.28 2000/01/20 19:55:34 keil + * Add FAX Class 1 support + * * Revision 1.27 1999/11/29 13:12:03 armin * Autoconnect on L2_TRANS doesn't work with link_level correctly, * changed back to former mode. @@ -142,7 +145,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.27 $"; +char *eicon_idi_revision = "$Revision: 1.28 $"; eicon_manifbuf *manbuf; @@ -224,7 +227,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = 1; } switch(chan->l3prot) { - case ISDN_PROTO_L3_FAX: + case ISDN_PROTO_L3_FCLASS2: #ifdef CONFIG_ISDN_TTY_FAX reqbuf->XBuffer.P[l++] = 6; reqbuf->XBuffer.P[l++] = NLC; diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index d84def160d96..a75a5c31ac06 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.22 1999/11/27 12:56:19 armin Exp $ +/* $Id: eicon_mod.c,v 1.23 2000/01/20 19:55:34 keil Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * @@ -31,6 +31,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.23 2000/01/20 19:55:34 keil + * Add FAX Class 1 support + * * Revision 1.22 1999/11/27 12:56:19 armin * Forgot some iomem changes for last ioremap compat. * @@ -133,7 +136,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.22 $"; +static char *eicon_revision = "$Revision: 1.23 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -669,7 +672,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c) break; chan->l3prot = (c->arg >> 8); #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l3prot == ISDN_PROTO_L3_FAX) + if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) chan->fax = c->parm.fax; #endif return 0; @@ -1086,7 +1089,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L2_MODEM | ISDN_FEATURE_L2_FAX | ISDN_FEATURE_L3_TRANSDSP | - ISDN_FEATURE_L3_FAX; + ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; card->hwif.pci.PCIreg = pcic->PCIreg; card->hwif.pci.PCIcfg = pcic->PCIcfg; @@ -1110,7 +1113,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L2_MODEM | ISDN_FEATURE_L2_FAX | ISDN_FEATURE_L3_TRANSDSP | - ISDN_FEATURE_L3_FAX; + ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem; card->hwif.pci.PCIreg = pcic->PCIreg; diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index e37d9c404d2d..7bc340de9c9c 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -137,6 +137,10 @@ ifeq ($(CONFIG_HISAX_HFC_PCI),y) HFC_2BDS0 += hfc_pci.o endif +ifeq ($(CONFIG_HISAX_HFC_SX),y) + HFC_2BDS0 += hfc_sx.o +endif + ifeq ($(CONFIG_HISAX_NICCY),y) O_OBJS += niccy.o ISAC_OBJ := isac.o diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index abae1d89c23b..eee955b83c4b 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,14 +1,21 @@ -/* $Id: config.c,v 2.42 1999/12/19 13:09:41 keil Exp $ +/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.43 2000/01/20 19:49:36 keil + * Support teles 13.3c vendor version 2.1 + * * Revision 2.42 1999/12/19 13:09:41 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays * + * Revision 2.41 1999/11/18 00:00:43 werner + * + * Added support for HFC-S+ and HFC-SP cards + * * Revision 2.40 1999/10/30 13:09:45 keil * Version 3.3c * @@ -205,6 +212,7 @@ * 34 Gazel ISDN cards * 35 HFC 2BDS0 PCI none * 36 Winbond 6692 PCI none + * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase * * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * @@ -220,6 +228,7 @@ const char *CardType[] = "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", + "HFC 2BDS0 SX", }; void HiSax_closecard(int cardnr); @@ -355,6 +364,13 @@ EXPORT_SYMBOL(sedl_init_pcmcia); #define DEFAULT_CFG {0,0,0,0} #endif +#ifdef CONFIG_HISAX_HFC_SX +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_HFC_SX +#define DEFAULT_CFG {5,0x2E0,0,0} +#endif + #ifdef CONFIG_HISAX_AMD7930 #undef DEFAULT_CARD @@ -532,9 +548,9 @@ HiSaxVersion(void)) printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3c (module)\n"); + printk(KERN_INFO "HiSax: Version 3.3d (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3c (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); @@ -682,6 +698,10 @@ extern int setup_hfcs(struct IsdnCard *card); extern int setup_hfcpci(struct IsdnCard *card); #endif +#if CARD_HFC_SX +extern int setup_hfcsx(struct IsdnCard *card); +#endif + #if CARD_AMD7930 extern int setup_amd7930(struct IsdnCard *card); #endif @@ -1203,6 +1223,11 @@ checkcard(int cardnr, char *id, int *busy_flag)) ret = setup_hfcpci(card); break; #endif +#if CARD_HFC_SX + case ISDN_CTYPE_HFC_SX: + ret = setup_hfcsx(card); + break; +#endif #if CARD_NICCY case ISDN_CTYPE_NICCY: ret = setup_niccy(card); @@ -1510,6 +1535,7 @@ HiSax_init(void)) case ISDN_CTYPE_FRITZPCI: case ISDN_CTYPE_HSTSAPHIR: case ISDN_CTYPE_GAZEL: + case ISDN_CTYPE_HFC_SX: cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; break; diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c new file mode 100644 index 000000000000..17086d64d8e0 --- /dev/null +++ b/drivers/isdn/hisax/hfc_sx.c @@ -0,0 +1,1584 @@ +/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $ + + * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards + * + * Author Werner Cornelius (werner@isdn4linux.de) + * based on existing driver for CCD HFC PCI cards + * + * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) + * + * 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 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. + * + * $Log: hfc_sx.c,v $ + * Revision 1.3 2000/01/20 19:49:36 keil + * Support teles 13.3c vendor version 2.1 + * + * Revision 1.2 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * + * Revision 1.1 1999/11/18 00:09:18 werner + * + * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM. + * Audio and Echo are supported. + * + * + * + */ + +#include +#define __NO_VERSION__ +#include "hisax.h" +#include "hfc_sx.h" +#include "isdnl1.h" +#include + +extern const char *CardType[]; + +static const char *hfcsx_revision = "$Revision: 1.3 $"; + +/***************************************/ +/* IRQ-table for CCDs demo board */ +/* IRQs 6,5,10,11,12,15 are supported */ +/***************************************/ + +/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1 + * + * Thanks to Uwe Wisniewski + * + * ISA-SLOT Signal PIN + * B25 IRQ3 92 IRQ_G + * B23 IRQ5 94 IRQ_A + * B4 IRQ2/9 95 IRQ_B + * D3 IRQ10 96 IRQ_C + * D4 IRQ11 97 IRQ_D + * D5 IRQ12 98 IRQ_E + * D6 IRQ15 99 IRQ_F + */ + +#undef CCD_DEMO_BOARD +#ifdef CCD_DEMO_BOARD +static u_char ccd_sp_irqtab[16] = { + 0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6 +}; +#else /* Teles 16.3c */ +static u_char ccd_sp_irqtab[16] = { + 0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6 +}; +#endif +#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +/******************************/ +/* In/Out access to registers */ +/******************************/ +static inline void +Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val) +{ register int flags; + + save_flags(flags); + cli(); + byteout(cs->hw.hfcsx.base+1, regnum); + byteout(cs->hw.hfcsx.base, val); + restore_flags(flags); +} + +static inline u_char +Read_hfc(struct IsdnCardState *cs, u_char regnum) +{ register int flags; + register u_char ret; + + save_flags(flags); + cli(); + byteout(cs->hw.hfcsx.base+1, regnum); + ret = bytein(cs->hw.hfcsx.base); + restore_flags(flags); + return(ret); +} + + +/**************************************************/ +/* select a fifo and remember which one for reuse */ +/**************************************************/ +static void +fifo_select(struct IsdnCardState *cs, u_char fifo) +{ int flags; + + if (fifo == cs->hw.hfcsx.last_fifo) + return; /* still valid */ + + save_flags(flags); + cli(); + byteout(cs->hw.hfcsx.base+1, HFCSX_FIF_SEL); + byteout(cs->hw.hfcsx.base, fifo); + while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ + udelay(4); + byteout(cs->hw.hfcsx.base, fifo); + while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ + restore_flags(flags); +} + +/******************************************/ +/* reset the specified fifo to defaults. */ +/* If its a send fifo init needed markers */ +/******************************************/ +static void +reset_fifo(struct IsdnCardState *cs, u_char fifo) +{ int flags; + + save_flags(flags); + cli(); + fifo_select(cs, fifo); /* first select the fifo */ + byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM); + byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */ + udelay(1); + while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ + restore_flags(flags); +} + + +/*************************************************************/ +/* write_fifo writes the skb contents to the desired fifo */ +/* if no space is available or an error occurs 0 is returned */ +/* the skb is not released in any way. */ +/*************************************************************/ +static int +write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max) +{ unsigned short *msp; + int fifo_size, count, z1, z2; + u_char f_msk, f1, f2, *src; + + if (skb->len <= 0) return(0); + if (fifo & 1) return(0); /* no write fifo */ + + fifo_select(cs, fifo); + if (fifo & 4) { + fifo_size = D_FIFO_SIZE; /* D-channel */ + f_msk = MAX_D_FRAMES; + if (trans_max) return(0); /* only HDLC */ + } + else { + fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ + f_msk = MAX_B_FRAMES; + } + + z1 = Read_hfc(cs, HFCSX_FIF_Z1H); + z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); + + /* Check for transparent mode */ + if (trans_max) { + z2 = Read_hfc(cs, HFCSX_FIF_Z2H); + z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); + count = z2 - z1; + if (count <= 0) + count += fifo_size; /* free bytes */ + if (count < skb->len+1) return(0); /* no room */ + count = fifo_size - count; /* bytes still not send */ + if (count > 2 * trans_max) return(0); /* delay to long */ + count = skb->len; + src = skb->data; + while (count--) + Write_hfc(cs, HFCSX_FIF_DWR, *src++); + return(1); /* success */ + } + + msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker; + msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES+1)); + f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; + f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; + + count = f1 - f2; /* frame count actually buffered */ + if (count < 0) + count += (f_msk + 1); /* if wrap around */ + if (count > f_msk-1) { + if (cs->debug & L1_DEB_ISAC_FIFO) + debugl1(cs, "hfcsx_write_fifo %d more as %d frames",fifo,f_msk-1); + return(0); + } + + *(msp + f1) = z1; /* remember marker */ + + if (cs->debug & L1_DEB_ISAC_FIFO) + debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)", + fifo, f1, f2, z1); + /* now determine free bytes in FIFO buffer */ + count = *(msp + f2) - z1; + if (count <= 0) + count += fifo_size; /* count now contains available bytes */ + + if (cs->debug & L1_DEB_ISAC_FIFO) + debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)", + fifo, skb->len, count); + if (count < skb->len) { + if (cs->debug & L1_DEB_ISAC_FIFO) + debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo); + return(0); + } + + count = skb->len; /* get frame len */ + src = skb->data; /* source pointer */ + while (count--) + Write_hfc(cs, HFCSX_FIF_DWR, *src++); + + Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */ + udelay(1); + while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ + return(1); +} + +/***************************************************************/ +/* read_fifo reads data to an skb from the desired fifo */ +/* if no data is available or an error occurs NULL is returned */ +/* the skb is not released in any way. */ +/***************************************************************/ +static struct sk_buff * +read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) +{ int fifo_size, count, z1, z2; + u_char f_msk, f1, f2, *dst; + struct sk_buff *skb; + + if (!(fifo & 1)) return(NULL); /* no read fifo */ + fifo_select(cs, fifo); + if (fifo & 4) { + fifo_size = D_FIFO_SIZE; /* D-channel */ + f_msk = MAX_D_FRAMES; + if (trans_max) return(NULL); /* only hdlc */ + } + else { + fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ + f_msk = MAX_B_FRAMES; + } + + /* transparent mode */ + if (trans_max) { + z1 = Read_hfc(cs, HFCSX_FIF_Z1H); + z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); + z2 = Read_hfc(cs, HFCSX_FIF_Z2H); + z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); + /* now determine bytes in actual FIFO buffer */ + count = z1 - z2; + if (count <= 0) + count += fifo_size; /* count now contains buffered bytes */ + count++; + if (count > trans_max) + count = trans_max; /* limit length */ + if ((skb = dev_alloc_skb(count))) { + dst = skb_put(skb, count); + while (count--) + *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); + return(skb); + } + else return(NULL); /* no memory */ + } + + do { + f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; + f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; + + if (f1 == f2) return(NULL); /* no frame available */ + + z1 = Read_hfc(cs, HFCSX_FIF_Z1H); + z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); + z2 = Read_hfc(cs, HFCSX_FIF_Z2H); + z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); + + if (cs->debug & L1_DEB_ISAC_FIFO) + debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)", + fifo, f1, f2, z1, z2); + /* now determine bytes in actual FIFO buffer */ + count = z1 - z2; + if (count <= 0) + count += fifo_size; /* count now contains buffered bytes */ + count++; + + if (cs->debug & L1_DEB_ISAC_FIFO) + debugl1(cs, "hfcsx_read_fifo %d count %ld)", + fifo, count); + + if ((count > fifo_size) || (count < 4)) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcsx_read_fifo %d paket inv. len %d ", fifo , count); + while (count) { + count--; /* empty fifo */ + Read_hfc(cs, HFCSX_FIF_DRD); + } + skb = NULL; + } else + if ((skb = dev_alloc_skb(count - 3))) { + count -= 3; + dst = skb_put(skb, count); + + while (count--) + *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); + + Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ + Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ + if (Read_hfc(cs, HFCSX_FIF_DRD)) { + dev_kfree_skb(skb); + if (cs->debug & L1_DEB_ISAC_FIFO) + debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); + skb = NULL; + } + } else { + printk(KERN_WARNING "HFC-SX: receive out of memory\n"); + return(NULL); + } + + Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */ + udelay(1); + while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ + udelay(1); + } while (!skb); /* retry in case of crc error */ + return(skb); +} + +/******************************************/ +/* free hardware resources used by driver */ +/******************************************/ +void +release_io_hfcsx(struct IsdnCardState *cs) +{ + int flags; + + save_flags(flags); + cli(); + cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ + Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); + restore_flags(flags); + Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */ + sti(); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ + Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */ + del_timer(&cs->hw.hfcsx.timer); + release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */ + kfree(cs->hw.hfcsx.extra); + cs->hw.hfcsx.extra = NULL; +} + +/**********************************************************/ +/* set_fifo_size determines the size of the RAM and FIFOs */ +/* returning 0 -> need to reset the chip again. */ +/**********************************************************/ +static int set_fifo_size(struct IsdnCardState *cs) +{ + + if (cs->hw.hfcsx.b_fifo_size) return(1); /* already determined */ + + if ((cs->hw.hfcsx.chip >> 4) == 9) { + cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K; + return(1); + } + + cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K; + cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */ + return(0); + +} + +/********************************************************************************/ +/* function called to reset the HFC SX chip. A complete software reset of chip */ +/* and fifos is done. */ +/********************************************************************************/ +static void +reset_hfcsx(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + cli(); + cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ + Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); + + printk(KERN_INFO "HFC_SX: resetting card\n"); + while (1) { + Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */ + sti(); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ + Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + if (Read_hfc(cs, HFCSX_STATUS) & 2) + printk(KERN_WARNING "HFC-SX init bit busy\n"); + cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */ + if (!set_fifo_size(cs)) continue; + break; + } + + cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */ + Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); + + Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ + cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE; + Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */ + cs->hw.hfcsx.bswapped = 0; /* no exchange */ + cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */ + cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER; + Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); + + cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC | + HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + + /* Clear already pending ints */ + if (Read_hfc(cs, HFCSX_INT_S1)); + + Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */ + udelay(10); + Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */ + cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */ + + Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ + Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); + cs->hw.hfcsx.sctrl_r = 0; + Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); + + /* Init GCI/IOM2 in master mode */ + /* Slots 0 and 1 are set for B-chan 1 and 2 */ + /* D- and monitor/CI channel are not enabled */ + /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ + /* STIO2 is used as data input, B1+B2 from IOM->ST */ + /* ST B-channel send disabled -> continous 1s */ + /* The IOM slots are always enabled */ + cs->hw.hfcsx.conn = 0x36; /* set data flow directions */ + Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); + Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */ + Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */ + Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */ + Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */ + + /* Finally enable IRQ output */ + cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE; + Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); + if (Read_hfc(cs, HFCSX_INT_S2)); + restore_flags(flags); +} + +/***************************************************/ +/* Timer function called when kernel timer expires */ +/***************************************************/ +static void +hfcsx_Timer(struct IsdnCardState *cs) +{ + cs->hw.hfcsx.timer.expires = jiffies + 75; + /* WD RESET */ +/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80); + add_timer(&cs->hw.hfcsx.timer); + */ +} + + +/*********************************/ +/* schedule a new D-channel task */ +/*********************************/ +static void +sched_event_D_sx(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + queue_task(&cs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/*********************************/ +/* schedule a new b_channel task */ +/*********************************/ +static void +hfcsx_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + queue_task(&bcs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/************************************************/ +/* select a b-channel entry matching and active */ +/************************************************/ +static +struct BCState * +Sel_BCS(struct IsdnCardState *cs, int channel) +{ + if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) + return (&cs->bcs[0]); + else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) + return (&cs->bcs[1]); + else + return (NULL); +} + +/*******************************/ +/* D-channel receive procedure */ +/*******************************/ +static +int +receive_dmsg(struct IsdnCardState *cs) +{ + struct sk_buff *skb; + int count = 5; + + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_dmsg blocked"); + return (1); + } + + do { + skb = read_fifo(cs, HFCSX_SEL_D_RX, 0); + if (skb) { + skb_queue_tail(&cs->rq, skb); + sched_event_D_sx(cs, D_RCVBUFREADY); + } + } while (--count && skb); + + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + return (1); +} + +/**********************************/ +/* B-channel main receive routine */ +/**********************************/ +void +main_rec_hfcsx(struct BCState *bcs) +{ + long flags; + struct IsdnCardState *cs = bcs->cs; + int count = 5; + struct sk_buff *skb; + + save_flags(flags); + + Begin: + count--; + cli(); + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_data %d blocked", bcs->channel); + restore_flags(flags); + return; + } + sti(); + skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? + HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX, + (bcs->mode == L1_MODE_TRANS) ? + HFCSX_BTRANS_THRESHOLD : 0); + + if (skb) { + cli(); + skb_queue_tail(&bcs->rqueue, skb); + sti(); + hfcsx_sched_event(bcs, B_RCVBUFREADY); + } + + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + if (count && skb) + goto Begin; + restore_flags(flags); + return; +} + +/**************************/ +/* D-channel send routine */ +/**************************/ +static void +hfcsx_fill_dfifo(struct IsdnCardState *cs) +{ + if (!cs->tx_skb) + return; + if (cs->tx_skb->len <= 0) + return; + + if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { + dev_kfree_skb(cs->tx_skb); + cs->tx_skb = NULL; + } + return; +} + +/**************************/ +/* B-channel send routine */ +/**************************/ +static void +hfcsx_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + int flags; + + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) + return; + + save_flags(flags); + sti(); + + if (write_fifo(cs, bcs->tx_skb, + ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? + HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX, + (bcs->mode == L1_MODE_TRANS) ? + HFCSX_BTRANS_THRESHOLD : 0)) { + + bcs->tx_cnt -= bcs->tx_skb->len; + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + + cli(); + restore_flags(flags); + return; +} + +/**********************************************/ +/* D-channel l1 state call for leased NT-mode */ +/**********************************************/ +static void +dch_nt_l2l1(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + + switch (pr) { + case (PH_DATA | REQUEST): + case (PH_PULL | REQUEST): + case (PH_PULL | INDICATION): + st->l1.l1hw(st, pr, arg); + break; + case (PH_ACTIVATE | REQUEST): + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); + break; + case (PH_TESTLOOP | REQUEST): + if (1 & (long) arg) + debugl1(cs, "PH_TEST_LOOP B1"); + if (2 & (long) arg) + debugl1(cs, "PH_TEST_LOOP B2"); + if (!(3 & (long) arg)) + debugl1(cs, "PH_TEST_LOOP DISABLED"); + st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); + break; + default: + if (cs->debug) + debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr); + break; + } +} + + + +/***********************/ +/* set/reset echo mode */ +/***********************/ +static int +hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic) +{ + int flags; + int i = *(unsigned int *) ic->parm.num; + + if ((ic->arg == 98) && + (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) { + save_flags(flags); + cli(); + Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */ + udelay(10); + cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT; + Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */ + udelay(10); + Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */ + udelay(10); + Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION); + cs->dc.hfcsx.ph_state = 1; + cs->hw.hfcsx.nt_mode = 1; + cs->hw.hfcsx.nt_timer = 0; + cs->stlist->l2.l2l1 = dch_nt_l2l1; + restore_flags(flags); + debugl1(cs, "NT mode activated"); + return (0); + } + if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) || + (cs->hw.hfcsx.nt_mode) || (ic->arg != 12)) + return (-EINVAL); + + save_flags(flags); + cli(); + if (i) { + cs->logecho = 1; + cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */ + cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC; + /* reset Channel !!!!! */ + } else { + cs->logecho = 0; + cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */ + cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC; + } + cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; + cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; + cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */ + cs->hw.hfcsx.ctmt &= ~2; + Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); + Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); + Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); + Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); + Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + restore_flags(flags); + return (0); +} /* hfcsx_auxcmd */ + +/*****************************/ +/* E-channel receive routine */ +/*****************************/ +static void +receive_emsg(struct IsdnCardState *cs) +{ + int flags; + int count = 5; + u_char *ptr; + struct sk_buff *skb; + + + save_flags(flags); + cli(); + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "echo_rec_data blocked"); + restore_flags(flags); + return; + } + sti(); + + do { + skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0); + if (skb) { + if (cs->debug & DEB_DLOG_HEX) { + ptr = cs->dlog; + if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) { + *ptr++ = 'E'; + *ptr++ = 'C'; + *ptr++ = 'H'; + *ptr++ = 'O'; + *ptr++ = ':'; + ptr += QuickHex(ptr, skb->data, skb->len); + ptr--; + *ptr++ = '\n'; + *ptr = 0; + HiSax_putstatus(cs, NULL, cs->dlog); + } else + HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); + } + dev_kfree_skb(skb); + } + } while (--count && skb); + + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + restore_flags(flags); + return; +} /* receive_emsg */ + + +/*********************/ +/* Interrupt handler */ +/*********************/ +static void +hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char exval; + struct BCState *bcs; + int count = 15; + long flags; + u_char val, stat; + + if (!cs) { + printk(KERN_WARNING "HFC-SX: Spurious interrupt!\n"); + return; + } + if (!(cs->hw.hfcsx.int_m2 & 0x08)) + return; /* not initialised */ + + if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) { + val = Read_hfc(cs, HFCSX_INT_S1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val); + } else + return; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFC-SX irq %x %s", val, + test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? + "locked" : "unlocked"); + val &= cs->hw.hfcsx.int_m1; + if (val & 0x40) { /* state machine irq */ + exval = Read_hfc(cs, HFCSX_STATES) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state, + exval); + cs->dc.hfcsx.ph_state = exval; + sched_event_D_sx(cs, D_L1STATECHANGE); + val &= ~0x40; + } + if (val & 0x80) { /* timer irq */ + if (cs->hw.hfcsx.nt_mode) { + if ((--cs->hw.hfcsx.nt_timer) < 0) + sched_event_D_sx(cs, D_L1STATECHANGE); + } + val &= ~0x80; + Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); + } + while (val) { + save_flags(flags); + cli(); + if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + cs->hw.hfcsx.int_s1 |= val; + restore_flags(flags); + return; + } + if (cs->hw.hfcsx.int_s1 & 0x18) { + exval = val; + val = cs->hw.hfcsx.int_s1; + cs->hw.hfcsx.int_s1 = exval; + } + if (val & 0x08) { + if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { + if (cs->debug) + debugl1(cs, "hfcsx spurious 0x08 IRQ"); + } else + main_rec_hfcsx(bcs); + } + if (val & 0x10) { + if (cs->logecho) + receive_emsg(cs); + else if (!(bcs = Sel_BCS(cs, 1))) { + if (cs->debug) + debugl1(cs, "hfcsx spurious 0x10 IRQ"); + } else + main_rec_hfcsx(bcs); + } + if (val & 0x01) { + if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { + if (cs->debug) + debugl1(cs, "hfcsx spurious 0x01 IRQ"); + } else { + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + hfcsx_sched_event(bcs, B_XMTBUFREADY); + } + } + } + } + if (val & 0x02) { + if (!(bcs = Sel_BCS(cs, 1))) { + if (cs->debug) + debugl1(cs, "hfcsx spurious 0x02 IRQ"); + } else { + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + hfcsx_sched_event(bcs, B_XMTBUFREADY); + } + } + } + } + if (val & 0x20) { /* receive dframe */ + receive_dmsg(cs); + } + if (val & 0x04) { /* dframe transmitted */ + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + sched_event_D_sx(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcsx_fill_dfifo irq blocked"); + } + goto afterXPR; + } else { + dev_kfree_skb(cs->tx_skb); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcsx_fill_dfifo irq blocked"); + } + } else + sched_event_D_sx(cs, D_XMTBUFREADY); + } + afterXPR: + if (cs->hw.hfcsx.int_s1 && count--) { + val = cs->hw.hfcsx.int_s1; + cs->hw.hfcsx.int_s1 = 0; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count); + } else + val = 0; + restore_flags(flags); + } +} + +/********************************************************************/ +/* timer callback for D-chan busy resolution. Currently no function */ +/********************************************************************/ +static void +hfcsx_dbusy_timer(struct IsdnCardState *cs) +{ +} + +/*************************************/ +/* Layer 1 D-channel hardware access */ +/*************************************/ +static void +HFCSX_l1hw(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + int flags; + + switch (pr) { + case (PH_DATA | REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcsx_fill_dfifo blocked"); + + } + break; + case (PH_PULL | INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcsx_fill_dfifo blocked"); + break; + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (HW_RESET | REQUEST): + Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */ + udelay(6); + Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */ + cs->hw.hfcsx.mst_m |= HFCSX_MASTER; + Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + case (HW_ENABLE | REQUEST): + Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); + break; + case (HW_DEACTIVATE | REQUEST): + cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER; + Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + break; + case (HW_INFO3 | REQUEST): + cs->hw.hfcsx.mst_m |= HFCSX_MASTER; + Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + break; + case (HW_TESTLOOP | REQUEST): + switch ((int) arg) { + case (1): + Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */ + Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */ + save_flags(flags); + cli(); + cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1; + Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); + restore_flags(flags); + break; + + case (2): + Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */ + Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */ + save_flags(flags); + cli(); + cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08; + Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); + restore_flags(flags); + break; + + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg); + return; + } + save_flags(flags); + cli(); + cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */ + Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); + restore_flags(flags); + break; + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr); + break; + } +} + +/***********************************************/ +/* called during init setting l1 stack pointer */ +/***********************************************/ +void +setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = HFCSX_l1hw; +} + +/**************************************/ +/* send B-channel data if not blocked */ +/**************************************/ +static void +hfcsx_send_data(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcsx_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "send_data %d blocked", bcs->channel); +} + +/***************************************************************/ +/* activate/deactivate hardware for selected channels and mode */ +/***************************************************************/ +void +mode_hfcsx(struct BCState *bcs, int mode, int bc) +{ + struct IsdnCardState *cs = bcs->cs; + int flags, fifo2; + + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d", + mode, bc, bcs->channel); + bcs->mode = mode; + bcs->channel = bc; + fifo2 = bc; + save_flags(flags); + cli(); + if (cs->chanlimit > 1) { + cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ + cs->hw.hfcsx.sctrl_e &= ~0x80; + } else { + if (bc) { + if (mode != L1_MODE_NULL) { + cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */ + cs->hw.hfcsx.sctrl_e |= 0x80; + } else { + cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ + cs->hw.hfcsx.sctrl_e &= ~0x80; + } + fifo2 = 0; + } else { + cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ + cs->hw.hfcsx.sctrl_e &= ~0x80; + } + } + switch (mode) { + case (L1_MODE_NULL): + if (bc) { + cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; + cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; + } else { + cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA; + cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA; + } + if (fifo2) { + cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); + } else { + cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); + } + break; + case (L1_MODE_TRANS): + if (bc) { + cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; + cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; + } else { + cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; + cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; + } + if (fifo2) { + cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); + cs->hw.hfcsx.ctmt |= 2; + cs->hw.hfcsx.conn &= ~0x18; + } else { + cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); + cs->hw.hfcsx.ctmt |= 1; + cs->hw.hfcsx.conn &= ~0x03; + } + break; + case (L1_MODE_HDLC): + if (bc) { + cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; + cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; + } else { + cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; + cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; + } + if (fifo2) { + cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); + cs->hw.hfcsx.ctmt &= ~2; + cs->hw.hfcsx.conn &= ~0x18; + } else { + cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); + cs->hw.hfcsx.ctmt &= ~1; + cs->hw.hfcsx.conn &= ~0x03; + } + break; + case (L1_MODE_EXTRN): + if (bc) { + cs->hw.hfcsx.conn |= 0x10; + cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; + cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; + cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); + } else { + cs->hw.hfcsx.conn |= 0x02; + cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; + cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; + cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); + } + break; + } + Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); + Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); + Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); + Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); + if (mode != L1_MODE_EXTRN) { + reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX); + reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX); + } + restore_flags(flags); +} + +/******************************/ +/* Layer2 -> Layer 1 Transfer */ +/******************************/ +static void +hfcsx_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + long flags; + + switch (pr) { + case (PH_DATA | REQUEST): + save_flags(flags); + cli(); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + restore_flags(flags); + } else { + st->l1.bcs->tx_skb = skb; +/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + */ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + restore_flags(flags); + } + break; + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { + printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); + break; + } + save_flags(flags); + cli(); +/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + */ st->l1.bcs->tx_skb = skb; + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + restore_flags(flags); + break; + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_hfcsx(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_hfcsx(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; + } +} + +/******************************************/ +/* deactivate B-channel access and queues */ +/******************************************/ +static void +close_hfcsx(struct BCState *bcs) +{ + mode_hfcsx(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + dev_kfree_skb(bcs->tx_skb); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } +} + +/*************************************/ +/* init B-channel queues and control */ +/*************************************/ +static int +open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs) +{ + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->tx_cnt = 0; + return (0); +} + +/*********************************/ +/* inits the stack for B-channel */ +/*********************************/ +static int +setstack_2b(struct PStack *st, struct BCState *bcs) +{ + bcs->channel = st->l1.bc; + if (open_hfcsxstate(st->l1.hardware, bcs)) + return (-1); + st->l1.bcs = bcs; + st->l2.l2l1 = hfcsx_l2l1; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +/***************************/ +/* handle L1 state changes */ +/***************************/ +static void +hfcsx_bh(struct IsdnCardState *cs) +{ + int flags; +/* struct PStack *stptr; + */ + if (!cs) + return; + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { + if (!cs->hw.hfcsx.nt_mode) + switch (cs->dc.hfcsx.ph_state) { + case (0): + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + case (3): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + case (8): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + case (6): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + case (7): + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); + break; + default: + break; + } else { + switch (cs->dc.hfcsx.ph_state) { + case (2): + save_flags(flags); + cli(); + if (cs->hw.hfcsx.nt_timer < 0) { + cs->hw.hfcsx.nt_timer = 0; + cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + /* Clear already pending ints */ + if (Read_hfc(cs, HFCSX_INT_S1)); + + Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE); + udelay(10); + Write_hfc(cs, HFCSX_STATES, 4); + cs->dc.hfcsx.ph_state = 4; + } else { + cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER; + cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125; + Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); + Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); + cs->hw.hfcsx.nt_timer = NT_T1_COUNT; + Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */ + } + restore_flags(flags); + break; + case (1): + case (3): + case (4): + save_flags(flags); + cli(); + cs->hw.hfcsx.nt_timer = 0; + cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + restore_flags(flags); + break; + default: + break; + } + } + } + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) + DChannel_proc_rcv(cs); + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) + DChannel_proc_xmt(cs); +} + + +/********************************/ +/* called for card init message */ +/********************************/ +__initfunc(void + inithfcsx(struct IsdnCardState *cs)) +{ + cs->setstack_d = setstack_hfcsx; + cs->dbusytimer.function = (void *) hfcsx_dbusy_timer; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + cs->tqueue.routine = (void *) (void *) hfcsx_bh; + cs->BC_Send_Data = &hfcsx_send_data; + cs->bcs[0].BC_SetStack = setstack_2b; + cs->bcs[1].BC_SetStack = setstack_2b; + cs->bcs[0].BC_Close = close_hfcsx; + cs->bcs[1].BC_Close = close_hfcsx; + mode_hfcsx(cs->bcs, 0, 0); + mode_hfcsx(cs->bcs + 1, 0, 1); +} + + + +/*******************************************/ +/* handle card messages from control layer */ +/*******************************************/ +static int +hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + long flags; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCSX: card_msg %x", mt); + switch (mt) { + case CARD_RESET: + reset_hfcsx(cs); + return (0); + case CARD_RELEASE: + release_io_hfcsx(cs); + return (0); + case CARD_INIT: + inithfcsx(cs); + save_flags(flags); + sti(); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ + /* now switch timer interrupt off */ + cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + /* reinit mode reg */ + Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); + restore_flags(flags); + return (0); + case CARD_TEST: + return (0); + } + return (0); +} + + + +__initfunc(int + setup_hfcsx(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + int flags; + + strcpy(tmp, hfcsx_revision); + printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp)); + cs->hw.hfcsx.base = card->para[1] & 0xfffe; + cs->irq = card->para[0]; + cs->hw.hfcsx.int_s1 = 0; + cs->dc.hfcsx.ph_state = 0; + cs->hw.hfcsx.fifo = 255; + if (cs->typ == ISDN_CTYPE_HFC_SX) { + if ((!cs->hw.hfcsx.base) || + check_region((cs->hw.hfcsx.base), 2)) { + printk(KERN_WARNING + "HiSax: HFC-SX io-base 0x%x already in use\n", + cs->hw.hfcsx.base); + return(0); + } else { + request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn"); + } + byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF); + byteout(cs->hw.hfcsx.base + 1, + ((cs->hw.hfcsx.base >> 8) & 3) | 0x54); + udelay(10); + cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID); + switch (cs->hw.hfcsx.chip >> 4) { + case 1: + tmp[0] ='+'; + break; + case 9: + tmp[0] ='P'; + break; + default: + printk(KERN_WARNING + "HFC-SX: invalid chip id 0x%x\n", + cs->hw.hfcsx.chip >> 4); + release_region(cs->hw.hfcsx.base, 2); + return(0); + } + if (!ccd_sp_irqtab[cs->irq & 0xF]) { + printk(KERN_WARNING + "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF); + release_region(cs->hw.hfcsx.base, 2); + return(0); + } + save_flags(flags); + cli(); + if (!(cs->hw.hfcsx.extra = (void *) + kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) { + restore_flags(flags); + release_region(cs->hw.hfcsx.base, 2); + printk(KERN_WARNING "HFC-SX: unable to allocate memory\n"); + return(0); + } + restore_flags(flags); + + printk(KERN_INFO + "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n", + tmp[0], (u_int) cs->hw.hfcsx.base, + cs->irq, HZ); + cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */ + cs->hw.hfcsx.int_m1 = 0; + Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); + Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); + } else + return (0); /* no valid card type */ + + cs->readisac = NULL; + cs->writeisac = NULL; + cs->readisacfifo = NULL; + cs->writeisacfifo = NULL; + cs->BC_Read_Reg = NULL; + cs->BC_Write_Reg = NULL; + cs->irq_func = &hfcsx_interrupt; + + cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer; + cs->hw.hfcsx.timer.data = (long) cs; + cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */ + cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */ + init_timer(&cs->hw.hfcsx.timer); + + reset_hfcsx(cs); + cs->cardmsg = &hfcsx_card_msg; + cs->auxcmd = &hfcsx_auxcmd; + return (1); +} + + + + diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h new file mode 100644 index 000000000000..ebb8d3e7d45e --- /dev/null +++ b/drivers/isdn/hisax/hfc_sx.h @@ -0,0 +1,216 @@ +/* $Id: hfc_sx.h,v 1.1 1999/11/18 00:09:18 werner Exp $ + + * specific defines for CCD's HFC 2BDS0 S+,SP chips + * + * Author Werner Cornelius (werner@isdn4linux.de) + * + * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) + * + * 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 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. + * + * $Log: hfc_sx.h,v $ + * Revision 1.1 1999/11/18 00:09:18 werner + * + * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM. + * Audio and Echo are supported. + * + * + * + */ + +/*********************************************/ +/* thresholds for transparent B-channel mode */ +/* change mask and threshold simultaneously */ +/*********************************************/ +#define HFCSX_BTRANS_THRESHOLD 128 +#define HFCSX_BTRANS_THRESMASK 0x00 + +/* GCI/IOM bus monitor registers */ + +#define HFCSX_C_I 0x02 +#define HFCSX_TRxR 0x03 +#define HFCSX_MON1_D 0x0A +#define HFCSX_MON2_D 0x0B + + +/* GCI/IOM bus timeslot registers */ + +#define HFCSX_B1_SSL 0x20 +#define HFCSX_B2_SSL 0x21 +#define HFCSX_AUX1_SSL 0x22 +#define HFCSX_AUX2_SSL 0x23 +#define HFCSX_B1_RSL 0x24 +#define HFCSX_B2_RSL 0x25 +#define HFCSX_AUX1_RSL 0x26 +#define HFCSX_AUX2_RSL 0x27 + +/* GCI/IOM bus data registers */ + +#define HFCSX_B1_D 0x28 +#define HFCSX_B2_D 0x29 +#define HFCSX_AUX1_D 0x2A +#define HFCSX_AUX2_D 0x2B + +/* GCI/IOM bus configuration registers */ + +#define HFCSX_MST_EMOD 0x2D +#define HFCSX_MST_MODE 0x2E +#define HFCSX_CONNECT 0x2F + + +/* Interrupt and status registers */ + +#define HFCSX_TRM 0x12 +#define HFCSX_B_MODE 0x13 +#define HFCSX_CHIP_ID 0x16 +#define HFCSX_CIRM 0x18 +#define HFCSX_CTMT 0x19 +#define HFCSX_INT_M1 0x1A +#define HFCSX_INT_M2 0x1B +#define HFCSX_INT_S1 0x1E +#define HFCSX_INT_S2 0x1F +#define HFCSX_STATUS 0x1C + +/* S/T section registers */ + +#define HFCSX_STATES 0x30 +#define HFCSX_SCTRL 0x31 +#define HFCSX_SCTRL_E 0x32 +#define HFCSX_SCTRL_R 0x33 +#define HFCSX_SQ 0x34 +#define HFCSX_CLKDEL 0x37 +#define HFCSX_B1_REC 0x3C +#define HFCSX_B1_SEND 0x3C +#define HFCSX_B2_REC 0x3D +#define HFCSX_B2_SEND 0x3D +#define HFCSX_D_REC 0x3E +#define HFCSX_D_SEND 0x3E +#define HFCSX_E_REC 0x3F + +/****************/ +/* FIFO section */ +/****************/ +#define HFCSX_FIF_SEL 0x10 +#define HFCSX_FIF_Z1L 0x80 +#define HFCSX_FIF_Z1H 0x84 +#define HFCSX_FIF_Z2L 0x88 +#define HFCSX_FIF_Z2H 0x8C +#define HFCSX_FIF_INCF1 0xA8 +#define HFCSX_FIF_DWR 0xAC +#define HFCSX_FIF_F1 0xB0 +#define HFCSX_FIF_F2 0xB4 +#define HFCSX_FIF_INCF2 0xB8 +#define HFCSX_FIF_DRD 0xBC + +/* bits in status register (READ) */ +#define HFCSX_SX_PROC 0x02 +#define HFCSX_NBUSY 0x04 +#define HFCSX_TIMER_ELAP 0x10 +#define HFCSX_STATINT 0x20 +#define HFCSX_FRAMEINT 0x40 +#define HFCSX_ANYINT 0x80 + +/* bits in CTMT (Write) */ +#define HFCSX_CLTIMER 0x80 +#define HFCSX_TIM3_125 0x04 +#define HFCSX_TIM25 0x10 +#define HFCSX_TIM50 0x14 +#define HFCSX_TIM400 0x18 +#define HFCSX_TIM800 0x1C +#define HFCSX_AUTO_TIMER 0x20 +#define HFCSX_TRANSB2 0x02 +#define HFCSX_TRANSB1 0x01 + +/* bits in CIRM (Write) */ +#define HFCSX_IRQ_SELMSK 0x07 +#define HFCSX_IRQ_SELDIS 0x00 +#define HFCSX_RESET 0x08 +#define HFCSX_FIFO_RESET 0x80 + + +/* bits in INT_M1 and INT_S1 */ +#define HFCSX_INTS_B1TRANS 0x01 +#define HFCSX_INTS_B2TRANS 0x02 +#define HFCSX_INTS_DTRANS 0x04 +#define HFCSX_INTS_B1REC 0x08 +#define HFCSX_INTS_B2REC 0x10 +#define HFCSX_INTS_DREC 0x20 +#define HFCSX_INTS_L1STATE 0x40 +#define HFCSX_INTS_TIMER 0x80 + +/* bits in INT_M2 */ +#define HFCSX_PROC_TRANS 0x01 +#define HFCSX_GCI_I_CHG 0x02 +#define HFCSX_GCI_MON_REC 0x04 +#define HFCSX_IRQ_ENABLE 0x08 + +/* bits in STATES */ +#define HFCSX_STATE_MSK 0x0F +#define HFCSX_LOAD_STATE 0x10 +#define HFCSX_ACTIVATE 0x20 +#define HFCSX_DO_ACTION 0x40 +#define HFCSX_NT_G2_G3 0x80 + +/* bits in HFCD_MST_MODE */ +#define HFCSX_MASTER 0x01 +#define HFCSX_SLAVE 0x00 +/* remaining bits are for codecs control */ + +/* bits in HFCD_SCTRL */ +#define SCTRL_B1_ENA 0x01 +#define SCTRL_B2_ENA 0x02 +#define SCTRL_MODE_TE 0x00 +#define SCTRL_MODE_NT 0x04 +#define SCTRL_LOW_PRIO 0x08 +#define SCTRL_SQ_ENA 0x10 +#define SCTRL_TEST 0x20 +#define SCTRL_NONE_CAP 0x40 +#define SCTRL_PWR_DOWN 0x80 + +/* bits in SCTRL_E */ +#define HFCSX_AUTO_AWAKE 0x01 +#define HFCSX_DBIT_1 0x04 +#define HFCSX_IGNORE_COL 0x08 +#define HFCSX_CHG_B1_B2 0x80 + +/**********************************/ +/* definitions for FIFO selection */ +/**********************************/ +#define HFCSX_SEL_D_RX 5 +#define HFCSX_SEL_D_TX 4 +#define HFCSX_SEL_B1_RX 1 +#define HFCSX_SEL_B1_TX 0 +#define HFCSX_SEL_B2_RX 3 +#define HFCSX_SEL_B2_TX 2 + +#define MAX_D_FRAMES 15 +#define MAX_B_FRAMES 31 +#define B_SUB_VAL_32K 0x0200 +#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K) +#define B_SUB_VAL_8K 0x1A00 +#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K) +#define D_FIFO_SIZE 512 +#define D_FREG_MASK 0xF + +/************************************************************/ +/* structure holding additional dynamic data -> send marker */ +/************************************************************/ +struct hfcsx_extra { + unsigned short marker[2*(MAX_B_FRAMES+1) + (MAX_D_FRAMES+1)]; +}; + +extern void main_irq_hfcsx(struct BCState *bcs); +extern void inithfcsx(struct IsdnCardState *cs); +extern void releasehfcsx(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 593dedc72ee3..b0eea570676f 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1,8 +1,16 @@ -/* $Id: hisax.h,v 2.38 1999/11/14 23:37:03 keil Exp $ +/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.40 2000/01/20 19:51:46 keil + * Fix AddTimer message + * Change CONFIG defines + * + * Revision 2.39 1999/11/18 00:00:43 werner + * + * Added support for HFC-S+ and HFC-SP cards + * * Revision 2.38 1999/11/14 23:37:03 keil * new ISA memory mapped IO * @@ -784,6 +792,31 @@ struct hfcPCI_hw { struct timer_list timer; }; +struct hfcSX_hw { + unsigned int base; + unsigned char cirm; + unsigned char ctmt; + unsigned char conn; + unsigned char mst_m; + unsigned char int_m1; + unsigned char int_m2; + unsigned char int_s1; + unsigned char sctrl; + unsigned char sctrl_r; + unsigned char sctrl_e; + unsigned char trm; + unsigned char stat; + unsigned char fifo; + unsigned char bswapped; + unsigned char nt_mode; + unsigned char chip; + int b_fifo_size; + unsigned char last_fifo; + void *extra; + int nt_timer; + struct timer_list timer; +}; + struct hfcD_hw { unsigned int addr; unsigned int bfifosize; @@ -894,6 +927,10 @@ struct hfcpci_chip { int ph_state; }; +struct hfcsx_chip { + int ph_state; +}; + struct w6692_chip { int ph_state; }; @@ -934,6 +971,7 @@ struct IsdnCardState { struct njet_hw njet; struct hfcD_hw hfcD; struct hfcPCI_hw hfcpci; + struct hfcSX_hw hfcsx; struct ix1_hw niccy; struct isurf_hw isurf; struct saphir_hw saphir; @@ -973,6 +1011,7 @@ struct IsdnCardState { struct isac_chip isac; struct hfcd_chip hfcd; struct hfcpci_chip hfcpci; + struct hfcsx_chip hfcsx; struct w6692_chip w6692; } dc; u_char *rcvbuf; @@ -1032,7 +1071,8 @@ struct IsdnCardState { #define ISDN_CTYPE_GAZEL 34 #define ISDN_CTYPE_HFC_PCI 35 #define ISDN_CTYPE_W6692 36 -#define ISDN_CTYPE_COUNT 36 +#define ISDN_CTYPE_HFC_SX 37 +#define ISDN_CTYPE_COUNT 37 #ifdef ISDN_CHIP_ISAC @@ -1201,6 +1241,12 @@ struct IsdnCardState { #define CARD_HFC_PCI 0 #endif +#ifdef CONFIG_HISAX_HFC_SX +#define CARD_HFC_SX 1 +#else +#define CARD_HFC_SX 0 +#endif + #ifdef CONFIG_HISAX_AMD7930 #define CARD_AMD7930 1 #else @@ -1298,19 +1344,6 @@ struct IsdnCardState { #ifdef CONFIG_HISAX_EURO #undef TEI_PER_CARD #define TEI_PER_CARD 1 -#define HISAX_EURO_SENDCOMPLETE 1 -#define EXT_BEARER_CAPS 1 -#define HISAX_SEND_STD_LLC_IE 1 -#ifdef CONFIG_HISAX_NO_SENDCOMPLETE -#undef HISAX_EURO_SENDCOMPLETE -#endif -#ifdef CONFIG_HISAX_NO_LLC -#undef HISAX_SEND_STD_LLC_IE -#endif -#undef HISAX_DE_AOC -#ifdef CONFIG_DE_AOC -#define HISAX_DE_AOC 1 -#endif #endif /* L1 Debug */ diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index d5dfe7c0c060..bfff8670754c 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.8 1999/12/19 13:00:56 keil Exp $ +/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,9 @@ * * * $Log: isar.c,v $ + * Revision 1.9 2000/01/20 19:47:45 keil + * Add Fax Class 1 support + * * Revision 1.8 1999/12/19 13:00:56 keil * Fix races in setting a new mode * @@ -45,7 +48,17 @@ #define MIN(a,b) ((aevent)) + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); + if (test_and_clear_bit(B_LL_CONNECT, &bcs->event)) + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + if (test_and_clear_bit(B_LL_OK, &bcs->event)) + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK); } static void @@ -445,6 +464,42 @@ isar_sched_event(struct BCState *bcs, int event) mark_bh(IMMEDIATE_BH); } +static inline void +send_DLE_ETX(struct BCState *bcs) +{ + u_char dleetx[2] = {DLE,ETX}; + struct sk_buff *skb; + + if ((skb = dev_alloc_skb(2))) { + memcpy(skb_put(skb, 2), dleetx, 2); + skb_queue_tail(&bcs->rqueue, skb); + isar_sched_event(bcs, B_RCVBUFREADY); + } else { + printk(KERN_WARNING "HiSax: skb out of memory\n"); + } +} + +static inline int +dle_count(unsigned char *buf, int len) +{ + int count = 0; + + while (len--) + if (*buf++ == DLE) + count++; + return count; +} + +static inline void +insert_dle(unsigned char *dest, unsigned char *src, int count) { + /* in input stream have to be flagged as */ + while (count--) { + *dest++ = *src; + if (*src++ == DLE) + *dest++ = DLE; + } +} + static inline void isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) { @@ -515,6 +570,88 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) } } break; + case L1_MODE_FAX: + if (bcs->hw.isar.state != STFAX_ACTIV) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: not ACTIV"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + break; + } + if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { + rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf); + bcs->hw.isar.rcvidx = ireg->clsb + + dle_count(bcs->hw.isar.rcvbuf, ireg->clsb); + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)", + ireg->clsb, bcs->hw.isar.rcvidx); + if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { + insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx), + bcs->hw.isar.rcvbuf, ireg->clsb); + skb_queue_tail(&bcs->rqueue, skb); + isar_sched_event(bcs, B_RCVBUFREADY); + if (ireg->cmsb & SART_NMD) { /* ABORT */ + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: no more data"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + send_DLE_ETX(bcs); + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, + 0, NULL); + bcs->hw.isar.state = STFAX_ESCAPE; + isar_sched_event(bcs, B_LL_NOCARRIER); + } + } else { + printk(KERN_WARNING "HiSax: skb out of memory\n"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + } + break; + } + if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: unknown fax mode %x", + bcs->hw.isar.cmd); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + break; + } + /* PCTRL_CMD_FRH */ + if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: incoming packet too large"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + } else if (ireg->cmsb & HDLC_ERROR) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame error %x len %d", + ireg->cmsb, ireg->clsb); + bcs->hw.isar.rcvidx = 0; + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + } else { + if (ireg->cmsb & HDLC_FSD) + bcs->hw.isar.rcvidx = 0; + ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; + bcs->hw.isar.rcvidx += ireg->clsb; + rcv_mbox(cs, ireg, ptr); + if (ireg->cmsb & HDLC_FED) { + if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ + printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", + bcs->hw.isar.rcvidx); + } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { + printk(KERN_WARNING "ISAR: receive out of memory\n"); + } else { + memcpy(skb_put(skb, bcs->hw.isar.rcvidx), + bcs->hw.isar.rcvbuf, + bcs->hw.isar.rcvidx); + skb_queue_tail(&bcs->rqueue, skb); + isar_sched_event(bcs, B_RCVBUFREADY); + send_DLE_ETX(bcs); + isar_sched_event(bcs, B_LL_OK); + } + } + } + break; default: printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); @@ -547,38 +684,57 @@ isar_fill_fifo(struct BCState *bcs) count = bcs->tx_skb->len; msb = HDLC_FED; } - if (!bcs->hw.isar.txcnt) - msb |= HDLC_FST; save_flags(flags); cli(); ptr = bcs->tx_skb->data; + if (!bcs->hw.isar.txcnt) { + msb |= HDLC_FST; + if ((bcs->mode == L1_MODE_FAX) && + (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) { + if (bcs->tx_skb->len > 1) { + if ((ptr[0]== 0xff) && (ptr[1] == 0x13)) + /* last frame */ + test_and_set_bit(BC_FLG_LASTDATA, + &bcs->Flag); + } + } + } skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.isar.txcnt += count; switch (bcs->mode) { - case L1_MODE_NULL: - printk(KERN_ERR"isar_fill_fifo wrong mode 0\n"); - break; - case L1_MODE_TRANS: - case L1_MODE_V32: - if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - 0, count, ptr)) { - if (cs->debug) - debugl1(cs, "isar bin data send dp%d failed", - bcs->hw.isar.dpath); - } - break; - case L1_MODE_HDLC: - if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - msb, count, ptr)) { + case L1_MODE_NULL: + printk(KERN_ERR"isar_fill_fifo wrong mode 0\n"); + break; + case L1_MODE_TRANS: + case L1_MODE_V32: + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, + 0, count, ptr); + break; + case L1_MODE_HDLC: + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, + msb, count, ptr); + break; + case L1_MODE_FAX: + if (bcs->hw.isar.state != STFAX_ACTIV) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_fill_fifo: not ACTIV"); + } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, + msb, count, ptr); + } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { + sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, + 0, count, ptr); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_fill_fifo: not FTH/FTM"); + } + break; + default: if (cs->debug) - debugl1(cs, "isar hdlc data send dp%d failed", - bcs->hw.isar.dpath); - } - break; - default: - printk(KERN_ERR"isar_fill_fifo mode (%x)error\n", bcs->mode); - break; + debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode); + printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode); + break; } restore_flags(flags); } @@ -606,6 +762,18 @@ send_frames(struct BCState *bcs) if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt); + if (bcs->mode == L1_MODE_FAX) { + if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { + if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) { + test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); + } + } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { + if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) { + test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag); + test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); + } + } + } dev_kfree_skb(bcs->tx_skb); bcs->hw.isar.txcnt = 0; bcs->tx_skb = NULL; @@ -616,6 +784,18 @@ send_frames(struct BCState *bcs) test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); isar_fill_fifo(bcs); } else { + if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) { + if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) { + if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) { + u_char dummy = 0; + sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) | + ISAR_HIS_SDATA, 0x01, 1, &dummy); + } + test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag); + } else { + isar_sched_event(bcs, B_LL_CONNECT); + } + } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); isar_sched_event(bcs, B_XMTBUFREADY); } @@ -642,6 +822,7 @@ check_send(struct IsdnCardState *cs, u_char rdm) } } + const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", "300", "600", "1200", "2400", "4800", "7200", "9600nt", "9600t", "12000", "14400", "WRONG"}; @@ -703,7 +884,7 @@ isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) { } static void -isar_pump_status_ev(struct BCState *bcs, u_char devt) { +isar_pump_statev_modem(struct BCState *bcs, u_char devt) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -772,6 +953,192 @@ isar_pump_status_ev(struct BCState *bcs, u_char devt) { } } +static inline void +ll_deliver_faxstat(struct BCState *bcs, u_char status) +{ + isdn_ctrl ic; + struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; + + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "HL->LL FAXIND %x", status); + ic.driver = bcs->cs->myid; + ic.command = ISDN_STAT_FAXIND; + ic.arg = chanp->chan; + ic.parm.aux.cmd = status; + bcs->cs->iif.statcallb(&ic); +} + +static void +isar_pump_statev_fax(struct BCState *bcs, u_char devt) { + struct IsdnCardState *cs = bcs->cs; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char p1; + + switch(devt) { + case PSEV_10MS_TIMER: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev TIMER"); + break; + case PSEV_RSP_READY: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_READY"); + bcs->hw.isar.state = STFAX_READY; + l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL); + if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { + isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3); + } else { + isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3); + } + break; + case PSEV_LINE_TX_H: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_TX_H"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_TX_H wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_LINE_RX_H: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_RX_H"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_RX_H wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_LINE_TX_B: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_TX_B"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_TX_B wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_LINE_RX_B: + if (bcs->hw.isar.state == STFAX_LINE) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev LINE_RX_B"); + bcs->hw.isar.state = STFAX_CONT; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev LINE_RX_B wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_RSP_CONN: + if (bcs->hw.isar.state == STFAX_CONT) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_CONN"); + bcs->hw.isar.state = STFAX_ACTIV; + test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags); + sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { + /* 1s Flags before data */ + if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) + del_timer(&bcs->hw.isar.ftimer); + /* 1000 ms */ + bcs->hw.isar.ftimer.expires = + jiffies + ((1000 * HZ)/1000); + test_and_set_bit(BC_FLG_LL_CONN, + &bcs->Flag); + add_timer(&bcs->hw.isar.ftimer); + } else { + isar_sched_event(bcs, B_LL_CONNECT); + } + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "pump stev RSP_CONN wrong st %x", + bcs->hw.isar.state); + } + break; + case PSEV_FLAGS_DET: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev FLAGS_DET"); + break; + case PSEV_RSP_DISC: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_DISC"); + if (bcs->hw.isar.state == STFAX_ESCAPE) { + switch(bcs->hw.isar.newcmd) { + case PCTRL_CMD_FTH: + case PCTRL_CMD_FTM: + p1 = 10; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_SILON, 1, &p1); + bcs->hw.isar.state = STFAX_SILDET; + break; + case PCTRL_CMD_FRH: + case PCTRL_CMD_FRM: + p1 = bcs->hw.isar.newmod; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.cmd = bcs->hw.isar.newcmd; + bcs->hw.isar.newcmd = 0; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + bcs->hw.isar.cmd, 1, &p1); + bcs->hw.isar.state = STFAX_LINE; + break; + default: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd); + break; + } + } else if (bcs->hw.isar.state == STFAX_ACTIV) { + if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) { + isar_sched_event(bcs, B_LL_OK); + } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { + send_DLE_ETX(bcs); + isar_sched_event(bcs, B_LL_NOCARRIER); + } else { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); + } + bcs->hw.isar.state = STFAX_READY; + } else { + bcs->hw.isar.state = STFAX_READY; + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); + } + break; + case PSEV_RSP_SILDET: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_SILDET"); + if (bcs->hw.isar.state == STFAX_SILDET) { + p1 = bcs->hw.isar.newmod; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.cmd = bcs->hw.isar.newcmd; + bcs->hw.isar.newcmd = 0; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, + bcs->hw.isar.cmd, 1, &p1); + bcs->hw.isar.state = STFAX_LINE; + } + break; + case PSEV_RSP_SILOFF: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_SILOFF"); + break; + case PSEV_RSP_FCERR: + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "pump stev RSP_FCERR"); + bcs->hw.isar.state = STFAX_ESCAPE; + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); + break; + default: + break; + } +} + static char debbuf[128]; void @@ -791,8 +1158,6 @@ isar_int_main(struct IsdnCardState *cs) } else { debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar spurious IIS_RDATA %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; @@ -818,12 +1183,18 @@ isar_int_main(struct IsdnCardState *cs) case ISAR_IIS_PSTEV: if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { rcv_mbox(cs, ireg, (u_char *)ireg->par); - isar_pump_status_ev(bcs, ireg->cmsb); + if (bcs->mode == L1_MODE_V32) { + isar_pump_statev_modem(bcs, ireg->cmsb); + } else if (bcs->mode == L1_MODE_FAX) { + isar_pump_statev_fax(bcs, ireg->cmsb); + } else { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar IIS_PSTEV pmode %d stat %x", + bcs->mode, ireg->cmsb); + } } else { debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar spurious IIS_PSTEV %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; @@ -834,8 +1205,6 @@ isar_int_main(struct IsdnCardState *cs) } else { debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x", ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar spurious IIS_PSTRSP %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); } break; @@ -869,6 +1238,17 @@ isar_int_main(struct IsdnCardState *cs) restore_flags(flags); } +static void +ftimer_handler(struct BCState *bcs) { + if (bcs->cs->debug) + debugl1(bcs->cs, "ftimer flags %04x", + bcs->Flag); + test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag); + if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) { + isar_sched_event(bcs, B_LL_CONNECT); + } +} + static void setup_pump(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; @@ -879,11 +1259,7 @@ setup_pump(struct BCState *bcs) { case L1_MODE_NULL: case L1_MODE_TRANS: case L1_MODE_HDLC: - if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar pump bypass cfg dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); break; case L1_MODE_V32: ctrl = PMOD_DATAMODEM; @@ -899,11 +1275,7 @@ setup_pump(struct BCState *bcs) { param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; param[3] = PV32P4_UT144; param[4] = PV32P5_UT144; - if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param)) { - if (cs->debug) - debugl1(cs, "isar pump datamodem cfg dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); break; case L1_MODE_FAX: ctrl = PMOD_FAX; @@ -914,11 +1286,11 @@ setup_pump(struct BCState *bcs) { param[1] = PFAXP2_ATN; } param[0] = 6; /* 6 db */ - if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param)) { - if (cs->debug) - debugl1(cs, "isar pump faxmodem cfg dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); + bcs->hw.isar.state = STFAX_NULL; + bcs->hw.isar.newcmd = 0; + bcs->hw.isar.newmod = 0; + test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag); break; } udelay(1000); @@ -934,37 +1306,25 @@ setup_sart(struct BCState *bcs) { switch (bcs->mode) { case L1_MODE_NULL: - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar sart disable dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, + NULL); break; case L1_MODE_TRANS: - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, "\0\0")) { - if (cs->debug) - debugl1(cs, "isar sart binary dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, + "\0\0"); break; case L1_MODE_HDLC: case L1_MODE_FAX: param[0] = 0; - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param)) { - if (cs->debug) - debugl1(cs, "isar sart hdlc dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, + param); break; case L1_MODE_V32: ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; param[0] = S_P1_CHS_8; param[1] = S_P2_BFT_DEF; - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, param)) { - if (cs->debug) - debugl1(cs, "isar sart v14 dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, + param); break; } udelay(1000); @@ -1035,8 +1395,8 @@ modeisar(struct BCState *bcs, int mode, int bc) &bcs->hw.isar.reg->Flags)) bcs->hw.isar.dpath = 1; else { - printk(KERN_WARNING"isar modeisar analog works only with DP1\n"); - debugl1(cs, "isar modeisar analog works only with DP1"); + printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n"); + debugl1(cs, "isar modeisar analog funktions only with DP1"); return(1); } break; @@ -1060,6 +1420,107 @@ modeisar(struct BCState *bcs, int mode, int bc) return(0); } +static void +isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) +{ + struct IsdnCardState *cs = bcs->cs; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char ctrl = 0, nom = 0, p1 = 0; + + switch(cmd) { + case ISDN_FAX_CLASS1_FTM: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTM; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FTM) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FTM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + case ISDN_FAX_CLASS1_FTH: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FTH; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FTH) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FTH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + case ISDN_FAX_CLASS1_FRM: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRM; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FRM) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FRM; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + case ISDN_FAX_CLASS1_FRH: + if (bcs->hw.isar.state == STFAX_READY) { + p1 = para; + ctrl = PCTRL_CMD_FRH; + nom = 1; + bcs->hw.isar.state = STFAX_LINE; + bcs->hw.isar.cmd = ctrl; + bcs->hw.isar.mod = para; + bcs->hw.isar.newmod = 0; + bcs->hw.isar.newcmd = 0; + } else if ((bcs->hw.isar.state == STFAX_ACTIV) && + (bcs->hw.isar.cmd == PCTRL_CMD_FRH) && + (bcs->hw.isar.mod == para)) { + ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); + } else { + bcs->hw.isar.newmod = para; + bcs->hw.isar.newcmd = PCTRL_CMD_FRH; + nom = 0; + ctrl = PCTRL_CMD_ESC; + bcs->hw.isar.state = STFAX_ESCAPE; + } + break; + } + if (ctrl) + sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); +} + void isar_setup(struct IsdnCardState *cs) { @@ -1070,11 +1531,8 @@ isar_setup(struct IsdnCardState *cs) msg = 61; for (i=0; i<2; i++) { /* Buffer Config */ - if (!sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | - ISAR_HIS_P12CFG, 4, 1, &msg)) { - if (cs->debug) - debugl1(cs, "isar P%dCFG failed", i+1); - } + sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | + ISAR_HIS_P12CFG, 4, 1, &msg); cs->bcs[i].hw.isar.mml = msg; cs->bcs[i].mode = 0; cs->bcs[i].hw.isar.dpath = i + 1; @@ -1141,6 +1599,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg) l1_msg_b(st, PH_ACTIVATE | REQUEST, arg); break; case L1_MODE_V32: + case L1_MODE_FAX: if (modeisar(st->l1.bcs, st->l1.mode, st->l1.bc)) l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); break; @@ -1179,6 +1638,7 @@ close_isarstate(struct BCState *bcs) debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY"); } } + del_timer(&bcs->hw.isar.ftimer); } int @@ -1200,6 +1660,9 @@ open_isarstate(struct IsdnCardState *cs, struct BCState *bcs) bcs->event = 0; bcs->hw.isar.rcvidx = 0; bcs->tx_cnt = 0; + bcs->hw.isar.ftimer.function = (void *) ftimer_handler; + bcs->hw.isar.ftimer.data = (long) bcs; + init_timer(&bcs->hw.isar.ftimer); return (0); } @@ -1220,15 +1683,66 @@ setstack_isar(struct PStack *st, struct BCState *bcs) int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { u_long adr; - int features; + int features, i; + struct BCState *bcs; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg); switch (ic->command) { + case (ISDN_CMD_FAXCMD): + bcs = cs->channel[ic->arg].bcs; + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d", + ic->parm.aux.cmd, ic->parm.aux.subcmd); + switch(ic->parm.aux.cmd) { + case ISDN_FAX_CLASS1_CTRL: + if (ic->parm.aux.subcmd == ETX) + test_and_set_bit(BC_FLG_DLEETX, + &bcs->Flag); + break; + case ISDN_FAX_CLASS1_FRM: + case ISDN_FAX_CLASS1_FRH: + case ISDN_FAX_CLASS1_FTM: + case ISDN_FAX_CLASS1_FTH: + if (ic->parm.aux.subcmd == AT_QUERY) { + sprintf(ic->parm.aux.para, + "%d", bcs->hw.isar.mod); + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; + cs->iif.statcallb(ic); + return(0); + } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { + strcpy(ic->parm.aux.para, faxmodulation_s); + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; + cs->iif.statcallb(ic); + return(0); + } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { + for(i=0;iparm.aux.para[0]) + break; + if ((FAXMODCNT > i) && + test_bit(BC_FLG_INIT, &bcs->Flag)) { + isar_pump_cmd(bcs, + ic->parm.aux.cmd, + ic->parm.aux.para[0]); + return(0); + } + } + /* wrong modulation or not activ */ + /* fall through */ + default: + ic->command = ISDN_STAT_FAXIND; + ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR; + cs->iif.statcallb(ic); + } + break; case (ISDN_CMD_IOCTL): switch (ic->arg) { case (9): /* load firmware */ - features = ISDN_FEATURE_L2_MODEM; + features = ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_FCLASS1; memcpy(&adr, ic->parm.num, sizeof(ulong)); if (isar_load_firmware(cs, (u_char *)adr)) return(1); diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h index f2bc4820a92d..ec3bff89ea97 100644 --- a/drivers/isdn/hisax/isar.h +++ b/drivers/isdn/hisax/isar.h @@ -1,10 +1,13 @@ -/* $Id: isar.h,v 1.6 1999/10/14 20:25:29 keil Exp $ +/* $Id: isar.h,v 1.7 2000/01/20 19:47:45 keil Exp $ * isar.h ISAR (Siemens PSB 7110) specific defines * * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: isar.h,v $ + * Revision 1.7 2000/01/20 19:47:45 keil + * Add Fax Class 1 support + * * Revision 1.6 1999/10/14 20:25:29 keil * add a statistic for error monitoring * @@ -145,6 +148,28 @@ #define PSEV_REM_REN 0xcd #define PSEV_GSTN_CLR 0xd4 +#define PSEV_RSP_READY 0xbc +#define PSEV_LINE_TX_H 0xb3 +#define PSEV_LINE_TX_B 0xb2 +#define PSEV_LINE_RX_H 0xb1 +#define PSEV_LINE_RX_B 0xb0 +#define PSEV_RSP_CONN 0xb5 +#define PSEV_RSP_DISC 0xb7 +#define PSEV_RSP_FCERR 0xb9 +#define PSEV_RSP_SILDET 0xbe +#define PSEV_RSP_SILOFF 0xab +#define PSEV_FLAGS_DET 0xba + +#define PCTRL_CMD_FTH 0xa7 +#define PCTRL_CMD_FRH 0xa5 +#define PCTRL_CMD_FTM 0xa8 +#define PCTRL_CMD_FRM 0xa6 +#define PCTRL_CMD_SILON 0xac +#define PCTRL_CMD_CONT 0xa2 +#define PCTRL_CMD_ESC 0xa4 +#define PCTRL_CMD_SILOFF 0xab +#define PCTRL_CMD_HALT 0xa9 + #define PCTRL_LOC_RET 0xcf #define PCTRL_LOC_REN 0xce @@ -193,6 +218,15 @@ #define BSTEV_TBO 0x1f #define BSTEV_RBO 0x2f +/* FAX State Machine */ +#define STFAX_NULL 0 +#define STFAX_READY 1 +#define STFAX_LINE 2 +#define STFAX_CONT 3 +#define STFAX_ACTIV 4 +#define STFAX_ESCAPE 5 +#define STFAX_SILDET 6 + extern int ISARVersion(struct IsdnCardState *cs, char *s); extern void isar_int_main(struct IsdnCardState *cs); extern void initisar(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index 7682170253e7..7715991cbc34 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -1,4 +1,4 @@ -/* $Id: isdnl1.c,v 2.36 1999/08/25 16:50:57 keil Exp $ +/* $Id: isdnl1.c,v 2.37 2000/01/20 19:51:46 keil Exp $ * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards * based on the teles driver from Jan den Ouden @@ -15,6 +15,10 @@ * * * $Log: isdnl1.c,v $ + * Revision 2.37 2000/01/20 19:51:46 keil + * Fix AddTimer message + * Change CONFIG defines + * * Revision 2.36 1999/08/25 16:50:57 keil * Fix bugs which cause 2.3.14 hangs (waitqueue init) * @@ -138,7 +142,7 @@ * */ -const char *l1_revision = "$Revision: 2.36 $"; +const char *l1_revision = "$Revision: 2.37 $"; #define __NO_VERSION__ #include "hisax.h" @@ -362,7 +366,8 @@ DChannel_proc_rcv(struct IsdnCardState *cs) stptr = stptr->next; if (!found) dev_kfree_skb(skb); - } + } else + dev_kfree_skb(skb); } } @@ -559,11 +564,8 @@ l1_deact_req(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L1_F3); -// if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) { - FsmDelTimer(&st->l1.timer, 1); - FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); - test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); -// } + FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); + test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); } static void @@ -574,8 +576,7 @@ l1_power_up(struct FsmInst *fi, int event, void *arg) if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) { FsmChangeState(fi, ST_L1_F4); st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); - FsmDelTimer(&st->l1.timer, 1); - FsmAddTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); } else FsmChangeState(fi, ST_L1_F3); @@ -614,7 +615,7 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg) if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) { if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags)) FsmDelTimer(&st->l1.timer, 3); - FsmAddTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2); + FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2); test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags); } } @@ -729,7 +730,7 @@ l1b_activate(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L1_WAIT_ACT); - FsmAddTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2); + FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2); } static void @@ -738,7 +739,7 @@ l1b_deactivate(struct FsmInst *fi, int event, void *arg) struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L1_WAIT_DEACT); - FsmAddTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2); + FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2); } static void diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index 31b25acdfc28..e6297bd94d18 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -1,4 +1,4 @@ -/* $Id: l3_1tr6.c,v 2.9 1999/07/01 08:11:55 keil Exp $ +/* $Id: l3_1tr6.c,v 2.10 2000/01/20 19:42:01 keil Exp $ * German 1TR6 D-channel protocol * @@ -10,6 +10,9 @@ * * * $Log: l3_1tr6.c,v $ + * Revision 2.10 2000/01/20 19:42:01 keil + * Fixed uninitialiesed location + * * Revision 2.9 1999/07/01 08:11:55 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * @@ -59,7 +62,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.9 $"; +const char *l3_1tr6_revision = "$Revision: 2.10 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -699,6 +702,7 @@ l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 0); pc->para.cause = 0x1b; /* Destination out of order */ + pc->para.loc = 0; pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index d672b6ccc43f..9fa10e326dd9 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.21 1999/12/19 20:25:17 keil Exp $ +/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,12 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.22 2000/01/20 19:44:20 keil + * Fixed uninitialiesed location + * Fixed redirecting number IE in Setup + * Changes from certification + * option for disabling use of KEYPAD protocol + * * Revision 2.21 1999/12/19 20:25:17 keil * fixed LLC for outgoing analog calls * IE Signal is valid on older local switches @@ -95,9 +101,10 @@ #include "isdnl3.h" #include "l3dss1.h" #include +#include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.21 $"; +const char *dss1_revision = "$Revision: 2.22 $"; #define EXT_BEARER_CAPS 1 @@ -698,8 +705,8 @@ static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS, IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, - IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_LLC, IE_HLC, - IE_USER_USER, -1}; + IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, + IE_LLC, IE_HLC, IE_USER_USER, -1}; static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | @@ -1278,6 +1285,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, u_char tmp[128]; u_char *p = tmp; u_char channel = 0; + u_char send_keypad; u_char screen = 0x80; u_char *teln; @@ -1289,14 +1297,18 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, MsgHead(p, pc->callref, MT_SETUP); teln = pc->para.setup.phone; +#ifndef CONFIG_HISAX_NO_KEYPAD send_keypad = (strchr(teln,'*') || strchr(teln,'#')) ? 1 : 0; +#else + send_keypad = 0; +#endif +#ifndef CONFIG_HISAX_NO_SENDCOMPLETE + if (!send_keypad) + *p++ = 0xa1; /* complete indicator */ +#endif /* * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 */ -#if HISAX_EURO_SENDCOMPLETE - if (!send_keypad) - *p++ = 0xa1; /* complete indicator */ -#endif if (!send_keypad) switch (pc->para.setup.si1) { case 1: /* Telephony */ @@ -1458,7 +1470,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr, *p++ = 0x90; *p++ = 0x21; p = EncodeASyncParams(p, pc->para.setup.si2 - 192); -#if HISAX_SEND_STD_LLC_IE +#ifndef CONFIG_HISAX_NO_LLC } else { switch (pc->para.setup.si1) { case 1: /* Telephony */ @@ -2757,6 +2769,7 @@ static void l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg) { pc->para.cause = 0x29; /* Temporary failure */ + pc->para.loc = 0; l3dss1_disconnect_req(pc, pr, NULL); pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } @@ -2766,6 +2779,7 @@ l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg) { newl3state(pc, 0); pc->para.cause = 0x1b; /* Destination out of order */ + pc->para.loc = 0; pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h index 268b5376face..2acb95c01631 100644 --- a/drivers/isdn/hisax/l3dss1.h +++ b/drivers/isdn/hisax/l3dss1.h @@ -1,8 +1,11 @@ -/* $Id: l3dss1.h,v 1.7 1999/07/01 08:12:02 keil Exp $ +/* $Id: l3dss1.h,v 1.8 2000/01/20 19:46:15 keil Exp $ * * DSS1 (Euro) D-channel protocol defines * * $Log: l3dss1.h,v $ + * Revision 1.8 2000/01/20 19:46:15 keil + * Changes from certification + * * Revision 1.7 1999/07/01 08:12:02 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * @@ -35,6 +38,8 @@ #define T304 30000 #define T305 30000 #define T308 4000 +/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ +/* This makes some tests easier and quicker */ #define T309 40000 #define T310 30000 #define T313 4000 diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index 39d9c0d71d39..b83fe66e1e7f 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -7,14 +7,14 @@ # Read ../../../Documentation/isdn/HiSax.cert for more informations. # 3c2b1c96274cba97a8261d1cecc662b8 isac.c -a9a15d069dbacb383cc24c238cb5ebbe isdnl1.c +dd3955847bbf680b41233478fe521d88 isdnl1.c bb51bd223040b511c18f091da5ab6456 isdnl2.c b7aa7f97b2374967a4aca7c52991142c isdnl3.c a23fbf8879c1432b04640b8b04bdf419 tei.c ce248e56c2e1326012d0b25f92bbf99b callc.c bf9605b36429898f7be6630034e83230 cert.c -2dbd5fadc33657c654f71385ff84127a l3dss1.c -2d748ced0eea375b21fe7ea91ca7917c l3_1tr6.c +233960fa9fc46aaffcaa883b5b59cf4e l3dss1.c +a3a570781f828b6d59e6b231653133de l3_1tr6.c 8188deeb4a1b34c574cd51638cd214d0 elsa.c a3c2b8e9d2c623658888b5f1d4317c2a diva.c # end of md5sums @@ -23,9 +23,9 @@ a3c2b8e9d2c623658888b5f1d4317c2a diva.c Version: 2.6.3i Charset: noconv -iQCVAwUBOGUfJzpxHvX/mS9tAQFpwwP/UFR+IP3URpDrRPJgWdzaP+Ho/nu4uOQM -+l2d0MNZlBPIPiRJnP921mcSXUw37OsuXf8cfqihuCgc+2+ExNZe9s9o/Wz5TttA -L1fhoP85OXy6m5Ap77Feh1tzxAQodRwIzzFvrXqUUN82JW32Q931dJzxVbYtgP16 -SkErM8N2GbM= -=QeLI +iQCVAwUBOIdqVzpxHvX/mS9tAQGaWQP+Pj0oVxbhusXnlNOQ+FV6YOGj1HGMXPsO +C/9555qSbvcKg64OO8VdU1LWq/RCsAwBkJ3eSizF5LbWD8lhCHUpkNlzEv4fIaHe +fAA9zLnC8Vk4h/YLwUNfZxezYvf22NGSydXGZH4VvLAigF0OGRlKaewsR61KZ/Fh +4GnVqcxYaH8= +=eINS -----END PGP SIGNATURE----- diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 7ab33ee272ea..7b73021b62e0 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.19 1999/12/19 13:09:42 keil Exp $ +/* $Id: sedlbauer.c,v 1.20 2000/01/20 19:47:45 keil Exp $ * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -17,6 +17,9 @@ * Edgar Toernig * * $Log: sedlbauer.c,v $ + * Revision 1.20 2000/01/20 19:47:45 keil + * Add Fax Class 1 support + * * Revision 1.19 1999/12/19 13:09:42 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -114,7 +117,7 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.19 $"; +const char *Sedlbauer_revision = "$Revision: 1.20 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", @@ -663,15 +666,13 @@ setup_sedlbauer(struct IsdnCard *card)) (sub_id == PCI_SUB_ID_SPEEDFAXP)) { cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; cs->subtyp = SEDL_SPEEDFAX_PCI; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ISAR_RESET_OFF; } else { cs->hw.sedl.chip = SEDL_CHIP_IPAC; cs->subtyp = SEDL_SPEED_PCI; } bytecnt = 256; + cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; + cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; byteout(cs->hw.sedl.cfg_reg, 0xff); byteout(cs->hw.sedl.cfg_reg, 0x00); byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index aca4f35ad72c..6b3ef9970941 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.93 1999/11/04 13:11:36 keil Exp $ +/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,32 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.97 2000/01/23 18:45:37 keil + * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) + * + * Revision 1.96 2000/01/20 19:55:33 keil + * Add FAX Class 1 support + * + * Revision 1.95 2000/01/09 20:43:13 detabc + * exand logical bind-group's for both call's (in and out). + * add first part of kernel-config-help for abc-extension. + * + * Revision 1.94 1999/11/20 22:14:13 detabc + * added channel dial-skip in case of external use + * (isdn phone or another isdn device) on the same NTBA. + * usefull with two or more card's connected the different NTBA's. + * global switchable in kernel-config and also per netinterface. + * + * add auto disable of netinterface's in case of: + * to many connection's in short time. + * config mistakes (wrong encapsulation, B2-protokoll or so on) on local + * or remote side. + * wrong password's or something else to a ISP (syncppp). + * + * possible encapsulations for this future are: + * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP, + * and ISDN_NET_ENCAP_CISCOHDLCK. + * * Revision 1.93 1999/11/04 13:11:36 keil * Reinit of v110 structs * @@ -416,7 +442,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.93 $"; +static char *isdn_revision = "$Revision: 1.97 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -438,6 +464,7 @@ isdn_divert_if *divert_if = NULL; /* interface to diversion module */ static int isdn_writebuf_stub(int, int, const u_char *, int, int); +static void set_global_features(void); void isdn_MOD_INC_USE_COUNT(void) @@ -720,29 +747,33 @@ isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) int isdn_command(isdn_ctrl *cmd) { + if (cmd->driver == -1) { + printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command); + return(1); + } if (cmd->command == ISDN_CMD_SETL2) { - int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255); - unsigned long l2prot = (cmd->arg >> 8) & 255; - unsigned long features = (dev->drv[cmd->driver]->interface->features - >> ISDN_FEATURE_L2_SHIFT) & - ISDN_FEATURE_L2_MASK; - unsigned long l2_feature = (1 << l2prot); - - switch (l2prot) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - /* If V.110 requested, but not supported by - * HL-driver, set emulator-flag and change - * Layer-2 to transparent - */ - if (!(features & l2_feature)) { - dev->v110emu[idx] = l2prot; - cmd->arg = (cmd->arg & 255) | - (ISDN_PROTO_L2_TRANS << 8); - } else - dev->v110emu[idx] = 0; - } + int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255); + unsigned long l2prot = (cmd->arg >> 8) & 255; + unsigned long features = (dev->drv[cmd->driver]->interface->features + >> ISDN_FEATURE_L2_SHIFT) & + ISDN_FEATURE_L2_MASK; + unsigned long l2_feature = (1 << l2prot); + + switch (l2prot) { + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: + /* If V.110 requested, but not supported by + * HL-driver, set emulator-flag and change + * Layer-2 to transparent + */ + if (!(features & l2_feature)) { + dev->v110emu[idx] = l2prot; + cmd->arg = (cmd->arg & 255) | + (ISDN_PROTO_L2_TRANS << 8); + } else + dev->v110emu[idx] = 0; + } } return dev->drv[cmd->driver]->interface->command(cmd); } @@ -822,6 +853,7 @@ isdn_status_callback(isdn_ctrl * c) for (i = 0; i < ISDN_MAX_CHANNELS; i++) if (dev->drvmap[i] == di) isdn_all_eaz(di, dev->chanmap[i]); + set_global_features(); break; case ISDN_STAT_STOP: dev->drv[di]->flags &= ~DRV_FLAG_RUNNING; @@ -1079,6 +1111,7 @@ isdn_status_callback(isdn_ctrl * c) dev->drv[di] = NULL; dev->drvid[di][0] = '\0'; isdn_info_update(); + set_global_features(); restore_flags(flags); return 0; case ISDN_STAT_L1ERR: @@ -1564,6 +1597,9 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) * are serialized by means of a semaphore. */ switch (cmd) { + case IIOCNETDWRSET: + printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n"); + return(-EINVAL); case IIOCNETLCR: printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); return -ENODEV; @@ -1855,7 +1891,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) for (i = 0; i < 10; i++) { sprintf(bname, "%s%s", strlen(dev->drv[drvidx]->msn2eaz[i]) ? - dev->drv[drvidx]->msn2eaz[i] : "-", + dev->drv[drvidx]->msn2eaz[i] : "_", (i < 9) ? "," : "\0"); if (copy_to_user(p, bname, strlen(bname) + 1)) return -EFAULT; @@ -2061,7 +2097,7 @@ isdn_map_eaz2msn(char *msn, int di) int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev - ,int pre_chan) + ,int pre_chan, char *msn) { int i; ulong flags; @@ -2084,6 +2120,8 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) && ((pre_dev != d) || (pre_chan != dev->chanmap[i]))) continue; + if (!strcmp(isdn_map_eaz2msn(msn, d), "-")) + continue; if (dev->usage[i] & ISDN_USAGE_DISABLED) continue; /* usage not allowed */ if (dev->drv[d]->flags & DRV_FLAG_RUNNING) { @@ -2374,6 +2412,19 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding) * Low-level-driver registration */ +static void +set_global_features(void) +{ + int drvidx; + + dev->global_features = 0; + for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) { + if (!dev->drv[drvidx]) + continue; + if (dev->drv[drvidx]->interface) + dev->global_features |= dev->drv[drvidx]->interface->features; + } +} #ifdef CONFIG_ISDN_DIVERSION extern isdn_divert_if *divert_if; @@ -2487,6 +2538,7 @@ register_isdn(isdn_if * i) strcpy(dev->drvid[drvidx], i->id); isdn_info_update(); dev->drivers++; + set_global_features(); restore_flags(flags); return 1; } diff --git a/drivers/isdn/isdn_common.h b/drivers/isdn/isdn_common.h index 83caab9c51e5..ef427991c1cb 100644 --- a/drivers/isdn/isdn_common.h +++ b/drivers/isdn/isdn_common.h @@ -1,4 +1,4 @@ -/* $Id: isdn_common.h,v 1.17 1999/10/27 21:21:17 detabc Exp $ +/* $Id: isdn_common.h,v 1.18 2000/01/23 18:45:37 keil Exp $ * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.h,v $ + * Revision 1.18 2000/01/23 18:45:37 keil + * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) + * * Revision 1.17 1999/10/27 21:21:17 detabc * Added support for building logically-bind-group's per interface. * usefull for outgoing call's with more then one isdn-card. @@ -128,7 +131,7 @@ extern void isdn_timer_ctrl(int tf, int onoff); extern void isdn_unexclusive_channel(int di, int ch); extern int isdn_getnum(char **); extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**); -extern int isdn_get_free_channel(int, int, int, int, int); +extern int isdn_get_free_channel(int, int, int, int, int, char *); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); extern int isdn_wildmat(char *, char *); diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index ae953c11b69a..d23eee32211b 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.95 1999/10/27 21:21:17 detabc Exp $ +/* $Id: isdn_net.c,v 1.103 2000/01/23 18:45:37 keil Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,46 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.103 2000/01/23 18:45:37 keil + * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) + * + * Revision 1.102 2000/01/09 20:43:14 detabc + * exand logical bind-group's for both call's (in and out). + * add first part of kernel-config-help for abc-extension. + * + * Revision 1.101 1999/12/05 16:06:08 detabc + * add resethandling for rawip-compression. + * at now all B2-Protocols are usable with rawip-compression + * + * Revision 1.100 1999/12/04 15:05:25 detabc + * bugfix abc-rawip-bsdcompress with channel-bundeling + * + * Revision 1.99 1999/11/30 11:29:06 detabc + * add a on the fly frame-counter and limit + * + * Revision 1.98 1999/11/28 14:49:07 detabc + * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the + * uncompressed size. + * + * Revision 1.97 1999/11/26 15:54:59 detabc + * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol. + * + * Revision 1.96 1999/11/20 22:14:13 detabc + * added channel dial-skip in case of external use + * (isdn phone or another isdn device) on the same NTBA. + * usefull with two or more card's connected the different NTBA's. + * global switchable in kernel-config and also per netinterface. + * + * add auto disable of netinterface's in case of: + * to many connection's in short time. + * config mistakes (wrong encapsulation, B2-protokoll or so on) on local + * or remote side. + * wrong password's or something else to a ISP (syncppp). + * + * possible encapsulations for this future are: + * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP, + * and ISDN_NET_ENCAP_CISCOHDLCK. + * * Revision 1.95 1999/10/27 21:21:17 detabc * Added support for building logically-bind-group's per interface. * usefull for outgoing call's with more then one isdn-card. @@ -443,7 +483,7 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct device *); static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.95 $"; +char *isdn_net_revision = "$Revision: 1.103 $"; /* * Code for raw-networking over ISDN @@ -1259,14 +1299,16 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) strcpy(addinfo, " IDP"); break; } - printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n", + printk(KERN_INFO + "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n", p[12], p[13], p[14], p[15], p[16], p[17], p[18], p[19], addinfo); break; case ETH_P_ARP: - printk(KERN_INFO "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", + printk(KERN_INFO + "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", p[14], p[15], p[16], p[17], p[24], p[25], p[26], p[27]); break; @@ -1286,8 +1328,8 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) */ #endif int -isdn_net_send_skb(struct device *ndev, isdn_net_local * lp, - struct sk_buff *skb) +isdn_net_send_skb + (struct device *ndev, isdn_net_local * lp,struct sk_buff *skb) { int ret; int len = skb->len; /* save len */ @@ -1484,7 +1526,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) } else lp->dialwait_timer = 0; } - /* Grab a free ISDN-Channel */ if (((chi = isdn_get_free_channel( @@ -1492,7 +1533,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) lp->l2_proto, lp->l3_proto, lp->pre_device, - lp->pre_channel) + lp->pre_channel, + lp->msn) ) < 0) && ((chi = isdn_get_free_channel( @@ -1500,7 +1542,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev) lp->l2_proto, lp->l3_proto, lp->pre_device, - lp->pre_channel^1) + lp->pre_channel^1, + lp->msn) ) < 0)) { restore_flags(flags); isdn_net_unreachable(ndev, skb, @@ -2389,7 +2432,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) p = (isdn_net_dev *) p->next; continue; } - } + } if (lp->flags & ISDN_NET_CALLBACK) { int chi; /* @@ -2411,9 +2454,10 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) isdn_get_free_channel( ISDN_USAGE_NET, lp->l2_proto, - lp->l3_proto, + lp->l3_proto, lp->pre_device, - lp->pre_channel) + lp->pre_channel, + lp->msn) ) < 0) { printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name); @@ -2528,7 +2572,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp) lp->l2_proto, lp->l3_proto, lp->pre_device, - lp->pre_channel) + lp->pre_channel, + lp->msn) ) < 0) { printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name); restore_flags(flags); @@ -2837,10 +2882,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) /* If binding is exclusive, try to grab the channel */ save_flags(flags); - if ((i = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto, - lp->l3_proto, - drvidx, - chidx)) < 0) { + if ((i = isdn_get_free_channel(ISDN_USAGE_NET, + lp->l2_proto, lp->l3_proto, drvidx, + chidx, lp->msn)) < 0) { /* Grab failed, because desired channel is in use */ lp->exclusive = -1; restore_flags(flags); diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index df69bce3a4f8..5b12c224974f 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.60 1999/11/04 20:29:55 he Exp $ +/* $Id: isdn_ppp.c,v 1.61 1999/11/20 22:14:14 detabc Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,22 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.61 1999/11/20 22:14:14 detabc + * added channel dial-skip in case of external use + * (isdn phone or another isdn device) on the same NTBA. + * usefull with two or more card's connected the different NTBA's. + * global switchable in kernel-config and also per netinterface. + * + * add auto disable of netinterface's in case of: + * to many connection's in short time. + * config mistakes (wrong encapsulation, B2-protokoll or so on) on local + * or remote side. + * wrong password's or something else to a ISP (syncppp). + * + * possible encapsulations for this future are: + * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP, + * and ISDN_NET_ENCAP_CISCOHDLCK. + * * Revision 1.60 1999/11/04 20:29:55 he * applied Andre Beck's reset_free fix * @@ -306,7 +322,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb, static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.60 $"; +char *isdn_ppp_revision = "$Revision: 1.61 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index f11bba779c85..b1a17ecd827a 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.80 1999/11/07 13:34:30 armin Exp $ +/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.82 2000/01/23 18:45:37 keil + * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) + * + * Revision 1.81 2000/01/20 19:55:33 keil + * Add FAX Class 1 support + * * Revision 1.80 1999/11/07 13:34:30 armin * Fixed AT command line editor * @@ -348,6 +354,7 @@ #endif #define FIX_FILE_TRANSFER +#define DUMMY_HAYES_AT /* Prototypes */ @@ -372,7 +379,7 @@ static int bit2si[8] = static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.80 $"; +char *isdn_tty_revision = "$Revision: 1.82 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -976,7 +983,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) m->mdmreg[REG_SI1I] = si2bit[si]; save_flags(flags); cli(); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); isdn_tty_modem_result(6, info); @@ -1187,7 +1194,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m) m->mdmreg[REG_SI1I] = si2bit[si]; save_flags(flags); cli(); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); isdn_tty_modem_result(6, info); @@ -1281,7 +1288,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) m->mdmreg[REG_SI1I] = si2bit[si]; save_flags(flags); cli(); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); isdn_tty_modem_result(6, info); @@ -1555,6 +1562,23 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co } } } else + if (TTY_IS_FCLASS1(info)) { + int cc = isdn_tty_handleDLEdown(info, m, c); + + if (info->vonline & 4) { /* ETX seen */ + isdn_ctrl c; + + c.command = ISDN_CMD_FAXCMD; + c.driver = info->isdn_driver; + c.arg = info->isdn_channel; + c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL; + c.parm.aux.subcmd = ETX; + isdn_command(&c); + } + info->vonline = 0; + printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c); + info->xmit_count += cc; + } else #endif info->xmit_count += c; } else { @@ -2568,7 +2592,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) int -isdn_tty_stat_callback(int i, isdn_ctrl * c) +isdn_tty_stat_callback(int i, isdn_ctrl *c) { int mi; modem_info *info; @@ -2669,8 +2693,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c) if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { strcpy(info->emu.connmsg, c->parm.num); isdn_tty_modem_result(1, info); - } - else + } else isdn_tty_modem_result(5, info); } if (USG_VOICE(dev->usage[i])) @@ -2721,7 +2744,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c) #ifdef CONFIG_ISDN_TTY_FAX case ISDN_STAT_FAXIND: if (TTY_IS_ACTIVE(info)) { - isdn_tty_fax_command(info); + isdn_tty_fax_command(info, c); } break; #endif @@ -3248,8 +3271,22 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) info->xmit_size /= 10; } break; + case 'C': + /* &C - DCD Status */ + p[0]++; + switch (isdn_getnum(p)) { + case 0: + m->mdmreg[REG_DCD] &= ~BIT_DCD; + break; + case 1: + m->mdmreg[REG_DCD] |= BIT_DCD; + break; + default: + PARSE_ERROR1 + } + break; case 'D': - /* &D - Set DCD-Low-behavior */ + /* &D - Set DTR-Low-behavior */ p[0]++; switch (isdn_getnum(p)) { case 0: @@ -3281,6 +3318,14 @@ isdn_tty_cmd_ATand(char **p, modem_info * info) isdn_tty_reset_profile(m); isdn_tty_modem_reset_regs(info, 1); break; +#ifdef DUMMY_HAYES_AT + case 'K': + /* only for be compilant with common scripts */ + /* &K Flowcontrol - no function */ + p[0]++; + isdn_getnum(p); + break; +#endif case 'L': /* &L -Set Numbers to listen on */ p[0]++; @@ -3566,8 +3611,10 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info) sprintf(rs, "\r\n%d", (m->mdmreg[REG_SI1] & 1) ? 8 : 0); #ifdef CONFIG_ISDN_TTY_FAX - if (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) - sprintf(rs, "\r\n2"); + if (TTY_IS_FCLASS2(info)) + sprintf(rs, "\r\n2"); + else if (TTY_IS_FCLASS1(info)) + sprintf(rs, "\r\n1"); #endif isdn_tty_at_cout(rs, info); break; @@ -3583,11 +3630,25 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info) m->mdmreg[REG_PSIZE] * 16; break; #ifdef CONFIG_ISDN_TTY_FAX + case '1': + p[0]++; + if (!(dev->global_features & + ISDN_FEATURE_L3_FCLASS1)) + PARSE_ERROR1; + m->mdmreg[REG_SI1] = 1; + m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX; + m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1; + info->xmit_size = + m->mdmreg[REG_PSIZE] * 16; + break; case '2': p[0]++; + if (!(dev->global_features & + ISDN_FEATURE_L3_FCLASS2)) + PARSE_ERROR1; m->mdmreg[REG_SI1] = 1; m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FAX; + m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2; info->xmit_size = m->mdmreg[REG_PSIZE] * 16; break; @@ -3602,11 +3663,17 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info) break; case '?': p[0]++; + strcpy(rs, "\r\n0,"); #ifdef CONFIG_ISDN_TTY_FAX - isdn_tty_at_cout("\r\n0,2,8", info); -#else - isdn_tty_at_cout("\r\n0,8", info); + if (dev->global_features & + ISDN_FEATURE_L3_FCLASS1) + strcat(rs, "1,"); + if (dev->global_features & + ISDN_FEATURE_L3_FCLASS2) + strcat(rs, "2,"); #endif + strcat(rs, "8"); + isdn_tty_at_cout(rs, info); break; default: PARSE_ERROR1; @@ -3996,6 +4063,15 @@ isdn_tty_parse_at(modem_info * info) default: } break; +#ifdef DUMMY_HAYES_AT + case 'L': + case 'M': + /* only for be compilant with common scripts */ + /* no function */ + p++; + isdn_getnum(&p); + break; +#endif case 'O': /* O - Go online */ p++; diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index 1c27b83009c9..ff7e479f0cd1 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.17 1999/09/21 19:00:35 armin Exp $ +/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.18 2000/01/20 19:55:33 keil + * Add FAX Class 1 support + * * Revision 1.17 1999/09/21 19:00:35 armin * Extended FCON message with added CPN * can now be activated with Bit 1 of Reg 23. @@ -160,6 +163,13 @@ #define BIT_CPN 1 #define BIT_CPNFCON 2 +#define TTY_IS_FCLASS1(info) \ + ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ + (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1)) +#define TTY_IS_FCLASS2(info) \ + ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ + (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2)) + extern void isdn_tty_modem_escape(void); extern void isdn_tty_modem_ring(void); extern void isdn_tty_carrier_timeout(void); @@ -175,6 +185,6 @@ extern void isdn_tty_at_cout(char *, modem_info *); extern void isdn_tty_modem_hup(modem_info *, int); #ifdef CONFIG_ISDN_TTY_FAX extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *); -extern int isdn_tty_fax_command(modem_info *); +extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *); extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *); #endif diff --git a/drivers/isdn/isdn_ttyfax.c b/drivers/isdn/isdn_ttyfax.c index 9b7268b32c5c..33f67ff4bea8 100644 --- a/drivers/isdn/isdn_ttyfax.c +++ b/drivers/isdn/isdn_ttyfax.c @@ -1,9 +1,9 @@ -/* $Id: isdn_ttyfax.c,v 1.4 1999/09/21 19:00:35 armin Exp $ +/* $Id: isdn_ttyfax.c,v 1.6 2000/01/26 00:41:13 keil Exp $ * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). * * Copyright 1999 by Armin Schindler (mac@melware.de) * Copyright 1999 by Ralf Spachmann (mel@melware.de) - * Copyright 1999 by Cytronics & Melware + * Copyright 1999 by Cytronics & Melware * * 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 @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ttyfax.c,v $ + * Revision 1.6 2000/01/26 00:41:13 keil + * add "00" as dummy msn in isdn_get_free_channel call + * + * Revision 1.5 2000/01/20 19:55:33 keil + * Add FAX Class 1 support + * * Revision 1.4 1999/09/21 19:00:35 armin * Extended FCON message with added CPN * can now be activated with Bit 1 of Reg 23. @@ -50,31 +56,32 @@ #include "isdn_ttyfax.h" -static char *isdn_tty_fax_revision = "$Revision: 1.4 $"; +static char *isdn_tty_fax_revision = "$Revision: 1.6 $"; #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } static char * isdn_getrev(const char *revision) { - char *rev; - char *p; + char *rev; + char *p; - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else - rev = "???"; - return rev; + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; } - /* * Fax Class 2 Modem results * */ -static void isdn_tty_fax_modem_result(int code, modem_info * info) + +static void +isdn_tty_fax_modem_result(int code, modem_info * info) { atemu *m = &info->emu; T30_s *f = info->fax; @@ -85,7 +92,7 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info) static char *msg[] = {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:", "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:", - "+FCFR", "+FPTS:", "+FET:" }; + "+FCFR", "+FPTS:", "+FET:"}; isdn_tty_at_cout("\r\n", info); @@ -115,12 +122,12 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info) case 3: /* +FCSI */ case 8: /* +FTSI */ sprintf(rs, "\"%s\"", f->r_id); - isdn_tty_at_cout(rs, info); + isdn_tty_at_cout(rs, info); break; case 4: /* +FDIS */ rs[0] = 0; rp = &f->r_resolution; - for(i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { sprintf(rss, "%c%s", rp[i] + 48, (i < 7) ? "," : ""); strcat(rs, rss); @@ -128,18 +135,18 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info) isdn_tty_at_cout(rs, info); #ifdef ISDN_TTY_FAX_CMD_DEBUG printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n", - rs, info->line); + rs, info->line); #endif break; case 5: /* +FHNG */ sprintf(rs, "%d", f->code); - isdn_tty_at_cout(rs, info); + isdn_tty_at_cout(rs, info); info->faxonline = 0; break; case 6: /* +FDCS */ rs[0] = 0; rp = &f->r_resolution; - for(i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { sprintf(rss, "%c%s", rp[i] + 48, (i < 7) ? "," : ""); strcat(rs, rss); @@ -147,127 +154,169 @@ static void isdn_tty_fax_modem_result(int code, modem_info * info) isdn_tty_at_cout(rs, info); #ifdef ISDN_TTY_FAX_CMD_DEBUG printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n", - rs, info->line); + rs, info->line); #endif break; case 7: /* CONNECT */ info->faxonline |= 2; break; - case 9: /* FCFR */ + case 9: /* FCFR */ break; - case 10: /* FPTS */ + case 10: /* FPTS */ isdn_tty_at_cout("1", info); break; - case 11: /* FET */ + case 11: /* FET */ sprintf(rs, "%d", f->fet); - isdn_tty_at_cout(rs, info); + isdn_tty_at_cout(rs, info); break; } isdn_tty_at_cout("\r\n", info); switch (code) { - case 7: /* CONNECT */ + case 7: /* CONNECT */ info->online = 2; if (info->faxonline & 1) { sprintf(rs, "%c", XON); - isdn_tty_at_cout(rs, info); + isdn_tty_at_cout(rs, info); + } + break; + } +} + +int +isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c) +{ + static char *msg[] = + {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"}; + +#ifdef ISDN_TTY_FAX_CMD_DEBUG + printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd); +#endif + if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) { + if (info->online) + info->online = 1; + isdn_tty_at_cout("\r\n", info); + isdn_tty_at_cout(msg[c->parm.aux.cmd], info); + isdn_tty_at_cout("\r\n", info); + } + switch (c->parm.aux.cmd) { + case ISDN_FAX_CLASS1_CONNECT: + info->online = 2; + break; + case ISDN_FAX_CLASS1_OK: + case ISDN_FAX_CLASS1_FCERROR: + case ISDN_FAX_CLASS1_ERROR: + case ISDN_FAX_CLASS1_NOCARR: + break; + case ISDN_FAX_CLASS1_QUERY: + isdn_tty_at_cout("\r\n", info); + if (!c->parm.aux.para[0]) { + isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info); + isdn_tty_at_cout("\r\n", info); + } else { + isdn_tty_at_cout(c->parm.aux.para, info); + isdn_tty_at_cout("\r\nOK\r\n", info); } break; } + return (0); } int -isdn_tty_fax_command(modem_info * info) +isdn_tty_fax_command(modem_info * info, isdn_ctrl * c) { T30_s *f = info->fax; char rs[10]; + if (TTY_IS_FCLASS1(info)) + return (isdn_tty_fax_command1(info, c)); + #ifdef ISDN_TTY_FAX_CMD_DEBUG printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n", - f->r_code, info->line); + f->r_code, info->line); #endif - switch(f->r_code) { + switch (f->r_code) { case ISDN_TTY_FAX_FCON: info->faxonline = 1; - isdn_tty_fax_modem_result(2, info); /* +FCON */ - return(0); + isdn_tty_fax_modem_result(2, info); /* +FCON */ + return (0); case ISDN_TTY_FAX_FCON_I: info->faxonline = 16; - isdn_tty_fax_modem_result(2, info); /* +FCON */ - return(0); + isdn_tty_fax_modem_result(2, info); /* +FCON */ + return (0); case ISDN_TTY_FAX_RID: if (info->faxonline & 1) - isdn_tty_fax_modem_result(3, info); /* +FCSI */ + isdn_tty_fax_modem_result(3, info); /* +FCSI */ if (info->faxonline & 16) - isdn_tty_fax_modem_result(8, info); /* +FTSI */ - return(0); + isdn_tty_fax_modem_result(8, info); /* +FTSI */ + return (0); case ISDN_TTY_FAX_DIS: - isdn_tty_fax_modem_result(4, info); /* +FDIS */ - return(0); + isdn_tty_fax_modem_result(4, info); /* +FDIS */ + return (0); case ISDN_TTY_FAX_HNG: if (f->phase == ISDN_FAX_PHASE_C) { if (f->direction == ISDN_TTY_FAX_CONN_IN) { sprintf(rs, "%c%c", DLE, ETX); - isdn_tty_at_cout(rs, info); + isdn_tty_at_cout(rs, info); } else { sprintf(rs, "%c", 0x18); - isdn_tty_at_cout(rs, info); + isdn_tty_at_cout(rs, info); } - info->faxonline &= ~2; /* leave data mode */ + info->faxonline &= ~2; /* leave data mode */ info->online = 1; } f->phase = ISDN_FAX_PHASE_E; - isdn_tty_fax_modem_result(5, info); /* +FHNG */ - isdn_tty_fax_modem_result(0, info); /* OK */ - return(0); + isdn_tty_fax_modem_result(5, info); /* +FHNG */ + isdn_tty_fax_modem_result(0, info); /* OK */ + return (0); case ISDN_TTY_FAX_DCS: - isdn_tty_fax_modem_result(6, info); /* +FDCS */ - isdn_tty_fax_modem_result(7, info); /* CONNECT */ + isdn_tty_fax_modem_result(6, info); /* +FDCS */ + isdn_tty_fax_modem_result(7, info); /* CONNECT */ f->phase = ISDN_FAX_PHASE_C; - return(0); + return (0); case ISDN_TTY_FAX_TRAIN_OK: - isdn_tty_fax_modem_result(6, info); /* +FDCS */ - isdn_tty_fax_modem_result(0, info); /* OK */ - return(0); + isdn_tty_fax_modem_result(6, info); /* +FDCS */ + isdn_tty_fax_modem_result(0, info); /* OK */ + return (0); case ISDN_TTY_FAX_SENT: - isdn_tty_fax_modem_result(0, info); /* OK */ - return(0); + isdn_tty_fax_modem_result(0, info); /* OK */ + return (0); case ISDN_TTY_FAX_CFR: - isdn_tty_fax_modem_result(9, info); /* +FCFR */ - return(0); + isdn_tty_fax_modem_result(9, info); /* +FCFR */ + return (0); case ISDN_TTY_FAX_ET: sprintf(rs, "%c%c", DLE, ETX); - isdn_tty_at_cout(rs, info); - isdn_tty_fax_modem_result(10, info); /* +FPTS */ - isdn_tty_fax_modem_result(11, info); /* +FET */ - isdn_tty_fax_modem_result(0, info); /* OK */ - info->faxonline &= ~2; /* leave data mode */ + isdn_tty_at_cout(rs, info); + isdn_tty_fax_modem_result(10, info); /* +FPTS */ + isdn_tty_fax_modem_result(11, info); /* +FET */ + isdn_tty_fax_modem_result(0, info); /* OK */ + info->faxonline &= ~2; /* leave data mode */ info->online = 1; f->phase = ISDN_FAX_PHASE_D; - return(0); + return (0); case ISDN_TTY_FAX_PTS: - isdn_tty_fax_modem_result(10, info); /* +FPTS */ + isdn_tty_fax_modem_result(10, info); /* +FPTS */ if (f->direction == ISDN_TTY_FAX_CONN_OUT) { if (f->fet == 1) f->phase = ISDN_FAX_PHASE_B; if (f->fet == 0) - isdn_tty_fax_modem_result(0, info); /* OK */ + isdn_tty_fax_modem_result(0, info); /* OK */ } - return(0); + return (0); case ISDN_TTY_FAX_EOP: - info->faxonline &= ~2; /* leave data mode */ + info->faxonline &= ~2; /* leave data mode */ info->online = 1; f->phase = ISDN_FAX_PHASE_D; - return(0); + return (0); } - return(-1); + return (-1); } void -isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb) +isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb) { __u8 LeftMask; __u8 RightMask; @@ -276,13 +325,13 @@ isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb) int i; if (!info->fax->bor) { - for(i = 0; i < skb->len; i++) { + for (i = 0; i < skb->len; i++) { Data = skb->data[i]; for ( - LeftMask = 0x80, RightMask = 0x01; - LeftMask > RightMask; - LeftMask >>= 1, RightMask <<= 1 - ) { + LeftMask = 0x80, RightMask = 0x01; + LeftMask > RightMask; + LeftMask >>= 1, RightMask <<= 1 + ) { fBit = (Data & LeftMask); if (Data & RightMask) Data |= LeftMask; @@ -299,11 +348,104 @@ isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb) } } +/* + * Parse AT+F.. FAX class 1 commands + */ + +int +isdn_tty_cmd_FCLASS1(char **p, modem_info * info) +{ + static char *cmd[] = + {"AE", "TS", "RS", "TM", "RM", "TH", "RH"}; + isdn_ctrl c; + int par, i; + long flags; + + for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++) + if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2)) + break; + +#ifdef ISDN_TTY_FAX_CMD_DEBUG + printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd); +#endif + if (c.parm.aux.cmd == 7) + PARSE_ERROR1; + + p[0] += 2; + switch (*p[0]) { + case '?': + p[0]++; + c.parm.aux.subcmd = AT_QUERY; + break; + case '=': + p[0]++; + if (*p[0] == '?') { + p[0]++; + c.parm.aux.subcmd = AT_EQ_QUERY; + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + c.parm.aux.subcmd = AT_EQ_VALUE; + c.parm.aux.para[0] = par; + } + break; + case 0: + c.parm.aux.subcmd = AT_COMMAND; + break; + default: + PARSE_ERROR1; + } + c.command = ISDN_CMD_FAXCMD; +#ifdef ISDN_TTY_FAX_CMD_DEBUG + printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n", + c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]); +#endif + if (info->isdn_driver < 0) { + save_flags(flags); + cli(); + if ((c.parm.aux.subcmd == AT_EQ_VALUE) || + (c.parm.aux.subcmd == AT_COMMAND)) { + restore_flags(flags); + PARSE_ERROR1; + } + /* get a temporary connection to the first free fax driver */ + i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX, + ISDN_PROTO_L3_FCLASS1, -1, -1, "00"); + if (i < 0) { + restore_flags(flags); + PARSE_ERROR1; + } + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + c.driver = info->isdn_driver; + c.arg = info->isdn_channel; + isdn_command(&c); + isdn_free_channel(info->isdn_driver, info->isdn_channel, + ISDN_USAGE_FAX); + info->isdn_driver = -1; + info->isdn_channel = -1; + if (info->drv_index >= 0) { + dev->m_idx[info->drv_index] = -1; + info->drv_index = -1; + } + restore_flags(flags); + } else { + c.driver = info->isdn_driver; + c.arg = info->isdn_channel; + isdn_command(&c); + } + return 1; +} + /* * Parse AT+F.. FAX class 2 commands */ -int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) +int +isdn_tty_cmd_FCLASS2(char **p, modem_info * info) { atemu *m = &info->emu; T30_s *f = info->fax; @@ -311,10 +453,11 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) int par; char rs[50]; char rss[50]; - int maxdccval[]={1,5,2,2,3,2,0,7}; + int maxdccval[] = + {1, 5, 2, 2, 3, 2, 0, 7}; /* FAA still unchanged */ - if (!strncmp(p[0], "AA", 2)) { /* TODO */ + if (!strncmp(p[0], "AA", 2)) { /* TODO */ p[0] += 2; switch (*p[0]) { case '?': @@ -332,399 +475,363 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) PARSE_ERROR1; } return 0; - } - + } /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */ - if (!strncmp(p[0], "BADLIN", 6)) { - p[0] += 6; + if (!strncmp(p[0], "BADLIN", 6)) { + p[0] += 6; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d",f->badlin); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->badlin); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->badlin = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->badlin = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par); #endif - } - break; + } + break; default: - PARSE_ERROR1; + PARSE_ERROR1; } - return 0; - } - + return 0; + } /* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */ - if (!strncmp(p[0], "BADMUL", 6)){ - p[0] +=6; + if (!strncmp(p[0], "BADMUL", 6)) { + p[0] += 6; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d", f->badmul); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->badmul); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->badmul = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->badmul = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* BOR=n - Phase C bit order, 0=direct, 1=reverse */ - if (!strncmp(p[0], "BOR", 3)){ - p[0] +=3; + if (!strncmp(p[0], "BOR", 3)) { + p[0] += 3; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d", f->bor); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->bor); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->bor = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->bor = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par); #endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - + } + break; + default: + PARSE_ERROR1; + } + return 0; + } /* NBC=n - No Best Capabilities */ - if (!strncmp(p[0], "NBC", 3)){ - p[0] +=3; + if (!strncmp(p[0], "NBC", 3)) { + p[0] += 3; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d", f->nbc); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->nbc); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->nbc = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->nbc = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par); #endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - + } + break; + default: + PARSE_ERROR1; + } + return 0; + } /* BUF? - Readonly buffersize readout */ - if (!strncmp(p[0], "BUF?", 4)) { - p[0] += 4; + if (!strncmp(p[0], "BUF?", 4)) { + p[0] += 4; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE])); + printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE])); #endif - p[0]++; - sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE])); - isdn_tty_at_cout(rs, info); - return 0; - } - + p[0]++; + sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE])); + isdn_tty_at_cout(rs, info); + return 0; + } /* CIG=string - local fax station id string for polling rx */ - if (!strncmp(p[0], "CIG", 3)) { + if (!strncmp(p[0], "CIG", 3)) { int i, r; - p[0] += 3; + p[0] += 3; switch (*p[0]) { case '?': p[0]++; sprintf(rs, "\r\n\"%s\"", f->pollid); - isdn_tty_at_cout(rs, info); - break; + isdn_tty_at_cout(rs, info); + break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n\"STRING\""); - isdn_tty_at_cout(rs, info); - } - else - { - if (*p[0] =='"') - p[0]++; - for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++) - { - f->pollid[i] = *p[0]++; - } - if (*p[0] =='"') - p[0]++; - for(r=i; r < FAXIDLEN; r++) - { - f->pollid[r] = 32; - } - f->pollid[FAXIDLEN-1] = 0; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n\"STRING\""); + isdn_tty_at_cout(rs, info); + } else { + if (*p[0] == '"') + p[0]++; + for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) { + f->pollid[i] = *p[0]++; + } + if (*p[0] == '"') + p[0]++; + for (r = i; r < FAXIDLEN; r++) { + f->pollid[r] = 32; + } + f->pollid[FAXIDLEN - 1] = 0; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid); + printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */ - if (!strncmp(p[0], "CQ", 2)) { - p[0] += 2; + if (!strncmp(p[0], "CQ", 2)) { + p[0] += 2; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d", f->cq); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->cq); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0,1,2"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 2)) - PARSE_ERROR1; - f->cq = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0,1,2"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 2)) + PARSE_ERROR1; + f->cq = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */ - if (!strncmp(p[0], "CR", 2)) { - p[0] += 2; + if (!strncmp(p[0], "CR", 2)) { + p[0] += 2; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */ - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */ + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0,1"); /* display online help */ - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->cr = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0,1"); /* display online help */ + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->cr = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* CTCRTY=value - ECM retry count */ - if (!strncmp(p[0], "CTCRTY", 6)){ - p[0] +=6; + if (!strncmp(p[0], "CTCRTY", 6)) { + p[0] += 6; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d",f->ctcrty); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->ctcrty); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->ctcrty = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->ctcrty = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */ - if (!strncmp(p[0], "DCC", 3)) { + if (!strncmp(p[0], "DCC", 3)) { char *rp = &f->resolution; int i; - p[0] += 3; - switch(*p[0]) { + p[0] += 3; + switch (*p[0]) { case '?': p[0]++; - strcpy(rs, "\r\n"); - for(i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); + strcpy(rs, "\r\n"); + for (i = 0; i < 8; i++) { + sprintf(rss, "%c%s", rp[i] + 48, + (i < 7) ? "," : ""); + strcat(rs, rss); + } + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') { - isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info); - p[0]++; - } else { - for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) { + p[0]++; + if (*p[0] == '?') { + isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info); + p[0]++; + } else { + for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) { if (*p[0] != ',') { if ((*p[0] - 48) > maxdccval[i]) { PARSE_ERROR1; } rp[i] = *p[0] - 48; p[0]++; - if (*p[0] == ',') + if (*p[0] == ',') p[0]++; - } else p[0]++; + } else + p[0]++; } #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n", - rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); + printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n", + rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); #endif - } + } break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */ - if (!strncmp(p[0], "DIS", 3)) { + if (!strncmp(p[0], "DIS", 3)) { char *rp = &f->resolution; int i; - p[0] += 3; - switch(*p[0]) { + p[0] += 3; + switch (*p[0]) { case '?': p[0]++; - strcpy(rs, "\r\n"); - for(i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); + strcpy(rs, "\r\n"); + for (i = 0; i < 8; i++) { + sprintf(rss, "%c%s", rp[i] + 48, + (i < 7) ? "," : ""); + strcat(rs, rss); + } + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') { - isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info); - p[0]++; - } else { - for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) { + p[0]++; + if (*p[0] == '?') { + isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info); + p[0]++; + } else { + for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) { if (*p[0] != ',') { if ((*p[0] - 48) > maxdccval[i]) { PARSE_ERROR1; } rp[i] = *p[0] - 48; p[0]++; - if (*p[0] == ',') + if (*p[0] == ',') p[0]++; - } else p[0]++; + } else + p[0]++; } #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n", - rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); + printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n", + rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); #endif - } + } break; default: PARSE_ERROR1; } - return 0; - } - - /* DR - Receive Phase C data command, initiates document reception */ - if (!strncmp(p[0], "DR", 2)) { - p[0] += 2; + return 0; + } + /* DR - Receive Phase C data command, initiates document reception */ + if (!strncmp(p[0], "DR", 2)) { + p[0] += 2; if ((info->faxonline & 16) && /* incoming connection */ - ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) { + ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) { #ifdef ISDN_TTY_FAX_STAT_DEBUG printk(KERN_DEBUG "isdn_tty: Fax FDR\n"); #endif @@ -735,11 +842,11 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) isdn_command(&cmd); if (f->phase == ISDN_FAX_PHASE_B) { f->phase = ISDN_FAX_PHASE_C; - } else if (f->phase == ISDN_FAX_PHASE_D) { - switch(f->fet) { + } else if (f->phase == ISDN_FAX_PHASE_D) { + switch (f->fet) { case 0: /* next page will be received */ f->phase = ISDN_FAX_PHASE_C; - isdn_tty_fax_modem_result(7, info); /* CONNECT */ + isdn_tty_fax_modem_result(7, info); /* CONNECT */ break; case 1: /* next doc will be received */ f->phase = ISDN_FAX_PHASE_B; @@ -747,35 +854,36 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) case 2: /* fax session is terminating */ f->phase = ISDN_FAX_PHASE_E; break; - default: + default: PARSE_ERROR1; } } } else { PARSE_ERROR1; } - return 1; + return 1; } - /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */ - if (!strncmp(p[0], "DT", 2)) { - int i, val[]={4,0,2,3}; + if (!strncmp(p[0], "DT", 2)) { + int i, val[] = + {4, 0, 2, 3}; char *rp = &f->resolution; - p[0] += 2; - if (!info->faxonline & 1) /* not outgoing connection */ + p[0] += 2; + if (!info->faxonline & 1) /* not outgoing connection */ PARSE_ERROR1; - for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<4); i++) { + for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) { if (*p[0] != ',') { if ((*p[0] - 48) > maxdccval[val[i]]) { PARSE_ERROR1; } rp[val[i]] = *p[0] - 48; p[0]++; - if (*p[0] == ',') + if (*p[0] == ',') p[0]++; - } else p[0]++; + } else + p[0]++; } #ifdef ISDN_TTY_FAX_STAT_DEBUG printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n", @@ -789,48 +897,43 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) isdn_command(&cmd); if (f->phase == ISDN_FAX_PHASE_D) { f->phase = ISDN_FAX_PHASE_C; - isdn_tty_fax_modem_result(7, info); /* CONNECT */ + isdn_tty_fax_modem_result(7, info); /* CONNECT */ } } else { PARSE_ERROR1; } - return 1; - } - + return 1; + } /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */ - if (!strncmp(p[0], "ECM", 3)) { - p[0] += 3; + if (!strncmp(p[0], "ECM", 3)) { + p[0] += 3; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d",f->ecm); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->ecm); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0,2"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par != 0) && (par != 2)) - PARSE_ERROR1; - f->ecm = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0,2"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par != 0) && (par != 2)) + PARSE_ERROR1; + f->ecm = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* ET=n - End of page or document */ if (!strncmp(p[0], "ET=", 3)) { p[0] += 3; @@ -857,7 +960,6 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) } return 0; } - /* K - terminate */ if (!strncmp(p[0], "K", 1)) { p[0] += 1; @@ -866,205 +968,191 @@ int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) isdn_tty_modem_hup(info, 1); return 1; } - /* LID=string - local fax ID */ - if (!strncmp(p[0], "LID", 3)) { + if (!strncmp(p[0], "LID", 3)) { int i, r; - p[0] += 3; + p[0] += 3; switch (*p[0]) { case '?': p[0]++; sprintf(rs, "\r\n\"%s\"", f->id); - isdn_tty_at_cout(rs, info); - break; + isdn_tty_at_cout(rs, info); + break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n\"STRING\""); - isdn_tty_at_cout(rs, info); - } - else - { - if (*p[0] =='"') - p[0]++; - for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++) - { - f->id[i] = *p[0]++; - } - if (*p[0] =='"') - p[0]++; - for(r=i; r < FAXIDLEN; r++) - { - f->id[r] = 32; - } - f->id[FAXIDLEN-1] = 0; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n\"STRING\""); + isdn_tty_at_cout(rs, info); + } else { + if (*p[0] == '"') + p[0]++; + for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) { + f->id[i] = *p[0]++; + } + if (*p[0] == '"') + p[0]++; + for (r = i; r < FAXIDLEN; r++) { + f->id[r] = 32; + } + f->id[FAXIDLEN - 1] = 0; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id); + printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* MDL? - DCE Model */ - if (!strncmp(p[0], "MDL?", 4)) { - p[0] += 4; + if (!strncmp(p[0], "MDL?", 4)) { + p[0] += 4; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FMDL?\n"); + printk(KERN_DEBUG "isdn_tty: FMDL?\n"); #endif - isdn_tty_at_cout("\r\nisdn4linux", info); - return 0; - } - + isdn_tty_at_cout("\r\nisdn4linux", info); + return 0; + } /* MFR? - DCE Manufacturer */ - if (!strncmp(p[0], "MFR?", 4)) { - p[0] += 4; + if (!strncmp(p[0], "MFR?", 4)) { + p[0] += 4; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FMFR?\n"); + printk(KERN_DEBUG "isdn_tty: FMFR?\n"); #endif - isdn_tty_at_cout("\r\nisdn4linux", info); - return 0; - } - + isdn_tty_at_cout("\r\nisdn4linux", info); + return 0; + } /* MINSP=n - Minimum Speed for Phase C */ - if (!strncmp(p[0], "MINSP", 5)) { - p[0] += 5; + if (!strncmp(p[0], "MINSP", 5)) { + p[0] += 5; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d",f->minsp); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->minsp); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0-5"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 5)) - PARSE_ERROR1; - f->minsp = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0-5"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 5)) + PARSE_ERROR1; + f->minsp = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* PHCTO=value - DTE phase C timeout */ - if (!strncmp(p[0], "PHCTO", 5)){ - p[0] +=5; + if (!strncmp(p[0], "PHCTO", 5)) { + p[0] += 5; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d",f->phcto); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->phcto); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->phcto = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->phcto = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* REL=n - Phase C received EOL alignment */ - if (!strncmp(p[0], "REL", 3)) { - p[0] += 3; + if (!strncmp(p[0], "REL", 3)) { + p[0] += 3; switch (*p[0]) { case '?': p[0]++; - sprintf(rs, "\r\n%d",f->rel); - isdn_tty_at_cout(rs, info); + sprintf(rs, "\r\n%d", f->rel); + isdn_tty_at_cout(rs, info); break; case '=': - p[0]++; - if (*p[0] == '?') - { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } - else - { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->rel = par; + p[0]++; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } else { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->rel = par; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par); + printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par); #endif - } - break; + } + break; default: PARSE_ERROR1; } - return 0; - } - + return 0; + } /* REV? - DCE Revision */ - if (!strncmp(p[0], "REV?", 4)) { - p[0] += 4; + if (!strncmp(p[0], "REV?", 4)) { + p[0] += 4; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FREV?\n"); + printk(KERN_DEBUG "isdn_tty: FREV?\n"); #endif strcpy(rss, isdn_tty_fax_revision); sprintf(rs, "\r\nRev: %s", isdn_getrev(rss)); - isdn_tty_at_cout(rs, info); - return 0; - } - + isdn_tty_at_cout(rs, info); + return 0; + } /* Phase C Transmit Data Block Size */ - if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */ + if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */ p[0] += 4; #ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]); + printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]); #endif - switch (*p[0]) { - case '0': - p[0]++; - break; - default: - PARSE_ERROR1; - } - return 0; + switch (*p[0]) { + case '0': + p[0]++; + break; + default: + PARSE_ERROR1; + } + return 0; } - - printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]); + printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]); PARSE_ERROR1; } +int +isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) +{ + if (TTY_IS_FCLASS2(info)) + return (isdn_tty_cmd_FCLASS2(p, info)); + else if (TTY_IS_FCLASS1(info)) + return (isdn_tty_cmd_FCLASS1(p, info)); + PARSE_ERROR1; +} diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c index 14586e59e1a1..3b6b25f1cc2b 100644 --- a/drivers/misc/parport_pc.c +++ b/drivers/misc/parport_pc.c @@ -839,11 +839,6 @@ static int probe_one_port(unsigned long int base, * Put the ECP detected port in the more PS2 like mode. */ parport_pc_write_econtrol(p, 0x34); - parport_pc_write_control(p, 0x8); - parport_pc_write_data(p, 0); - udelay (50); - parport_pc_write_control(p, 0xc); - udelay (50); if (parport_probe_hook) (*parport_probe_hook)(p); diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 2c7c31792763..be750fb56ba8 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -18,6 +18,7 @@ fi endmenu tristate 'Dummy net driver support' CONFIG_DUMMY +tristate 'Bonding driver support' CONFIG_BONDING tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_NETLINK" = "y" ]; then diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a911f7970dfa..6e511616a6bb 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -366,6 +366,14 @@ else endif endif +ifeq ($(CONFIG_BONDING),y) +L_OBJS += bonding.o +else + ifeq ($(CONFIG_BONDING),m) + M_OBJS += bonding.o + endif +endif + ifeq ($(CONFIG_DE600),y) L_OBJS += de600.o else diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 31dbcad86110..5a0e026a0eba 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -120,7 +120,7 @@ extern int via_rhine_probe(struct device *dev); extern int tc515_probe(struct device *dev); extern int lance_probe(struct device *dev); extern int rcpci_probe(struct device *); -extern int dmfe_reg_board(struct device *); +extern int dmfe_probe(struct device *); /* Gigabit Ethernet adapters */ extern int yellowfin_probe(struct device *dev); @@ -227,7 +227,7 @@ struct devprobe pci_probes[] __initdata = { #endif #ifdef CONFIG_DM9102 - {dmfe_reg_board, 0}, + {dmfe_probe, 0}, #endif #ifdef CONFIG_YELLOWFIN @@ -243,7 +243,7 @@ struct devprobe pci_probes[] __initdata = { {via_rhine_probe, 0}, #endif #ifdef CONFI_NET_DM9102 - {dmfe_reg_board, 0}, + {dmfe_probe, 0}, #endif {NULL, 0}, }; diff --git a/drivers/net/bonding.c b/drivers/net/bonding.c new file mode 100644 index 000000000000..7de7b39fe369 --- /dev/null +++ b/drivers/net/bonding.c @@ -0,0 +1,353 @@ +/* + * originally based on the dummy device. + * + * Copyright 1999, Thomas Davis, tadavis@lbl.gov. + * Licensed under the GPL. Based on dummy.c, and eql.c devices. + * + * bond.c: a bonding/etherchannel/sun trunking net driver + * + * This is useful to talk to a Cisco 5500, running Etherchannel, aka: + * Linux Channel Bonding + * Sun Trunking (Solaris) + * + * How it works: + * ifconfig bond0 ipaddress netmask up + * will setup a network device, with an ip address. No mac address + * will be assigned at this time. The hw mac address will come from + * the first slave bonded to the channel. All slaves will then use + * this hw mac address. + * + * ifconfig bond0 down + * will release all slaves, marking them as down. + * + * ifenslave bond0 eth0 + * will attache eth0 to bond0 as a slave. eth0 hw mac address will either + * a: be used as initial mac address + * b: if a hw mac address already is there, eth0's hw mac address + * will then be set from bond0. + * + * v0.1 - first working version. + * v0.2 - changed stats to be calculated by summing slaves stats. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static int bond_xmit(struct sk_buff *skb, struct device *dev); +static struct net_device_stats *bond_get_stats(struct device *dev); + +static int bond_open(struct device *dev) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int bond_close(struct device *master) +{ + bonding_t *private = (struct bonding *) master->priv; + slave_queue_t *queue = (struct slave_queue *) private->queue; + slave_t *slave, *next; + + for( slave=queue->head; slave != NULL; slave=next) { +#ifdef BONDING_DEBUG + printk("freeing = %s\n", slave->dev->name); +#endif + slave->dev->flags &= ~IFF_SLAVE; + slave->dev->slave = NULL; + next = slave->next; + kfree(slave); + queue->num_slaves++; + } + + MOD_DEC_USE_COUNT; + return 0; +} + +/* fake multicast ability */ +static void set_multicast_list(struct device *dev) +{ +} + +static int bond_enslave(struct device *master, struct device *slave) +{ + bonding_t *private = (struct bonding *) master->priv; + slave_queue_t *queue = (struct slave_queue *) private->queue; + slave_t *new_slave; + int flags; + + if (master == NULL || slave == NULL) + return -ENODEV; + +#ifdef BONDING_DEBUG + printk (KERN_WARNING "%s: enslaving '%s'\n", master->name, slave->name); +#endif + + save_flags(flags); + cli(); + + /* not running. */ + if ((slave->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { + restore_flags(flags); + return -EINVAL; + } + + /* already enslaved */ + if (master->flags & IFF_SLAVE || slave->flags & IFF_SLAVE) { + restore_flags(flags); + return -EBUSY; + } + + slave->slave = master; /* save the master in slave->slave */ + slave->flags |= IFF_SLAVE; + + if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + memset(new_slave, 0, sizeof(slave_t)); + + new_slave->dev = slave; + + if (queue->head == NULL) { + queue->head = new_slave; + queue->current_slave = queue->head; + } else { + queue->tail->next = new_slave; + } + + queue->tail = new_slave; + queue->num_slaves++; + + restore_flags(flags); + + return 0; +} + +static int bond_release(struct device *master, struct device *slave) +{ + printk (KERN_DEBUG "%s: releasing `%s`\n", master->name, slave->name); + + return -EINVAL; +} + +static int bond_sethwaddr(struct device *master, struct device *slave) +{ + memcpy(master->dev_addr, slave->dev_addr, slave->addr_len); + return 0; +} + +static int bond_ioctl(struct device *master, struct ifreq *ifr, int cmd) +{ + struct device *slave = dev_get(ifr->ifr_slave); + +#ifdef BONDING_DEBUG + printk("master=%s, slave=%s\n", master->name, slave->name); +#endif + + switch (cmd) { + case BOND_ENSLAVE: + return bond_enslave(master, slave); + case BOND_RELEASE: + return bond_release(master, slave); + case BOND_SETHWADDR: + return bond_sethwaddr(master, slave); + default: + return -EOPNOTSUPP; + } +} + +#ifdef CONFIG_NET_FASTROUTE +static int bond_accept_fastpath(struct device *dev, struct dst_entry *dst) +{ + return -1; +} +#endif + +__initfunc(int bond_init(struct device *dev)) +{ + bonding_t *bond; + + /* Initialize the device structure. */ + dev->hard_start_xmit = bond_xmit; + + dev->priv = kmalloc(sizeof(struct bonding), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + + memset(dev->priv, 0, sizeof(struct bonding)); + + bond = (struct bonding *) dev->priv; + + bond->queue = kmalloc(sizeof(struct slave_queue), GFP_KERNEL); + if (bond->queue == NULL) + return -ENOMEM; + + memset(bond->queue, 0, sizeof(struct slave_queue)); + + bond->stats = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + if (bond->stats == NULL) + return -ENOMEM; + + memset(bond->stats, 0, sizeof(struct enet_statistics)); + + dev->get_stats = bond_get_stats; + + dev->open = bond_open; + dev->stop = bond_close; + dev->set_multicast_list = set_multicast_list; + + dev->do_ioctl = bond_ioctl; + + /* Fill in the fields of the device structure with ethernet-generic + values. */ + ether_setup(dev); + dev->tx_queue_len = 0; + dev->flags |= (IFF_MASTER|IFF_MULTICAST); +#ifdef CONFIG_NET_FASTROUTE + dev->accept_fastpath = bond_accept_fastpath; +#endif + + return 0; +} + +static int bond_xmit(struct sk_buff *skb, struct device *dev) +{ + struct device *slave; + struct bonding *bond = (struct bonding *) dev->priv; + struct slave_queue *queue = bond->queue; + int good = 0; + + while (good == 0) { + slave = queue->current_slave->dev; + if (slave->flags & (IFF_UP|IFF_RUNNING)) { + skb->dev = slave; + skb->priority = 1; + dev_queue_xmit(skb); + good = 1; + } + if (queue->current_slave->next != NULL) { + queue->current_slave = queue->current_slave->next; + } else { + queue->current_slave = queue->head; + } + } + + return 0; +} + +static struct net_device_stats *bond_get_stats(struct device *dev) +{ + bonding_t *private = dev->priv; + slave_queue_t *queue = private->queue; + struct net_device_stats *stats = private->stats, *sstats; + slave_t *slave; + + memset(private->stats, 0, sizeof(struct net_device_stats)); + for (slave=queue->head; slave != NULL; slave=slave->next) { + sstats = slave->dev->get_stats(slave->dev); + + stats->rx_packets += sstats->rx_packets; + stats->rx_bytes += sstats->rx_bytes; + stats->rx_errors += sstats->rx_errors; + stats->rx_dropped += sstats->rx_dropped; + + stats->tx_packets += sstats->tx_packets; + stats->tx_bytes += sstats->tx_bytes; + stats->tx_errors += sstats->tx_errors; + stats->tx_dropped += sstats->tx_dropped; + + stats->multicast += sstats->multicast; + stats->collisions += sstats->collisions; + + stats->rx_length_errors += sstats->rx_length_errors; + stats->rx_over_errors += sstats->rx_over_errors; + stats->rx_crc_errors += sstats->rx_crc_errors; + stats->rx_frame_errors += sstats->rx_frame_errors; + stats->rx_fifo_errors += sstats->rx_fifo_errors; + stats->rx_missed_errors += sstats->rx_missed_errors; + + stats->tx_aborted_errors += sstats->tx_aborted_errors; + stats->tx_carrier_errors += sstats->tx_carrier_errors; + stats->tx_fifo_errors += sstats->tx_fifo_errors; + stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; + stats->tx_window_errors += sstats->tx_window_errors; + + } + + return stats; +} + +#ifdef MODULE + +__initfunc(static int bond_probe(struct device *dev)) +{ + bond_init(dev); + return 0; +} + +static char bond_name[16]; + +static struct device dev_bond = { + bond_name, /* Needs to be writeable */ + 0, 0, 0, 0, + 0x0, 0, + 0, 0, 0, NULL, bond_probe }; + +int init_module(void) +{ + /* Find a name for this unit */ + int err=dev_alloc_name(&dev_bond,"bond%d"); + + if (err<0) + return err; + + if (register_netdev(&dev_bond) != 0) + return -EIO; + + return 0; +} + +void cleanup_module(void) +{ + struct bonding *bond = (struct bonding *) dev_bond.priv; + + unregister_netdev(&dev_bond); + + kfree(bond->queue); + kfree(bond->stats); + kfree(dev_bond.priv); + + dev_bond.priv = NULL; +} +#endif /* MODULE */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c index b5085d2b39bc..029dc187e28f 100644 --- a/drivers/net/dmfe.c +++ b/drivers/net/dmfe.c @@ -283,7 +283,7 @@ static unsigned long CrcTable[256] = }; /* function declaration ------------------------------------- */ -static int dmfe_probe(struct device *); +int dmfe_probe(struct device *); static int dmfe_open(struct device *); static int dmfe_start_xmit(struct sk_buff *, struct device *); static int dmfe_stop(struct device *); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 87b05d63c00e..c67ffcc70c57 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -6,7 +6,7 @@ * Status: Stable. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Wed Jan 19 08:59:16 2000 + * Modified at: Wed Jan 26 13:00:29 2000 * Modified by: Dag Brattli * * Copyright (c) 1998-2000 Dag Brattli @@ -163,10 +163,6 @@ int __init nsc_ircc_init(void) int reg; int i = 0; -#ifdef CONFIG_APM - apm_register_callback(nsc_ircc_apmproc); -#endif /* CONFIG_APM */ - /* Probe for all the NSC chipsets we know about */ for (chip=chips; chip->name ; chip++,i++) { IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", @@ -219,6 +215,12 @@ int __init nsc_ircc_init(void) } } +#ifdef CONFIG_APM + /* Make sure at least one chip was found before enabling APM */ + if (ret == 0) + apm_register_callback(nsc_ircc_apmproc); +#endif /* CONFIG_APM */ + return ret; } @@ -1207,7 +1209,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct device *dev) } out: /* Not busy transmitting anymore if window is not full */ - if (self->tx_fifo.free < MAX_WINDOW) + if (self->tx_fifo.free < MAX_TX_WINDOW) dev->tbusy = 0; /* Restore bank register */ @@ -1354,7 +1356,7 @@ static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self) } /* Make sure we have room for more frames */ - if (self->tx_fifo.free < MAX_WINDOW) { + if (self->tx_fifo.free < MAX_TX_WINDOW) { /* Not busy transmitting anymore */ self->netdev->tbusy = 0; @@ -1442,20 +1444,21 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) /* Read all entries in status FIFO */ switch_bank(iobase, BANK5); - while (((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) && - (st_fifo->tail < MAX_WINDOW)) - { - st_fifo->entries[st_fifo->tail].status = status; + while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { + /* We must empty the status FIFO no matter what */ + len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); - len = inb(iobase+RFLFL) | (inb(iobase+RFLFH) << 8); - + if (st_fifo->tail >= MAX_RX_WINDOW) + continue; + + st_fifo->entries[st_fifo->tail].status = status; st_fifo->entries[st_fifo->tail].len = len; st_fifo->pending_bytes += len; st_fifo->tail++; st_fifo->len++; } /* Try to process all entries in status FIFO */ - while (st_fifo->len) { + while (st_fifo->len > 0) { /* Get first entry */ status = st_fifo->entries[st_fifo->head].status; len = st_fifo->entries[st_fifo->head].len; @@ -1662,8 +1665,8 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, bank = inb(iobase+BSR); - /* Status event, or end of frame detected in FIFO */ - if (eir & (EIR_SFIF_EV|EIR_LS_EV)) { + /* Status FIFO event*/ + if (eir & EIR_SFIF_EV) { if (nsc_ircc_dma_receive_complete(self, iobase)) { /* Wait for next status FIFO interrupt */ self->ier = IER_SFIF_IE; @@ -1678,7 +1681,7 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, /* Start timer */ outb(IRCR1_TMR_EN, iobase+IRCR1); - self->ier = IER_TMR_IE; + self->ier = IER_TMR_IE | IER_SFIF_IE; } } else if (eir & EIR_TMR_EV) { /* Timer finished */ /* Disable timer */ @@ -1709,7 +1712,7 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, /* Prepare for receive */ nsc_ircc_dma_receive(self); - self->ier = IER_LS_IE|IER_SFIF_IE; + self->ier = IER_SFIF_IE; } } else { /* Not finished yet, so interrupt on DMA again */ diff --git a/drivers/net/lmc/lmc_main.c b/drivers/net/lmc/lmc_main.c index 44a08406fdc7..711bcab44b1e 100644 --- a/drivers/net/lmc/lmc_main.c +++ b/drivers/net/lmc/lmc_main.c @@ -313,7 +313,7 @@ static int lmc_ioctl (struct device *dev, struct ifreq *ifr, int cmd) /*fold00*/ /* the watchdog process that cruises around */ -static void lmc_watchdog (unsigned long data) /*FOLD00*/ +static void lmc_watchdog (unsigned long data) /*fold00*/ { struct device *dev = (struct device *) data; lmc_softc_t *sc; @@ -483,9 +483,9 @@ static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fol /* * Switch to common hdlc%d naming. We name by type not by vendor */ - dev->name = (char *)(dev+1); + dev->name = (char *) (((u32) (dev)) + sizeof (struct ppp_device)); dev_alloc_name(dev, "hdlc%d"); - + Lmc_Count++; if(lmc_first_load == 0){ @@ -504,10 +504,7 @@ static struct device *lmc_probe1 (struct device *dev, int ioaddr, int irq, /*fol * Allocate space for the private data structure */ - /* FIXME: we adjust to 8 byte align, but we then kfree the adjusted value - BUG BUG BUG - fortunately kmalloc will be 8 byte aligned.. */ - - sc = (void *) (((long) kmalloc (sizeof (lmc_softc_t), GFP_KERNEL) + 7) & ~7); + sc = kmalloc (sizeof (lmc_softc_t), GFP_KERNEL); if (sc == NULL) { printk (KERN_WARNING "%s: Cannot allocate memory for device state\n", dev->name); @@ -923,7 +920,6 @@ static int lmc_close (struct device *dev) /*fold00*/ del_timer (&sc->timer); sppp_close (dev); lmc_ifdown (dev); - printk(KERN_DEBUG "%s: Close ran\n", dev->name); return 0; } @@ -1315,7 +1311,7 @@ lmc_start_xmit_bug_out: } -static int lmc_rx (struct device *dev) /*FOLD00*/ +static int lmc_rx (struct device *dev) /*fold00*/ { lmc_softc_t *sc; int i; diff --git a/drivers/net/olympic.c b/drivers/net/olympic.c index afe32c11f743..bd59802d71dc 100644 --- a/drivers/net/olympic.c +++ b/drivers/net/olympic.c @@ -23,10 +23,11 @@ * 6/8/99 - Official Release 0.2.0 * Merged into the kernel code * - * To Do: - * - * Sanitize for smp + * 1/10/00 - Added Spinlocks for smp. * + * To Do: + * IPv6 Multicast + * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult @@ -71,6 +72,7 @@ #include #include #include +#include #include "olympic.h" @@ -83,7 +85,7 @@ */ static char *version = -"Olympic.c v0.2.0 6/8/99 - Peter De Schrijver & Mike Phillips" ; +"Olympic.c v0.2.1 1/10/00 - Peter De Schrijver & Mike Phillips" ; static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", "Address Verification", "Neighbor Notification (Ring Poll)", @@ -245,6 +247,8 @@ __initfunc(static int olympic_init(struct device *dev)) } } + spin_lock_init(&olympic_priv->olympic_lock) ; + #if OLYMPIC_DEBUG printk("BCTL: %x\n",readl(olympic_mmio+BCTL)); printk("GPR: %x\n",readw(olympic_mmio+GPR)); @@ -751,6 +755,8 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ return ; + spin_lock(&olympic_priv->olympic_lock) ; + if (dev->interrupt) printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; @@ -829,15 +835,19 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) dev->interrupt = 0 ; writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); - + spin_unlock(&olympic_priv->olympic_lock) ; } static int olympic_xmit(struct sk_buff *skb, struct device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; - __u8 *olympic_mmio=olympic_priv->olympic_mmio; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + unsigned long flags ; + + spin_lock_irqsave(&olympic_priv->olympic_lock, flags) ; if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags) ; return 1; } @@ -854,10 +864,12 @@ static int olympic_xmit(struct sk_buff *skb, struct device *dev) writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1); dev->tbusy=0; - + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags) ; return 0; - } else + } else { + spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags) ; return 1; + } } diff --git a/drivers/net/olympic.h b/drivers/net/olympic.h index 56830317b6d3..089a3f49abcc 100644 --- a/drivers/net/olympic.h +++ b/drivers/net/olympic.h @@ -244,6 +244,8 @@ struct olympic_private { __u8 *olympic_mmio; __u8 *olympic_lap; + spinlock_t olympic_lock ; + volatile int srb_queued; /* True if an SRB is still posted */ struct wait_queue *srb_wait; diff --git a/drivers/pnp/parport_probe.c b/drivers/pnp/parport_probe.c index 8ae499311fc2..11728ea9bc18 100644 --- a/drivers/pnp/parport_probe.c +++ b/drivers/pnp/parport_probe.c @@ -96,6 +96,7 @@ int parport_probe(struct parport *port, char *buffer, int len) struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev); int result = 0; + int lives = 1; if (!dev) { printk("%s: unable to register for probe.\n", port->name); @@ -104,6 +105,7 @@ int parport_probe(struct parport *port, char *buffer, int len) parport_claim_or_block(dev); + try_again: switch (parport_ieee1284_nibble_mode_ok(port, 4)) { case 2: current->state=TASK_INTERRUPTIBLE; @@ -116,6 +118,20 @@ int parport_probe(struct parport *port, char *buffer, int len) break; } + if (result < 1 && lives--) { + /* Reset the peripherals and try again. */ + parport_pc_write_control(port, 0x8); + parport_pc_write_data(port, 0); + udelay (50); + parport_pc_write_control(port, 0xc); + udelay (500); + goto try_again; + } + + printk (KERN_DEBUG "parport_probe: %s%s\n", + lives ? "" : "after reset: ", + result < 1 ? "failed" : "succeeded"); + parport_release(dev); parport_unregister_device(dev); diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index 2f96d3ba9f08..8e712af0e20d 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -10393,7 +10393,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) * instead of slowing down if those exist. That's hard to do with simple * checksums though. */ - if(aic7xxx_verbose & VERBOSE_NEGOTIATION) + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "reducing SCSI transfer speed due to Domain " "validation failure.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -10424,7 +10424,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) } else { - if(aic7xxx_verbose & VERBOSE_NEGOTIATION) + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Performing Domain validation.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -10449,7 +10449,7 @@ aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) } else { - if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) && + if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && (p->needdv & (1<sense_buffer[2] == ILLEGAL_REQUEST) { if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten) { - rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0; + if (SCpnt->cmnd[0] == READ_10 || SCpnt->cmnd[0] == WRITE_10 || + SCpnt->sense_buffer[12] == 0x20) + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0; requeue_sd_request(SCpnt); result = 0; } else { @@ -1016,7 +1021,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) this_count = this_count << 1; } - if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) + if (((this_count > 0xff) || (block > 0x1fffff)) || rscsi_disks[dev].ten) { if (this_count > 0xffff) this_count = 0xffff; diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index 1e511af0b72f..9117400a1c84 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c @@ -35,13 +35,13 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) QNX4DEBUG(("filp->f_pos = %ld\n", (long) filp->f_pos)); while (filp->f_pos < inode->i_size) { - blknum = qnx4_block_map( inode, filp->f_pos / QNX4_BLOCK_SIZE ); + blknum = qnx4_block_map( inode, filp->f_pos >> QNX4_BLOCK_SIZE_SHIFT ); bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE); if(bh==NULL) { printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum); break; } - ix = (filp->f_pos / QNX4_DIR_ENTRY_SIZE - (filp->f_pos / QNX4_BLOCK_SIZE) * QNX4_INODES_PER_BLOCK) % QNX4_INODES_PER_BLOCK; + ix = ( (filp->f_pos >> QNX4_DIR_ENTRY_SIZE_SHIFT) - (filp->f_pos >> QNX4_BLOCK_SIZE_SHIFT) * QNX4_INODES_PER_BLOCK) & QNX4_INODES_PER_BLOCK_MASK; while (ix < QNX4_INODES_PER_BLOCK) { offset = ix * QNX4_DIR_ENTRY_SIZE; de = (struct qnx4_inode_entry *) (bh->b_data + offset); diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h new file mode 100644 index 000000000000..91b2764218d5 --- /dev/null +++ b/include/linux/if_bonding.h @@ -0,0 +1,59 @@ +/* + * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. + * + * + * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes + * NCM: Network and Communications Management, Inc. + * + * BUT, I'm the one who modified it for ethernet, so: + * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + */ + +#ifndef _LINUX_IF_BONDING_H +#define _LINUX_IF_BONDING_H + +#include + +#define BOND_ENSLAVE (SIOCDEVPRIVATE) +#define BOND_RELEASE (SIOCDEVPRIVATE + 1) +#define BOND_SETHWADDR (SIOCDEVPRIVATE + 2) + +typedef struct slave { + struct device *dev; + struct slave *next; + struct slave *prev; +} slave_t; + +typedef struct slave_queue { + slave_t *head; + slave_t *tail; + slave_t *current_slave; + int num_slaves; + struct device *master_dev; + char lock; +} slave_queue_t; + +typedef struct bonding { + slave_queue_t *queue; + int min_slaves; + int max_slaves; + struct net_device_stats *stats; + struct timer_list timer; + char timer_on; +} bonding_t; + +#endif /* _LINUX_BOND_H */ + +/* + * Local variables: + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/include/linux/isdn.h b/include/linux/isdn.h index a0a0b0fa70be..2ef651e19ad8 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.81 1999/10/27 21:21:18 detabc Exp $ +/* $Id: isdn.h,v 1.88 2000/01/20 19:59:43 keil Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,43 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.88 2000/01/20 19:59:43 keil + * Add FAX Class 1 support + * + * Revision 1.87 2000/01/09 20:43:15 detabc + * exand logical bind-group's for both call's (in and out). + * add first part of kernel-config-help for abc-extension. + * + * Revision 1.86 1999/12/05 16:06:09 detabc + * add resethandling for rawip-compression. + * at now all B2-Protocols are usable with rawip-compression + * + * Revision 1.85 1999/11/30 11:29:06 detabc + * add a on the fly frame-counter and limit + * + * Revision 1.84 1999/11/28 14:49:08 detabc + * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the + * uncompressed size. + * + * Revision 1.83 1999/11/26 15:54:59 detabc + * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol. + * + * Revision 1.82 1999/11/20 22:14:14 detabc + * added channel dial-skip in case of external use + * (isdn phone or another isdn device) on the same NTBA. + * usefull with two or more card's connected the different NTBA's. + * global switchable in kernel-config and also per netinterface. + * + * add auto disable of netinterface's in case of: + * to many connection's in short time. + * config mistakes (wrong encapsulation, B2-protokoll or so on) on local + * or remote side. + * wrong password's or something else to a ISP (syncppp). + * + * possible encapsulations for this future are: + * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP, + * and ISDN_NET_ENCAP_CISCOHDLCK. + * * Revision 1.81 1999/10/27 21:21:18 detabc * Added support for building logically-bind-group's per interface. * usefull for outgoing call's with more then one isdn-card. @@ -333,6 +370,10 @@ #undef CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR #undef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER #undef CONFIG_ISDN_WITH_ABC_ICALL_BIND +#undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE +#undef CONFIG_ISDN_WITH_ABC_CONN_ERROR +#undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS +#undef CONFIG_ISDN_WITH_ABC_FRAME_LIMIT /* New ioctl-codes */ @@ -359,6 +400,7 @@ #define IIOCGETCPS _IO('I',21) #define IIOCGETDVR _IO('I',22) #define IIOCNETLCR _IO('I',23) /* dwabc ioctl for LCR from isdnlog */ +#define IIOCNETDWRSET _IO('I',24) /* dwabc ioctl to reset abc-values to default on a net-interface */ #define IIOCNETALN _IO('I',32) #define IIOCNETDLN _IO('I',33) @@ -923,6 +965,7 @@ typedef struct isdn_devt { isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */ struct semaphore sem; /* serialize list access*/ isdn_module *modules; + unsigned long global_features; } isdn_dev; extern isdn_dev *dev; diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index 07e3b826df91..209cd9d81ee7 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.32 1999/10/11 22:03:00 keil Exp $ +/* $Id: isdnif.h,v 1.33 2000/01/20 19:59:43 keil Exp $ * * Linux ISDN subsystem * @@ -22,6 +22,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnif.h,v $ + * Revision 1.33 2000/01/20 19:59:43 keil + * Add FAX Class 1 support + * * Revision 1.32 1999/10/11 22:03:00 keil * COMPAT_NEED_UACCESS (no include in isdn_compat.h) * @@ -175,10 +178,11 @@ /* * Values for Layer-3-protocol-selection */ -#define ISDN_PROTO_L3_TRANS 0 /* Transparent */ -#define ISDN_PROTO_L3_TRANSDSP 1 /* Transparent with DSP */ -#define ISDN_PROTO_L3_FAX 2 /* Fax Group 2/3 */ -#define ISDN_PROTO_L3_MAX 7 /* Max. 8 Protocols */ +#define ISDN_PROTO_L3_TRANS 0 /* Transparent */ +#define ISDN_PROTO_L3_TRANSDSP 1 /* Transparent with DSP */ +#define ISDN_PROTO_L3_FCLASS2 2 /* Fax Group 2/3 CLASS 2 */ +#define ISDN_PROTO_L3_FCLASS1 3 /* Fax Group 2/3 CLASS 1 */ +#define ISDN_PROTO_L3_MAX 7 /* Max. 8 Protocols */ #ifdef __KERNEL__ @@ -362,7 +366,8 @@ typedef struct /* Layer 3 */ #define ISDN_FEATURE_L3_TRANS (0x10000 << ISDN_PROTO_L3_TRANS) #define ISDN_FEATURE_L3_TRANSDSP (0x10000 << ISDN_PROTO_L3_TRANSDSP) -#define ISDN_FEATURE_L3_FAX (0x10000 << ISDN_PROTO_L3_FAX) +#define ISDN_FEATURE_L3_FCLASS2 (0x10000 << ISDN_PROTO_L3_FCLASS2) +#define ISDN_FEATURE_L3_FCLASS1 (0x10000 << ISDN_PROTO_L3_FCLASS1) #define ISDN_FEATURE_L3_MASK (0x0FF0000) /* Max. 8 Protocols */ #define ISDN_FEATURE_L3_SHIFT (16) @@ -463,6 +468,33 @@ typedef struct T30_s { #endif /* TTY_FAX */ +#define ISDN_FAX_CLASS1_FAE 0 +#define ISDN_FAX_CLASS1_FTS 1 +#define ISDN_FAX_CLASS1_FRS 2 +#define ISDN_FAX_CLASS1_FTM 3 +#define ISDN_FAX_CLASS1_FRM 4 +#define ISDN_FAX_CLASS1_FTH 5 +#define ISDN_FAX_CLASS1_FRH 6 +#define ISDN_FAX_CLASS1_CTRL 7 + +#define ISDN_FAX_CLASS1_OK 0 +#define ISDN_FAX_CLASS1_CONNECT 1 +#define ISDN_FAX_CLASS1_NOCARR 2 +#define ISDN_FAX_CLASS1_ERROR 3 +#define ISDN_FAX_CLASS1_FCERROR 4 +#define ISDN_FAX_CLASS1_QUERY 5 + +typedef struct { + __u8 cmd; + __u8 subcmd; + __u8 para[50]; +} aux_s; + +#define AT_COMMAND 0 +#define AT_EQ_VALUE 1 +#define AT_QUERY 2 +#define AT_EQ_QUERY 3 + /* CAPI structs */ /* this is compatible to the old union size */ @@ -494,13 +526,14 @@ typedef struct { int command; /* Command or Status (see above) */ ulong arg; /* Additional Data */ union { - ulong errcode; /* Type of error with STAT_L1ERR */ - int length; /* Amount of bytes sent with STAT_BSENT */ - u_char num[50];/* Additional Data */ + ulong errcode; /* Type of error with STAT_L1ERR */ + int length; /* Amount of bytes sent with STAT_BSENT */ + u_char num[50]; /* Additional Data */ setup_parm setup;/* For SETUP msg */ capi_msg cmsg; /* For CAPI like messages */ - char display[85];/* display message data */ - dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */ + char display[85];/* display message data */ + dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */ + aux_s aux; /* for modem commands/indications */ #ifdef CONFIG_ISDN_TTY_FAX T30_s *fax; /* Pointer to ttys fax struct */ #endif diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h index feb2cccac295..1cfd6558dd28 100644 --- a/include/linux/qnx4_fs.h +++ b/include/linux/qnx4_fs.h @@ -29,10 +29,12 @@ #define QNX4_VALID_FS 0x0001 /* Clean fs. */ #define QNX4_ERROR_FS 0x0002 /* fs has errors. */ #define QNX4_BLOCK_SIZE 0x200 /* blocksize of 512 bytes */ -#define QNX4_DIR_ENTRY_SIZE 0x040 /* dir entry size */ +#define QNX4_BLOCK_SIZE_SHIFT 9 +#define QNX4_DIR_ENTRY_SIZE 0x040 /* dir entry size of 64 bytes */ +#define QNX4_DIR_ENTRY_SIZE_SHIFT 6 #define QNX4_XBLK_ENTRY_SIZE 0x200 /* xblk entry size */ #define QNX4_INODES_PER_BLOCK 0x08 /* 512 / 64 */ - +#define QNX4_INODES_PER_BLOCK_MASK 0x07 /* for filenames */ #define QNX4_SHORT_NAME_MAX 16 #define QNX4_NAME_MAX 48 diff --git a/include/net/irda/nsc-ircc.h b/include/net/irda/nsc-ircc.h index 62a8c4cd901e..62c8d3a1edf6 100644 --- a/include/net/irda/nsc-ircc.h +++ b/include/net/irda/nsc-ircc.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Fri Nov 13 14:37:40 1998 - * Modified at: Thu Jan 13 18:27:38 2000 + * Modified at: Sun Jan 23 17:47:00 2000 * Modified by: Dag Brattli * * Copyright (c) 1998-2000 Dag Brattli @@ -204,10 +204,11 @@ struct st_fifo_entry { int len; }; -#define MAX_WINDOW 7 +#define MAX_TX_WINDOW 7 +#define MAX_RX_WINDOW 7 struct st_fifo { - struct st_fifo_entry entries[MAX_WINDOW]; + struct st_fifo_entry entries[MAX_RX_WINDOW]; int pending_bytes; int head; int tail; @@ -220,11 +221,11 @@ struct frame_cb { }; struct tx_fifo { - struct frame_cb queue[MAX_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 */ + 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 */ @@ -232,9 +233,6 @@ struct nsc_ircc_cb { struct st_fifo st_fifo; /* Info about received frames */ struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ - int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */ - int tx_len; /* Number of frames in tx_buff */ - struct device *netdev; /* Yes! we are some kind of netdevice */ struct net_device_stats stats; diff --git a/kernel/exit.c b/kernel/exit.c index 8343731c951f..66fc6fa6e0d7 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -473,6 +473,7 @@ repeat: if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED)) continue; read_unlock(&tasklist_lock); + current->state = TASK_RUNNING; /* We *must* do this before touching userspace! */ retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; if (!retval && stat_addr) retval = put_user((p->exit_code << 8) | 0x7f, stat_addr); @@ -485,6 +486,7 @@ repeat: current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime; current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime; read_unlock(&tasklist_lock); + current->state = TASK_RUNNING; /* We *must* do this before touching userspace! */ retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; if (!retval && stat_addr) retval = put_user(p->exit_code, stat_addr); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5406c5c57e6d..6b785b4c2907 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -210,6 +210,12 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order) */ if (!(current->flags & PF_MEMALLOC)) { int freed; + if (current->state != TASK_RUNNING && (gfp_mask & __GFP_WAIT)) { + printk("gfp called by non-running (%d) task from %p!\n", + current->state, __builtin_return_address(0)); + /* if we're not running, we can't sleep */ + gfp_mask &= ~__GFP_WAIT; + } if (nr_free_pages <= freepages.low) { wake_up_interruptible(&kswapd_wait); @@ -225,6 +231,9 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order) freed = try_to_free_pages(gfp_mask); current->flags &= ~PF_MEMALLOC; + if ((gfp_mask & __GFP_MED) && nr_free_pages > freepages.min / 2) + goto ok_to_allocate; + if (!freed && !(gfp_mask & __GFP_HIGH)) goto nopage; } diff --git a/net/core/dev.c b/net/core/dev.c index 0baa13711e03..3c4ba0301f19 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -784,6 +784,9 @@ void netif_rx(struct sk_buff *skb) #else netdev_dropping = 0; #endif + if (skb->dev->flags & IFF_SLAVE && skb->dev->slave) { + skb->dev = skb->dev->slave; + } skb_queue_tail(&backlog,skb); mark_bh(NET_BH); return; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e33e93895c3c..0a9e1ce6a6b3 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1283,6 +1283,9 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, continue; found_ok_skb: + /* Below we'll be accessing user memory, which might sleep, so... */ + current->state = TASK_RUNNING; + /* Lock the buffer. We can be fairly relaxed as * an interrupt will never steal a buffer we are * using unless I've missed something serious in @@ -1364,6 +1367,9 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, break; } + remove_wait_queue(sk->sleep, &wait); + current->state = TASK_RUNNING; + if(copied >= 0 && msg->msg_name) { tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) msg->msg_name); @@ -1371,9 +1377,6 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, *addr_len = tp->af_specific->sockaddr_len; } - remove_wait_queue(sk->sleep, &wait); - current->state = TASK_RUNNING; - /* Clean up data we have read: This will do ACK frames. */ cleanup_rbuf(sk, copied); release_sock(sk); diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index e79f45ee44bc..0a810af9c7fb 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -6,10 +6,10 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Oct 9 09:22:27 1999 - * Modified at: Sun Dec 12 12:24:32 1999 + * Modified at: Sun Jan 23 09:16:36 2000 * Modified by: Dag Brattli * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1999-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 @@ -55,7 +55,8 @@ #include extern int irtty_init(void); -extern int pc87108_init(void); +extern int nsc_ircc_init(void); +extern int ircc_init(void); extern int w83977af_init(void); extern int esi_init(void); extern int tekram_init(void); @@ -121,7 +122,7 @@ int __init irda_device_init( void) w83977af_init(); #endif #ifdef CONFIG_NSC_FIR - pc87108_init(); + nsc_ircc_init(); #endif #ifdef CONFIG_TOSHIBA_FIR toshoboe_init(); @@ -144,9 +145,6 @@ int __init irda_device_init( void) #ifdef CONFIG_LITELINK_DONGLE litelink_init(); #endif -#ifdef CONFIG_AIRPORT_DONGLE - airport_init(); -#endif #ifdef CONFIG_OLD_BELKIN old_belkin_init(); #endif -- 2.39.5