From be3ac86a4debc8071f43fed63931b10029a0047c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:31:31 -0500 Subject: [PATCH] Import 2.3.46pre2 --- Documentation/Configure.help | 96 +- Documentation/DMA-mapping.txt | 10 +- Documentation/isdn/00-INDEX | 3 + Documentation/isdn/CREDITS | 4 + Documentation/isdn/HiSax.cert | 12 +- Documentation/isdn/README | 12 +- Documentation/isdn/README.HiSax | 4 + Documentation/isdn/README.eicon | 20 +- Documentation/isdn/README.hysdn | 177 +++ Documentation/isdn/README.x25 | 16 +- Documentation/usb/usb-serial.txt | 14 - Makefile | 1 + arch/alpha/kernel/pci_iommu.c | 18 +- arch/arm/mm/consistent.c | 16 +- arch/i386/defconfig | 1 - arch/i386/kernel/acpi.c | 1 + arch/i386/kernel/io_apic.c | 1 - arch/i386/kernel/pci-dma.c | 18 +- arch/i386/kernel/pci-i386.c | 2 +- arch/i386/mm/init.c | 25 +- arch/ia64/kernel/pci-dma.c | 15 - arch/mips/jazz/floppy-jazz.c | 19 +- arch/mips/lib/floppy-std.c | 19 +- arch/ppc/config.in | 2 +- arch/ppc/kernel/misc.S | 25 +- arch/ppc/kernel/pci-dma.c | 18 +- arch/ppc/kernel/ppc_ksyms.c | 6 + arch/sparc/kernel/ioport.c | 22 +- arch/sparc/kernel/sparc_ksyms.c | 5 +- arch/sparc/kernel/sys_sparc.c | 95 +- arch/sparc/kernel/sys_sunos.c | 41 +- arch/sparc/kernel/systbls.S | 2 +- arch/sparc/lib/rwsem.S | 30 +- arch/sparc/mm/srmmu.c | 2 +- arch/sparc/mm/sun4c.c | 2 +- arch/sparc64/kernel/pci_iommu.c | 12 +- arch/sparc64/kernel/pci_sabre.c | 5 +- arch/sparc64/kernel/sbus.c | 12 +- arch/sparc64/kernel/smp.c | 4 +- arch/sparc64/kernel/sys_sparc.c | 112 +- arch/sparc64/kernel/sys_sparc32.c | 36 + arch/sparc64/kernel/sys_sunos32.c | 16 +- arch/sparc64/kernel/systbls.S | 6 +- arch/sparc64/mm/ultra.S | 6 +- arch/sparc64/solaris/misc.c | 16 +- drivers/block/Config.in | 4 +- drivers/block/floppy.c | 19 +- drivers/block/loop.c | 2 +- drivers/block/xd.c | 17 +- drivers/char/Config.in | 2 +- drivers/char/console.c | 106 +- drivers/char/dz.c | 1 + drivers/char/esp.c | 22 +- drivers/char/ftape/lowlevel/ftape-buffer.c | 18 +- drivers/char/isicom.c | 3 +- drivers/char/keyboard.c | 2 +- drivers/char/lp.c | 2 + drivers/char/pcxx.c | 1 - drivers/char/serial.c | 2 + drivers/char/serial167.c | 2 + drivers/char/tpqic02.c | 21 +- drivers/char/vc_screen.c | 225 ++- drivers/char/vme_scc.c | 1 + drivers/char/vt.c | 7 +- drivers/char/zr36120_mem.c | 15 +- drivers/isdn/Config.in | 127 +- drivers/isdn/Makefile | 6 +- drivers/isdn/avmb1/Makefile | 11 +- drivers/isdn/avmb1/avmcard.h | 31 +- drivers/isdn/avmb1/b1.c | 16 +- drivers/isdn/avmb1/b1dma.c | 983 ++++++++++++ drivers/isdn/avmb1/b1isa.c | 41 +- drivers/isdn/avmb1/b1pci.c | 295 +++- drivers/isdn/avmb1/b1pcmcia.c | 36 +- drivers/isdn/avmb1/c4.c | 1326 ++++++++++++++++ drivers/isdn/avmb1/capi.c | 19 +- drivers/isdn/avmb1/capidrv.c | 47 +- drivers/isdn/avmb1/kcapi.c | 120 +- drivers/isdn/avmb1/t1isa.c | 28 +- drivers/isdn/avmb1/t1pci.c | 964 +----------- drivers/isdn/divert/divert_procfs.c | 474 +++--- drivers/isdn/eicon/eicon.h | 32 +- drivers/isdn/eicon/eicon_dsp.h | 12 +- drivers/isdn/eicon/eicon_idi.c | 224 ++- drivers/isdn/eicon/eicon_idi.h | 21 +- drivers/isdn/eicon/eicon_io.c | 23 +- drivers/isdn/eicon/eicon_isa.c | 111 +- drivers/isdn/eicon/eicon_isa.h | 18 +- drivers/isdn/eicon/eicon_mod.c | 87 +- drivers/isdn/eicon/eicon_pci.c | 16 +- drivers/isdn/eicon/eicon_pci.h | 12 +- drivers/isdn/hisax/Makefile | 4 + drivers/isdn/hisax/arcofi.c | 17 +- drivers/isdn/hisax/arcofi.h | 7 +- drivers/isdn/hisax/asuscom.c | 12 +- drivers/isdn/hisax/avm_pci.c | 37 +- drivers/isdn/hisax/bkm_a4t.c | 16 +- drivers/isdn/hisax/bkm_a8.c | 12 +- drivers/isdn/hisax/callc.c | 584 ++++---- drivers/isdn/hisax/config.c | 38 +- drivers/isdn/hisax/diva.c | 20 +- drivers/isdn/hisax/elsa.c | 14 +- drivers/isdn/hisax/fsm.c | 7 +- drivers/isdn/hisax/hfc_2bds0.c | 7 +- drivers/isdn/hisax/hfc_2bds0.h | 7 +- drivers/isdn/hisax/hfc_2bs0.c | 186 ++- drivers/isdn/hisax/hfc_2bs0.h | 7 +- drivers/isdn/hisax/hfc_pci.c | 65 +- drivers/isdn/hisax/hfc_sx.c | 1584 ++++++++++++++++++++ drivers/isdn/hisax/hfc_sx.h | 216 +++ drivers/isdn/hisax/hfcscard.c | 14 +- drivers/isdn/hisax/hisax.h | 63 +- drivers/isdn/hisax/hscx.h | 7 +- drivers/isdn/hisax/ipac.h | 7 +- drivers/isdn/hisax/isac.h | 7 +- drivers/isdn/hisax/isar.c | 700 +++++++-- drivers/isdn/hisax/isar.h | 36 +- drivers/isdn/hisax/isdnl1.c | 27 +- drivers/isdn/hisax/isurf.c | 12 +- drivers/isdn/hisax/l3_1tr6.c | 8 +- drivers/isdn/hisax/l3dss1.c | 79 +- drivers/isdn/hisax/l3dss1.h | 7 +- drivers/isdn/hisax/netjet.c | 12 +- drivers/isdn/hisax/rawhdlc.c | 4 +- drivers/isdn/hisax/saphir.c | 12 +- drivers/isdn/hisax/sedlbauer.c | 31 +- drivers/isdn/hisax/sportster.c | 17 +- drivers/isdn/hisax/teleint.c | 12 +- drivers/isdn/hisax/teles0.c | 9 +- drivers/isdn/hisax/teles3.c | 22 +- drivers/isdn/hisax/telespci.c | 9 +- drivers/isdn/hysdn/Makefile | 24 + drivers/isdn/hysdn/boardergo.c | 468 ++++++ drivers/isdn/hysdn/boardergo.h | 117 ++ drivers/isdn/hysdn/hysdn_boot.c | 421 ++++++ drivers/isdn/hysdn/hysdn_defs.h | 229 +++ drivers/isdn/hysdn/hysdn_init.c | 243 +++ drivers/isdn/hysdn/hysdn_net.c | 379 +++++ drivers/isdn/hysdn/hysdn_pof.h | 95 ++ drivers/isdn/hysdn/hysdn_procconf.c | 486 ++++++ drivers/isdn/hysdn/hysdn_procfs.c | 503 +++++++ drivers/isdn/hysdn/hysdn_proclog.c | 482 ++++++ drivers/isdn/hysdn/hysdn_sched.c | 203 +++ drivers/isdn/hysdn/ince1pc.h | 132 ++ drivers/isdn/isdn_common.c | 122 +- drivers/isdn/isdn_common.h | 7 +- drivers/isdn/isdn_net.c | 320 ++-- drivers/isdn/isdn_ppp.c | 35 +- drivers/isdn/isdn_tty.c | 108 +- drivers/isdn/isdn_tty.h | 14 +- drivers/isdn/isdn_ttyfax.c | 1118 +++++++------- drivers/net/3c505.c | 18 +- drivers/net/eepro100.c | 37 +- drivers/net/epic100.c | 642 ++++---- drivers/net/hamradio/hdlcdrv.c | 4 +- drivers/net/ltpc.c | 18 +- drivers/net/pcmcia/3c574_cs.c | 142 +- drivers/net/pcmcia/3c589_cs.c | 56 +- drivers/net/pcmcia/Config.in | 1 - drivers/net/pcmcia/Makefile | 4 - drivers/net/pcmcia/fmvj18x_cs.c | 3 + drivers/net/pcmcia/netwave_cs.c | 5 +- drivers/net/pcmcia/nmclan_cs.c | 5 + drivers/net/pcmcia/pcnet_cs.c | 14 +- drivers/net/pcmcia/smc91c92_cs.c | 15 +- drivers/net/pcmcia/wavelan_cs.c | 3 + drivers/net/pcmcia/xirc2ps_cs.c | 29 +- drivers/net/sunlance.c | 31 +- drivers/net/via-rhine.c | 6 +- drivers/pci/pcisyms.c | 2 + drivers/pcmcia/cs.c | 22 +- drivers/pcmcia/cs_internal.h | 2 +- drivers/pcmcia/i82365.c | 26 +- drivers/pcmcia/tcic.c | 21 +- drivers/sbus/char/sunkbd.c | 8 +- drivers/scsi/Config.in | 5 + drivers/scsi/Makefile | 10 + drivers/scsi/aha152x.c | 8 +- drivers/scsi/esp.c | 18 +- drivers/scsi/fdomain.c | 4 - drivers/scsi/mesh.c | 4 +- drivers/scsi/pcmcia/Config.in | 23 + drivers/scsi/pcmcia/Makefile | 67 + drivers/scsi/pcmcia/aha152x_stub.c | 437 ++++++ drivers/scsi/pcmcia/apa1480_stub.c | 174 +++ drivers/scsi/pcmcia/fdomain_stub.c | 398 +++++ drivers/scsi/pcmcia/qlogic_stub.c | 428 ++++++ drivers/scsi/qlogicfas.c | 3 +- drivers/scsi/qlogicpti.c | 6 +- drivers/sound/dmasound.c | 7 +- drivers/sound/es1370.c | 6 +- drivers/sound/es1371.c | 6 +- drivers/sound/esssolo1.c | 7 +- drivers/sound/sonicvibes.c | 6 +- drivers/usb/Config.in | 10 +- drivers/usb/Makefile | 1 + drivers/usb/hid.c | 17 + drivers/usb/keybdev.c | 6 +- drivers/usb/plusb.c | 633 ++++++++ drivers/usb/plusb.h | 48 + drivers/usb/usb-core.c | 4 + drivers/usb/usb-serial.c | 246 +-- drivers/usb/usb-serial.h | 108 +- drivers/usb/usb-uhci.c | 213 ++- drivers/usb/usb-uhci.h | 5 +- drivers/usb/usb_storage.c | 32 +- drivers/video/bwtwofb.c | 2 +- drivers/video/cgsixfb.c | 4 +- drivers/video/matroxfb.c | 172 +-- fs/bfs/file.c | 39 +- fs/binfmt_elf.c | 8 +- include/asm-alpha/page.h | 14 + include/asm-arm/page.h | 14 + include/asm-i386/floppy.h | 4 +- include/asm-i386/page.h | 14 + include/asm-i386/pgtable.h | 3 +- include/asm-ia64/page.h | 12 + include/asm-m68k/page.h | 14 + include/asm-mips/page.h | 14 + include/asm-ppc/page.h | 15 + include/asm-ppc/pgtable.h | 2 + include/asm-sh/page.h | 15 + include/asm-sparc/page.h | 14 + include/asm-sparc/pgtable.h | 3 + include/asm-sparc64/page.h | 14 + include/asm-sparc64/pgtable.h | 11 +- include/linux/console.h | 3 + include/linux/hysdn_if.h | 49 + include/linux/interrupt.h | 23 +- include/linux/isdn.h | 56 +- include/linux/isdnif.h | 55 +- include/linux/kbd_kern.h | 8 +- include/linux/kernelcapi.h | 15 +- include/linux/parport.h | 10 +- include/pcmcia/ciscode.h | 4 +- include/pcmcia/ss.h | 3 +- include/pcmcia/version.h | 6 +- kernel/printk.c | 16 +- mm/filemap.c | 4 +- mm/mmap.c | 8 +- mm/mremap.c | 20 +- net/ipv4/tcp_timer.c | 3 +- 242 files changed, 16121 insertions(+), 4576 deletions(-) create mode 100644 Documentation/isdn/README.hysdn create mode 100644 drivers/isdn/avmb1/b1dma.c 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/isdn/hysdn/Makefile create mode 100644 drivers/isdn/hysdn/boardergo.c create mode 100644 drivers/isdn/hysdn/boardergo.h create mode 100644 drivers/isdn/hysdn/hysdn_boot.c create mode 100644 drivers/isdn/hysdn/hysdn_defs.h create mode 100644 drivers/isdn/hysdn/hysdn_init.c create mode 100644 drivers/isdn/hysdn/hysdn_net.c create mode 100644 drivers/isdn/hysdn/hysdn_pof.h create mode 100644 drivers/isdn/hysdn/hysdn_procconf.c create mode 100644 drivers/isdn/hysdn/hysdn_procfs.c create mode 100644 drivers/isdn/hysdn/hysdn_proclog.c create mode 100644 drivers/isdn/hysdn/hysdn_sched.c create mode 100644 drivers/isdn/hysdn/ince1pc.h create mode 100644 drivers/scsi/pcmcia/Config.in create mode 100644 drivers/scsi/pcmcia/Makefile create mode 100644 drivers/scsi/pcmcia/aha152x_stub.c create mode 100644 drivers/scsi/pcmcia/apa1480_stub.c create mode 100644 drivers/scsi/pcmcia/fdomain_stub.c create mode 100644 drivers/scsi/pcmcia/qlogic_stub.c create mode 100644 drivers/usb/plusb.c create mode 100644 drivers/usb/plusb.h create mode 100644 include/linux/hysdn_if.h diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 7a6d81a443f7..0bd8d16927d6 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -8079,6 +8079,17 @@ CONFIG_USB_UHCI The module will be called usb-uhci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB-UHCI High Bandwidth support +CONFIG_USB_UHCI_HIGH_BANDWIDTH + This option enables the so called reclamation loop in usb-uhci, thus + allowing much higher transfer bandwidth for USB-bulk and control + messages; isochronous transfers (audio, video etc.) are not affected. + Due to a very simple design of the UHCI controller, this may cause + a significant PCI congestion under certain conditions. If you are + experiencing a system slowdown, disable this option. + + If unsure, say N. + UHCI (intel PIIX4, VIA, ...) alternate (JE) support? CONFIG_USB_UHCI_ALT This is an alternate driver for UHCI support. It has been commonly @@ -8247,17 +8258,8 @@ CONFIG_USB_SERIAL_WHITEHEAT USB Handspring Visor Driver CONFIG_USB_SERIAL_VISOR Say Y here if you want to connect to your HandSpring Visor through - its USB docking station. - -USB Belkin Single Port Serial Driver -CONFIG_USB_SERIAL_BELKIN - Say Y here if you want to use a Belkin single port USB to serial - converter device. - -USB Peracom Single Port Serial Driver -CONFIG_USB_SERIAL_PERACOM - Say Y here if you want to use a Peracom single port USB to serial - converter device. + its USB docking station. See http://usbvisor.sourceforge.net for + more information on using this driver. USB Printer support CONFIG_USB_PRINTER @@ -8397,6 +8399,14 @@ CONFIG_USB_DABUSB The module will be called dabusb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +PLUSB driver +CONFIG_USB_PLUSB + A driver for the Prolific PL-2302 USB to USB network device. This 'USB + cable' connects two hosts via a point to point network with bandwidth of + 5Mbit/s. Configure this driver after connecting the USB cable via + ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 + (and vice versa on the other host). + ACPI support CONFIG_ACPI Advanced Configuration and Power Interface (ACPI) is an interface @@ -11730,11 +11740,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. @@ -11743,7 +11758,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. @@ -11752,17 +11767,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"). @@ -11770,17 +11785,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. @@ -11789,7 +11804,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. @@ -11797,7 +11812,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. @@ -11806,16 +11821,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. @@ -11823,7 +11838,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. @@ -11832,7 +11847,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. @@ -11840,21 +11855,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. @@ -11862,62 +11877,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. diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt index c48758677f84..f3fc1dca30ae 100644 --- a/Documentation/DMA-mapping.txt +++ b/Documentation/DMA-mapping.txt @@ -55,9 +55,15 @@ This routine will allocate RAM for that region, so it acts similarly to __get_free_pages (but takes size instead of page order). It returns two values: the virtual address which you can use to access it from the CPU and dma_handle which you pass to the card. -The return address is guaranteed to be page aligned. -To unmap and free such DMA region, you call: +The cpu return address and the DMA bus master address are both +guaranteed to be aligned to the smallest PAGE_SIZE order which +is greater than or equal to the requested size. This invariant +exists (for example) to guarentee that if you allocate a chunk +which is smaller than or equal to 64 kilobytes, the extent of the +buffer you receive will not cross a 64K boundry. + +To unmap and free such a DMA region, you call: pci_free_consistent(dev, size, cpu_addr, dma_handle); diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX index b7161af1a78f..b2e73cbc1d17 100644 --- a/Documentation/isdn/00-INDEX +++ b/Documentation/isdn/00-INDEX @@ -38,3 +38,6 @@ README.sc - info on driver for Spellcaster cards. README.x25 _ info for running X.25 over ISDN. +README.hysdn + - info on driver for Hypercope active HYSDN cards + \ No newline at end of file diff --git a/Documentation/isdn/CREDITS b/Documentation/isdn/CREDITS index beef990bab6b..e1b3023efaa8 100644 --- a/Documentation/isdn/CREDITS +++ b/Documentation/isdn/CREDITS @@ -58,9 +58,13 @@ Thomas Pfeiffer (pfeiffer@pds.de) Max Riegel (riegel@max.franken.de) For making the ICN hardware-documentation and test-equipment available. +Armin Schindler (mac@melware.de) + For the eicon active card driver. + Gerhard 'Fido' Schneider (fido@wuff.mayn.de) For heavy-duty-beta-testing with his BBS ;) Thomas Uhl (uhl@think.de) For distributing the cards. For pushing me to work ;-) + diff --git a/Documentation/isdn/HiSax.cert b/Documentation/isdn/HiSax.cert index de440068f9ce..af128daaa4ff 100644 --- a/Documentation/isdn/HiSax.cert +++ b/Documentation/isdn/HiSax.cert @@ -30,7 +30,7 @@ some validation checks that are made during the make process. The HiSax main files are protected by md5 checksums and the md5sum file is pgp signed by myself: -KeyID 1024/FF992F6D 1997/01/16 Karsten Keil +KeyID 1024/FF992F6D 1997/01/16 Karsten Keil Key fingerprint = 92 6B F7 58 EE 86 28 C8 C4 1A E6 DC 39 89 F2 AA Only if the checksums are OK, and the signature of the file @@ -70,9 +70,9 @@ keil@isdn4linux.de Version: 2.6.3i Charset: noconv -iQCVAwUBN6xoKTpxHvX/mS9tAQF4DAP/efRWym6jvNOND1O9eaEFdP5fd2xKB3XD -Ifh6Iv0DvARcIuxXtEjT+z3FjjQk35eo/wX4C4tpRhYQYdgCxl+iv+5DzhVDpB95 -3QS9E5m0E1eIK3t8XiQTRgb+1JPCMYUThCrakYsX25o3ndGKyDipsCTfkyR38XwC -bUyTfcOYKAk= -=VKyL +iQCVAwUBOFAwqTpxHvX/mS9tAQFI2QP9GLDK2iy/KBhwReE3F7LeO+tVhffTVZ3a +20q5/z/WcIg/pnH0uTkl2UgDXBFXYl45zJyDGNpAposIFmT+Edd14o7Vj1w/BBdn +Y+5rBmJf+gyBu61da5d6bv0lpymwRa/um+ri+ilYnZ/XPfg5JKhdjGSBCJuJAElM +d2jFbTrsMYw= +=LNf9 -----END PGP SIGNATURE----- diff --git a/Documentation/isdn/README b/Documentation/isdn/README index 3cf623d48eec..afd9f45af04d 100644 --- a/Documentation/isdn/README +++ b/Documentation/isdn/README @@ -80,8 +80,7 @@ README for the ISDN-subsystem The functionality is almost the same as that of a serial device (the line-discs are handled by the kernel), which lets you run SLIP, CSLIP and asynchronous PPP through the devices. We have tested - Seyon, minicom, CSLIP (uri-dip) PPP and mgetty (compiled with NO_FAX), - XCept. + Seyon, minicom, CSLIP (uri-dip) PPP, mgetty, XCept and Hylafax. The modem-emulation supports the following: 1.3.1 Commands: @@ -124,6 +123,10 @@ README for the ISDN-subsystem AT&D3 Same as AT&D2 but also resets all registers. AT&Ex Set the EAZ/MSN for this channel to x. AT&F Reset all registers and profile to "factory-defaults" + AT&Lx Set list of phone numbers to listen on. x is a + list of wildcard patterns separated by semicolon. + If this is set, it has precedence over the MSN set + by AT&E. AT&Rx Select V.110 bitrate adaption. This command enables V.110 protocol with 9600 baud (x=9600), 19200 baud (x=19200) or 38400 baud @@ -238,7 +241,8 @@ README for the ISDN-subsystem 15 0 Layer-3 protocol: 0 = transparent 1 = transparent with audio features (e.g. DSP) - 2 = Fax G3 (S14 has to be set to 11) + 2 = Fax G3 Class 2 commands (S14 has to be set to 11) + 2 = Fax G3 Class 1 commands (S14 has to be set to 11) 16 250 Send-Packet-size/16 17 8 Window-size (not yet implemented) 18 4 Bit coded register, Service-Octet-1 to accept, @@ -309,8 +313,6 @@ README for the ISDN-subsystem If an incoming call matches one network interface, it gets connected to it. If another incoming call for the same EAZ arrives, which does not match a network interface, the first tty gets a "RING" and so on. - As soon as voice gets supported (with the availability of the Diehl-driver), - the service-identifier will be evaluated in addition. 2 System prerequisites: 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/isdn/README.eicon b/Documentation/isdn/README.eicon index b40e1ecd23c5..73d8c92dd850 100644 --- a/Documentation/isdn/README.eicon +++ b/Documentation/isdn/README.eicon @@ -1,9 +1,10 @@ -$Id: README.eicon,v 1.5 1999/10/11 18:13:25 armin Exp $ +$Id: README.eicon,v 1.6 2000/01/27 09:54:44 armin Exp $ -(c) 1999 Cytronics & Melware (info@melware.de) +(c) 1999,2000 Armin Schindler (mac@melware.de) +(c) 1999,2000 Cytronics & Melware (info@melware.de) This document describes the eicon driver for the -Eicon.Diehl active ISDN cards. +Eicon active ISDN cards. It is meant to be used with isdn4linux, an ISDN link-level module for Linux. @@ -50,7 +51,8 @@ ISDN D-Channel Protocols - ETSI (Euro-DSS1) - 1TR6 (German ISDN) *not testet* - +- other protocols exist for the range of DIVA Server cards, + but they are not fully testet yet. You can load the module simply by using the insmod or modprobe function : @@ -58,7 +60,7 @@ You can load the module simply by using the insmod or modprobe function : insmod eicon [id=driverid] [membase=] [irq=] -The module will automatically probe the PCI-cards. If the id-options +The module will automatically probe the PCI-cards. If the id-option is omitted, the driver will assume 'eicon0' for the first pci card and increases the digit with each further card. With a given driver-id the module appends a number starting with '0'. @@ -85,6 +87,14 @@ Example for loading and starting a PRI card with E-DSS1 Protocol. Details about using the eiconctrl utility are in 'man eiconctrl' or will be printed by starting eiconctrl without any parameters. +ISDNLOG: +With eicon driver version 1.77 or newer and the eiconctrl utility +of version 1.1 or better, you can use the isdnlog user program +with your DIVA Server BRI card. +Just use "eiconctrl isdnlog on" and the driver will generate +the necessary D-Channel traces for isdnlog. + + Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH for sponsoring and testing fax diff --git a/Documentation/isdn/README.hysdn b/Documentation/isdn/README.hysdn new file mode 100644 index 000000000000..c9dbd0de8750 --- /dev/null +++ b/Documentation/isdn/README.hysdn @@ -0,0 +1,177 @@ +$Id: README.hysdn,v 1.1 2000/02/10 19:46:15 werner Exp $ +The hysdn driver has been written by +by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) +for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver +under the GNU Public License. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Table of contents +================= + +1. About the driver + +2. Loading/Unloading the driver + +3. Entries in the /proc filesystem + +4. The /proc/net/hysdn/cardconfX file + +5. The /proc/net/hysdn/cardlogX file + +6. Where to get additional info and help + + +1. About the driver + + The drivers/isdn/hysdn subdir contains a driver for HYPERCOPEs active + PCI isdn cards Champ, Ergo and Metro. To enable support for this cards + enable ISDN support in the kernel config and support for HYSDN cards in + the active cards submenu. The driver may only be compiled and used if + support for loadable modules and the process filesystem have been enabled. + No other ISDN options need to be enabled for these cards. + + Up to now these cards do not use or require the standard isdn interface + module (isdn.o), but registers itself as an ethernet card. All necessary + handlers for various protocols like ppp and others as well as config info + and firmware may be fetched from Hypercopes WWW-Site www.hypercope.de. + The driver has been included in the i4l tree as a CAPI compliant module + is under development and will be connected to the standard i4l modules + additionally. + +2. Loading/Unloading the driver + + The module has no command line parameters and auto detects up to 10 cards + in the id-range 0-9. + If a loaded driver shall be unloaded all open files in the /proc/net/hysdn + subdir need to be closed and all ethernet interfaces allocated by this + driver must be shut down. Otherwise the module counter will avoid a module + unload. + +3. Entries in the /proc filesystem + + When the module has been loaded it adds the directory hysdn in the + /proc/net tree. This directory contains exactly 2 file entries for each + card. One is called cardconfX and the other cardlogX, where X is the + card id number from 0 to 9. + The cards are numbered in the order found in the PCI config data. + +4. The /proc/net/hysdn/cardconfX file + + This file may be read to get by everyone to get info about the cards type, + actual state, available features and used resources. + The first 3 entries (id, bus and slot) are PCI info fields, the following + type field gives the information about the cards type: + + 4 -> Ergo card (server card with 2 b-chans) + 5 -> Metro card (server card with 4 or 8 b-chans) + 6 -> Champ card (client card with 2 b-chans) + + The following 3 fields show the hardware assignments for irq, iobase and the + dual ported memory (dp-mem). + The fields b-chans and fax-chans announce the available card resources of + this types for the user. + The state variable indicates the actual drivers state for this card with the + following assignments. + + 0 -> card has not been booted since driver load + 1 -> card booting is actually in progess + 2 -> card is in an error state due to a previous boot failure + 3 -> card is booted and active + + And the last field (device) shows the name of the ethernet device assigned + to this card. Up to the first successfull boot this field only shows a - + to tell that no net device has been allocated up to now. Once a net device + has been allocated it remains assigned to this card, even if a card is + rebooted and an boot error occurs. + + Writing to the cardconfX file boots the card or transfers config lines to + the cards firmware. The type of data is automatically detected when the + first data is written. Only root has write access to this file. + The firmware boot files are normally called hyclient.pof for client cards + and hyserver.pof for server cards. + After successfully writing the boot file, complete config files or single + config lines may be copied to this file. + If an error occurs the return value given to the writing process has the + following additional codes (decimal): + + 1000 Another process is currently bootng the card + 1001 Invalid firmware header + 1002 Boards dual-port RAM test failed + 1003 Internal firmware handler error + 1004 Boot image size invalid + 1005 First boot stage (bootstrap loader) failed + 1006 Second boot stage failure + 1007 Timeout waiting for card ready during boot + 1008 Operation only allowed in booted state + 1009 Config line to long + 1010 Invalid channel number + 1011 Timeout sending config data + + Additional info about error reasons may be fetched from the log output. + +5. The /proc/net/hysdn/cardlogX file + + The cardlogX file entry may be opened multiple for reading by everyone to + get the cards and drivers log data. Card messages always start with the + keyword LOG. All other lines are output from the driver. + The driver log data may be redirected to the syslog by selecting the + approriate bitmask. The cards log messages will always be send to this + interface but never to the syslog. + + A root user may write a decimal or hex (with 0x) value t this file to select + desired output options. As mentioned above the cards log dat is always + written to the cardlog file independant of the following options only used + to check and debug the driver itself: + + For example: + echo "0x34560078" > /proc/net/hysdn/cardlog0 + to output the hex log mask 34560078 for card 0. + + The written value is regarded as an unsigned 32-Bit value, bit ored for + desired output. The following bits are already assigned: + + 0x80000000 All driver log data is alternatively via syslog + 0x00000001 Log memory allocation errors + 0x00000010 Firmware load start and close are logged + 0x00000020 Log firmware record parser + 0x00000040 Log every firmware write actions + 0x00000080 Log all card related boot messages + 0x00000100 Output all config data sent for debugging purposes + 0x00000200 Only non comment config lines are shown wth channel + 0x00000400 Additional conf log output + 0x00001000 Log the asynchronous scheduler actions (config and log) + 0x00100000 Log all open and close actions to /proc/net/hysdn/card files + 0x00200000 Log all actions from /proc file entries + 0x00010000 Log network interface init and deinit + +6. Where to get additional info and help + + If you have any problems concerning the driver or configuration contact + the Hypercope support team (www.hypercope.de) and or the author + Werner Cornelius (werner@isdn4linux or cornelius@titro.de) + + + + + + + + + + + + + diff --git a/Documentation/isdn/README.x25 b/Documentation/isdn/README.x25 index 9794f41183f5..e561a77c4e22 100644 --- a/Documentation/isdn/README.x25 +++ b/Documentation/isdn/README.x25 @@ -61,7 +61,21 @@ X.25 on top of isdn might be useful with two different scenarios: - You might want to access a public X.25 data network from your Linux box. You can use i4l if you were physically connected to the X.25 switch - by an ISDN line (leased line as well as dial up connection should work) + by an ISDN B-channel (leased line as well as dial up connection should + work). + + This corresponds to ITU-T recommendation X.31 Case A (circuit-mode + access to PSPDN [packet switched public data network]). + + NOTE: X.31 also covers a Case B (access to PSPDN via virtual + circuit / packet mode service). The latter mode (which in theory + also allows using the D-channel) is not supported by isdn4linux. + It should however be possible to establish such packet mode connections + with certain active isdn cards provided that the firmware supports X.31 + and the driver exports this functionality to the user. Currently, + the AVM B1 driver is the only driver which does so. (It should be + possible to access D-channel X.31 with active AVM cards using the + CAPI interface of the AVM-B1 driver). - Or you might want to operate certain ISDN teleservices on your linux box. A lot of those teleservices run on top of the ISO-8208 diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index e9e94510b9a1..2a022f506227 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -67,20 +67,6 @@ Current status: http://usbvisor.sourceforge.net/ -Belkin single port serial converter -Peracom single port serial converter - -Current status: - The driver can handle enumerating the device, and sending and receiving - data from the converter. However, since I do not have a spec for the - Belkin, Peracom, and eTek devices, and the raw dumps from the Win98 - driver are confusing, and eTek refuses to provide documentation on their - protocol, no control signals are currently handled, and the data will - most likely come through on a baud rate that you are not expecting. So - if you have these devices, do not expect the correct data to show up at - either end. - - Generic Serial driver If your device is not one of the above listed devices, compatible with diff --git a/Makefile b/Makefile index 23509086c039..ff510cb9c64c 100644 --- a/Makefile +++ b/Makefile @@ -405,6 +405,7 @@ modules_install: if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \ if [ -f PCMCIA_NET_MODULES ]; then inst_mod PCMCIA_NET_MODULES pcmcia; fi; \ if [ -f PCMCIA_CHAR_MODULES ]; then inst_mod PCMCIA_CHAR_MODULES pcmcia; fi; \ + if [ -f PCMCIA_SCSI_MODULES ]; then inst_mod PCMCIA_SCSI_MODULES pcmcia; fi; \ \ ls -1 -U *.o | sort > $$MODLIB/.allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 14a127c14f71..a3d90a4457b7 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -39,20 +39,6 @@ calc_npages(long bytes) { return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; } - -static inline long -calc_order(long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} struct pci_iommu_arena * iommu_arena_new(dma_addr_t base, unsigned long window_size, @@ -248,7 +234,7 @@ void * pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp) { void *cpu_addr; - long order = calc_order(size); + long order = get_order(size); cpu_addr = (void *)__get_free_pages(GFP_ATOMIC, order); if (! cpu_addr) { @@ -285,7 +271,7 @@ pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr, dma_addr_t dma_addr) { pci_unmap_single(pdev, dma_addr, size); - free_pages((unsigned long)cpu_addr, calc_order(size)); + free_pages((unsigned long)cpu_addr, get_order(size)); DBGA2("pci_free_consistent: [%x,%lx] from %p\n", dma_addr, size, __builtin_return_address(0)); diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 4fece516d9c8..8673d6c1d564 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -12,20 +12,6 @@ #include #include -/* Pure 2^n version of get_order */ -extern __inline__ int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - /* * This allocates one page of cache-coherent memory space and returns * both the virtual and a "dma" address to that space. It is not clear @@ -43,7 +29,7 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) if (in_interrupt()) BUG(); - order = __get_order(size); + order = get_order(size); page = __get_free_pages(gfp, order); if (!page) diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 0f3a762a3993..6047f6de2d11 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -324,7 +324,6 @@ CONFIG_PCMCIA_PCNET=y # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_3C575 is not set # CONFIG_PCMCIA_TULIP is not set -# CONFIG_PCMCIA_EPIC100 is not set CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y # CONFIG_PCMCIA_NETWAVE is not set diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 8ae8bc299b87..9bdd111d1c4d 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -643,6 +643,7 @@ const static struct {NULL,}, {acpi_init_piix4}, {acpi_init_via}, + {acpi_init_via}, }; const static struct pci_device_id acpi_pci_tbl[] = diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 004c63ad1655..75b2bfb9fbb1 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1368,7 +1368,6 @@ void IO_APIC_init_uniprocessor (void) { if (!smp_found_config) return; - phys_cpu_present_map = 0xff; setup_local_APIC(); setup_IO_APIC(); setup_APIC_clocks(); diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c index 18b2032282a7..4bd1486fe690 100644 --- a/arch/i386/kernel/pci-dma.c +++ b/arch/i386/kernel/pci-dma.c @@ -13,20 +13,6 @@ #include #include -/* Pure 2^n version of get_order */ -extern __inline__ int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { @@ -35,7 +21,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, __get_order(size)); + ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { memset(ret, 0, size); @@ -47,5 +33,5 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, __get_order(size)); + free_pages((unsigned long)vaddr, get_order(size)); } diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c index ee2edca1e87b..6dd0a4306af2 100644 --- a/arch/i386/kernel/pci-i386.c +++ b/arch/i386/kernel/pci-i386.c @@ -132,7 +132,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) /* We need to avoid collisions with `mirrored' VGA ports and other strange ISA hardware, so we always want the addresses kilobyte aligned. */ - if (size >= 0x100) { + if (size > 0x100) { printk(KERN_ERR "PCI: I/O Region %s/%d too large" " (%ld bytes)\n", dev->slot_name, dev->resource - res, size); diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 4ef25674ff78..c3991b056888 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -307,27 +307,30 @@ static void __init pagetable_init(void) pmd_t *pmd; pte_t *pte; int i, j, k; - unsigned long vaddr; - unsigned long end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); + unsigned long vaddr, end; - pgd_base = swapper_pg_dir; + end = (unsigned long)__va(max_low_pfn*PAGE_SIZE) - 1; - vaddr = PAGE_OFFSET; - i = __pgd_offset(vaddr); + i = __pgd_offset(PAGE_OFFSET); + pgd_base = swapper_pg_dir; pgd = pgd_base + i; - for (; (i < PTRS_PER_PGD) && (vaddr <= end); pgd++, i++) { + for (; i < PTRS_PER_PGD; pgd++, i++) { vaddr = i*PGDIR_SIZE; + if (vaddr >= end) + break; #if CONFIG_X86_PAE - pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + pmd = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); #else pmd = (pmd_t *)pgd; #endif if (pmd != pmd_offset(pgd, 0)) BUG(); - for (j = 0; (j < PTRS_PER_PMD) && (vaddr <= end); pmd++, j++) { + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (vaddr >= end) + break; if (cpu_has_pse) { unsigned long __pe; @@ -349,10 +352,10 @@ static void __init pagetable_init(void) if (pte != pte_offset(pmd, 0)) BUG(); - for (k = 0; - (k < PTRS_PER_PTE) && (vaddr <= end); - pte++, k++) { + for (k = 0; k < PTRS_PER_PTE; pte++, k++) { vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + if (vaddr >= end) + break; *pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL); } } diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c index 9989356d3eba..0bc110510016 100644 --- a/arch/ia64/kernel/pci-dma.c +++ b/arch/ia64/kernel/pci-dma.c @@ -17,21 +17,6 @@ #include -/* Pure 2^n version of get_order */ -extern __inline__ unsigned long -get_order (unsigned long size) -{ - unsigned long order = ia64_fls(size - 1) + 1; - - printk ("get_order: size=%lu, order=%lu\n", size, order); - - if (order > PAGE_SHIFT) - order -= PAGE_SHIFT; - else - order = 0; - return order; -} - void * pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { diff --git a/arch/mips/jazz/floppy-jazz.c b/arch/mips/jazz/floppy-jazz.c index 92c1f95062f2..26498a2240ec 100644 --- a/arch/mips/jazz/floppy-jazz.c +++ b/arch/mips/jazz/floppy-jazz.c @@ -94,26 +94,11 @@ static unsigned long jazz_fd_getfdaddr1(void) return JAZZ_FDC_BASE; } -/* Pure 2^n version of get_order */ -extern inline int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static unsigned long jazz_fd_dma_mem_alloc(unsigned long size) { - int order = __get_order(size); unsigned long mem; - mem = __get_dma_pages(GFP_KERNEL, order); + mem = __get_dma_pages(GFP_KERNEL, get_order(size)); if(!mem) return 0; vdma_alloc(PHYSADDR(mem), size); /* XXX error checking */ @@ -125,7 +110,7 @@ static void jazz_fd_dma_mem_free(unsigned long addr, unsigned long size) { vdma_free(vdma_phys2log(PHYSADDR(addr))); - free_pages(addr, __get_order(size)); + free_pages(addr, get_order(size)); } static unsigned long jazz_fd_drive_type(unsigned long n) diff --git a/arch/mips/lib/floppy-std.c b/arch/mips/lib/floppy-std.c index 3d1c95feb419..d81994d2ba42 100644 --- a/arch/mips/lib/floppy-std.c +++ b/arch/mips/lib/floppy-std.c @@ -102,33 +102,18 @@ static unsigned long std_fd_getfdaddr1(void) return 0x3f0; } -/* Pure 2^n version of get_order */ -static int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static unsigned long std_fd_dma_mem_alloc(unsigned long size) { - int order = __get_order(size); unsigned long mem; - mem = __get_dma_pages(GFP_KERNEL,order); + mem = __get_dma_pages(GFP_KERNEL,get_order(size)); return mem; } static void std_fd_dma_mem_free(unsigned long addr, unsigned long size) { - free_pages(addr, __get_order(size)); + free_pages(addr, get_order(size)); } static unsigned long std_fd_drive_type(unsigned long n) diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 8ea7e9000e51..8bb23afa26ae 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -97,7 +97,7 @@ fi if [ "$CONFIG_6xx" = "y" -a "$CONFIG_APUS" != "y" ]; then define_bool CONFIG_PCI y fi -if [ "$CONFIG_PREP" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" -o "$CONFIG_ALL_PPC" = "y"]; then +if [ "$CONFIG_PREP" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then define_bool CONFIG_PCI y fi diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index a543169e7afd..50f63eeb4f00 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -229,7 +229,7 @@ _GLOBAL(flush_dcache_range) blr /* - * Flush a particular page from the DATA cache + * Flush a particular page from the data cache to RAM. * Note: this is necessary because the instruction cache does *not* * snoop from the data cache. * This is a no-op on the 601 which has a unified cache. @@ -241,18 +241,31 @@ _GLOBAL(__flush_page_to_ram) rlwinm r5,r5,16,16,31 cmpi 0,r5,1 beqlr /* for 601, do nothing */ - li r4,0x0FFF - andc r3,r3,r4 /* Get page base address */ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ mtctr r4 - mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ addi r3,r3,CACHE_LINE_SIZE bdnz 0b sync + blr + +/* + * Flush a particular page from the instruction cache. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * This is a no-op on the 601 which has a unified cache. + * + * void __flush_icache_page(void *page) + */ +_GLOBAL(__flush_icache_page) + mfspr r5,PVR + rlwinm r5,r5,16,16,31 + cmpi 0,r5,1 + beqlr /* for 601, do nothing */ + li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ mtctr r4 -1: icbi 0,r6 - addi r6,r6,CACHE_LINE_SIZE +1: icbi 0,r3 + addi r3,r3,CACHE_LINE_SIZE bdnz 1b sync isync diff --git a/arch/ppc/kernel/pci-dma.c b/arch/ppc/kernel/pci-dma.c index 089566908b8f..174de223fed6 100644 --- a/arch/ppc/kernel/pci-dma.c +++ b/arch/ppc/kernel/pci-dma.c @@ -14,20 +14,6 @@ #include #include -/* Pure 2^n version of get_order */ -extern __inline__ int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { @@ -36,7 +22,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, __get_order(size)); + ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { memset(ret, 0, size); @@ -48,5 +34,5 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, __get_order(size)); + free_pages((unsigned long)vaddr, get_order(size)); } diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index d81f0056a8e8..75771551272a 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -171,6 +172,11 @@ EXPORT_SYMBOL(chrp_ide_regbase); EXPORT_SYMBOL(chrp_ide_probe); #endif +#ifdef CONFIG_PCI +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); +#endif /* CONFIG_PCI */ + EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index f746f824b5a5..2fdab076e1b9 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -44,7 +44,6 @@ #include struct resource *_sparc_find_resource(struct resource *r, unsigned long); -int _sparc_len2order(unsigned long len); static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz); static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, @@ -280,7 +279,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) return NULL; } - order = _sparc_len2order(len_total); + order = get_order(len_total); va = __get_free_pages(GFP_KERNEL, order); if (va == 0) { /* @@ -341,7 +340,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) pgp = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); mmu_unmap_dma_area(ba, n); - free_pages(pgp, _sparc_len2order(n)); + free_pages(pgp, get_order(n)); } /* @@ -482,7 +481,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) return NULL; } - order = _sparc_len2order(len_total); + order = get_order(len_total); va = __get_free_pages(GFP_KERNEL, order); if (va == 0) { printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT); @@ -569,7 +568,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) release_resource(res); kfree(res); - free_pages(pgp, _sparc_len2order(n)); + free_pages(pgp, get_order(n)); } /* Map a single buffer of the indicated size for DMA in streaming mode. @@ -739,19 +738,6 @@ _sparc_find_resource(struct resource *root, unsigned long hit) return NULL; } -int -_sparc_len2order(unsigned long len) -{ - int order; - - for (order = 0; order < 7; order++) /* 2^6 pages == 256K */ - if ((1 << (order + PAGE_SHIFT)) >= len) - return order; - printk("len2order: from %p: len %lu(0x%lx) yields order >=7.\n", - __builtin_return_address(0), len, len); - return 1; -} - /* * Necessary boot time initializations. */ diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index d1b3eca6373e..ff09b1ac81da 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.89 2000/02/09 11:15:03 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.90 2000/02/13 09:52:54 anton Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -145,11 +145,8 @@ EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(global_irq_lock); EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(global_bh_count); -EXPORT_SYMBOL(sparc_bh_lock); EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(synchronize_bh); #endif EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index fde9bccfd7e5..4455bfa8c158 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -34,12 +34,39 @@ asmlinkage unsigned long sys_getpagesize(void) return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */ } +unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +{ + struct vm_area_struct * vmm; + + /* See asm-sparc/uaccess.h */ + if (len > TASK_SIZE - PAGE_SIZE) + return 0; + if (ARCH_SUN4C_SUN4 && len > 0x20000000) + return 0; + if (!addr) + addr = TASK_UNMAPPED_BASE; + addr = PAGE_ALIGN(addr); + + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) { + addr = PAGE_OFFSET; + vmm = find_vma(current->mm, PAGE_OFFSET); + } + if (TASK_SIZE - PAGE_SIZE - len < addr) + return 0; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + } +} + extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { if(ARCH_SUN4C_SUN4) { - if(brk >= 0x20000000 && brk < 0xe0000000) + if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) return current->mm->brk; } return sys_brk(brk); @@ -190,24 +217,16 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len, down(¤t->mm->mmap_sem); lock_kernel(); - retval = -ENOMEM; + retval = -EINVAL; len = PAGE_ALIGN(len); - if(!(flags & MAP_FIXED) && - (!addr || (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)))) { - addr = get_unmapped_area(0, len); - if(!addr) - goto out_putf; - if (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)) { - retval = -EINVAL; - goto out_putf; - } - } + if (ARCH_SUN4C_SUN4 && + (len > 0x20000000 || + ((flags & MAP_FIXED) && + addr < 0xe0000000 && addr + len > 0x20000000))) + goto out_putf; /* See asm-sparc/uaccess.h */ - retval = -EINVAL; - if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) + if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE) goto out_putf; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); @@ -238,6 +257,50 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); } +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sparc_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr) +{ + unsigned long ret = -EINVAL; + if (ARCH_SUN4C_SUN4) { + if (old_len > 0x20000000 || new_len > 0x20000000) + goto out; + if (addr < 0xe0000000 && addr + old_len > 0x20000000) + goto out; + } + if (old_len > TASK_SIZE - PAGE_SIZE || + new_len > TASK_SIZE - PAGE_SIZE) + goto out; + down(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (ARCH_SUN4C_SUN4 && + new_addr < 0xe0000000 && + new_addr + new_len > 0x20000000) + goto out_sem; + if (new_addr + new_len > TASK_SIZE - PAGE_SIZE) + goto out_sem; + } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 && + addr + new_len > 0x20000000) || + addr + new_len > TASK_SIZE - PAGE_SIZE) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (addr, new_len); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up(¤t->mm->mmap_sem); +out: + return ret; +} + /* we come to here via sys_nis_syscall so it can setup the regs argument */ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index bb3a5ad36cf9..a6873891876b 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -71,8 +71,10 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { - printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", - current->comm); + static int cnt; + if (cnt++ < 10) + printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", + current->comm); flags &= ~MAP_NORESERVE; } retval = -EBADF; @@ -84,19 +86,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, goto out; } - retval = -ENOMEM; - if(!(flags & MAP_FIXED) && - (!addr || (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)))) { - addr = get_unmapped_area(0, len); - if(!addr) - goto out_putf; - if (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)) { - retval = -EINVAL; - goto out_putf; - } - } + retval = -EINVAL; /* If this is ld.so or a shared library doing an mmap * of /dev/zero, transform it into an anonymous mapping. * SunOS is so stupid some times... hmph! @@ -105,18 +95,27 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR && MINOR(file->f_dentry->d_inode->i_rdev) == 5) { flags |= MAP_ANONYMOUS; + fput(file); file = 0; } } - if(!(flags & MAP_FIXED)) - addr = 0; ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; - /* See asm-sparc/uaccess.h */ - retval = -EINVAL; - if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) - goto out_putf; + if(!(flags & MAP_FIXED)) + addr = 0; + else { + if (ARCH_SUN4C_SUN4 && + (len > 0x20000000 || + ((flags & MAP_FIXED) && + addr < 0xe0000000 && addr + len > 0x20000000))) + goto out_putf; + + /* See asm-sparc/uaccess.h */ + if (len > TASK_SIZE - PAGE_SIZE || + addr + len > TASK_SIZE - PAGE_SIZE) + goto out_putf; + } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, off); diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 174522d033ff..96700679ded6 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -69,7 +69,7 @@ sys_call_table: /*235*/ .long sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_nis_syscall, sys_nis_syscall #ifdef CONFIG_SUNOS_EMUL diff --git a/arch/sparc/lib/rwsem.S b/arch/sparc/lib/rwsem.S index 0d5f7413964c..0396bf2bc09e 100644 --- a/arch/sparc/lib/rwsem.S +++ b/arch/sparc/lib/rwsem.S @@ -1,4 +1,4 @@ -/* $Id: rwsem.S,v 1.2 2000/01/05 01:00:38 davem Exp $ +/* $Id: rwsem.S,v 1.4 2000/02/13 07:59:39 anton Exp $ * Assembly part of rw semaphores. * * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) @@ -26,16 +26,19 @@ ___down_read: tst %g7 bne 1b ld [%g1], %g7 - subcc %g7, 1, %g7 + sub %g7, 1, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - subcc %g7, 1, %g7 + sub %g7, 1, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr + add %g7, 1, %g7 nop + nop + subcc %g7, 1, %g7 bneg 3f nop 2: jmpl %o7, %g0 @@ -74,16 +77,19 @@ ___down_write: tst %g7 bne 1b ld [%g1], %g7 - subcc %g7, %g2, %g7 + sub %g7, %g2, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - subcc %g7, %g2, %g7 + sub %g7, %g2, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr + add %g7, %g2, %g7 + nop nop + subcc %g7, %g2, %g7 bne 3f nop 2: jmpl %o7, %g0 @@ -122,16 +128,19 @@ ___up_read: tst %g7 bne 1b ld [%g1], %g7 - addcc %g7, 1, %g7 + add %g7, 1, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - addcc %g7, 1, %g7 + add %g7, 1, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr nop + nop + nop + cmp %g7, 0 be 3f nop 2: jmpl %o7, %g0 @@ -164,16 +173,19 @@ ___up_write: tst %g7 bne 1b ld [%g1], %g7 - addcc %g7, %g2, %g7 + add %g7, %g2, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - addcc %g7, %g2, %g7 + add %g7, %g2, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr + sub %g7, %g2, %g7 + nop nop + addcc %g7, %g2, %g7 bcs 3f nop 2: jmpl %o7, %g0 diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 890ed9d068ac..aa8ba110eaf0 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.206 2000/02/08 07:45:59 davem Exp $ +/* $Id: srmmu.c,v 1.207 2000/02/14 02:51:53 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 5df4febd4432..f456794ff011 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.188 2000/02/12 03:07:35 zaitcev Exp $ +/* $Id: sun4c.c,v 1.189 2000/02/14 02:51:55 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 409a44897678..ef9ff2004b81 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -123,11 +123,8 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad int npages; size = PAGE_ALIGN(size); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } - if (order == 10) + order = get_order(size); + if (order >= 10) return NULL; /* We still don't support devices which don't recognize at least 30 bits @@ -210,10 +207,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ spin_unlock_irqrestore(&iommu->lock, flags); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } + order = get_order(size); if (order < 10) free_pages((unsigned long)cpu, order); } diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index bbf10cac149b..af8acd0c6b42 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1133,10 +1133,7 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, control &= ~(SABRE_IOMMUCTRL_DENAB); sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); - for(order = 0;; order++) - if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) - break; - tsbbase = __get_free_pages(GFP_KERNEL, order); + tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8)); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 38e731f37910..ae431a2828c2 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -255,11 +255,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma return NULL; size = PAGE_ALIGN(size); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } - if (order == 10) + order = get_order(size); + if (order >= 10) return NULL; first_page = __get_free_pages(GFP_KERNEL, order); if (first_page == 0UL) @@ -306,10 +303,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add free_consistent_cluster(iommu, dvma, npages); spin_unlock_irq(&iommu->lock); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } + order = get_order(size); if (order < 10) free_pages((unsigned long)cpu, order); } diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 6e8899435f83..273c12de1ed8 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -753,9 +753,7 @@ static void __init smp_tune_scheduling (void) "ecache-size", (512 * 1024)); if (ecache_size > (4 * 1024 * 1024)) ecache_size = (4 * 1024 * 1024); - for (order = 0UL; (PAGE_SIZE << order) < ecache_size; order++) - ; - flush_base = __get_free_pages(GFP_KERNEL, order); + flush_base = __get_free_pages(GFP_KERNEL, order = get_order(ecache_size)); if (flush_base != 0UL) { __save_and_cli(flags); diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index be2638ec9ab7..de8a5b8fac87 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -39,17 +39,49 @@ asmlinkage unsigned long sys_getpagesize(void) return PAGE_SIZE; } +unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +{ + struct vm_area_struct * vmm; + unsigned long task_size = TASK_SIZE; + + if (current->thread.flags & SPARC_FLAG_32BIT) + task_size = 0xf0000000UL; + if (len > task_size || len > -PAGE_OFFSET) + return 0; + if (!addr) + addr = TASK_UNMAPPED_BASE; + addr = PAGE_ALIGN(addr); + + task_size -= len; + + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (addr < PAGE_OFFSET && -PAGE_OFFSET - len < addr) { + addr = PAGE_OFFSET; + vmm = find_vma(current->mm, PAGE_OFFSET); + } + if (task_size < addr) + return 0; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + } +} + extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { - if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) || - (brk - current->mm->brk > 0x80000000000UL && - brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */ + /* People could try to be nasty and use ta 0x6d in 32bit programs */ + if ((current->thread.flags & SPARC_FLAG_32BIT) && + brk >= 0xf0000000UL) + return current->mm->brk; + + if ((current->mm->brk & PAGE_OFFSET) != (brk & PAGE_OFFSET)) return current->mm->brk; return sys_brk(brk); } - + /* * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. @@ -164,30 +196,21 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - retval = -ENOMEM; len = PAGE_ALIGN(len); + retval = -EINVAL; + down(¤t->mm->mmap_sem); lock_kernel(); - if(!(flags & MAP_FIXED) && !addr) { - addr = get_unmapped_area(addr, len); - if(!addr) - goto out_putf; - } - retval = -EINVAL; if (current->thread.flags & SPARC_FLAG_32BIT) { - if (len > 0xf0000000UL || addr > 0xf0000000UL - len) + if (len > 0xf0000000UL || + ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)) goto out_putf; } else { - if (len >= 0x80000000000UL || - (addr < 0x80000000000UL && - addr > 0x80000000000UL-len)) + if (len > -PAGE_OFFSET || + ((flags & MAP_FIXED) && + addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) goto out_putf; - if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) { - /* VM hole */ - retval = current->mm->brk; - goto out_putf; - } } retval = do_mmap(file, addr, len, prot, flags, off); @@ -201,6 +224,55 @@ out: return retval; } +asmlinkage long sys64_munmap(unsigned long addr, size_t len) +{ + long ret; + + if (len > -PAGE_OFFSET || + (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) + return -EINVAL; + down(¤t->mm->mmap_sem); + ret = do_munmap(addr, len); + up(¤t->mm->mmap_sem); + return ret; +} + +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sys64_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr) +{ + unsigned long ret = -EINVAL; + if (current->thread.flags & SPARC_FLAG_32BIT) + goto out; + if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET) + goto out; + if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) + goto out; + down(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (new_addr < PAGE_OFFSET && + new_addr + new_len > -PAGE_OFFSET) + goto out_sem; + } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (addr, new_len); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up(¤t->mm->mmap_sem); +out: + return ret; +} + /* we come to here via sys_nis_syscall so it can setup the regs argument */ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 61b9a33977b3..9f2bf8afe076 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -4190,3 +4191,38 @@ out_error: fd = error; goto out; } + +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sys32_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, u32 __new_addr) +{ + unsigned long ret = -EINVAL; + unsigned long new_addr = AA(__new_addr); + + if (old_len > 0xf0000000UL || new_len > 0xf0000000UL) + goto out; + if (addr > 0xf0000000UL - old_len) + goto out; + down(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (new_addr > 0xf0000000UL - new_len) + goto out_sem; + } else if (addr > 0xf0000000UL - new_len) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (addr, new_len); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up(¤t->mm->mmap_sem); +out: + return ret; +} diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 62058ffcff6f..426780f9501e 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -71,8 +71,10 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { - printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", - current->comm); + static int cnt; + if (cnt++ < 10) + printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", + current->comm); flags &= ~MAP_NORESERVE; } retval = -EBADF; @@ -93,15 +95,11 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of } } - retval = -ENOMEM; - if(!(flags & MAP_FIXED) && !addr) { - unsigned long attempt = get_unmapped_area(addr, len); - if(!attempt || (attempt >= 0xf0000000UL)) - goto out_putf; - addr = (u32) attempt; - } + retval = -EINVAL; if(!(flags & MAP_FIXED)) addr = 0; + else if (len > 0xf0000000 || addr > 0xf0000000 - len) + goto out_putf; ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 10effccae9b8..70ce2fee1dd0 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -69,7 +69,7 @@ sys_call_table32: .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep -/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl +/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl .word sys_aplib /* Now the 64-bit native Linux syscall table. */ @@ -92,7 +92,7 @@ sys_call_table: .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize .word sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall -/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect +/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys64_munmap, sys_mprotect .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups /*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall @@ -128,7 +128,7 @@ sys_call_table: .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_aplib #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index cb281a6593ca..0825b058585d 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.36 1999/12/15 15:45:18 davem Exp $ +/* $Id: ultra.S,v 1.37 2000/02/14 02:52:04 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -132,8 +132,8 @@ __flush_tlb_range_pbp_slow: wrpr %g1, 0x0, %pstate .align 32 - .globl flush_icache_page -flush_icache_page: /* %o0 = phys_page */ + .globl __flush_icache_page +__flush_icache_page: /* %o0 = phys_page */ sethi %hi(1 << 13), %o2 ! IC_set bit mov 1, %g1 srlx %o0, 5, %o0 diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 46dbfb241d5a..a23e47dce4f8 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -83,27 +83,25 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o } } - down(¤t->mm->mmap_sem); - retval = -ENOMEM; - if(!(flags & MAP_FIXED) && !addr) { - unsigned long attempt = get_unmapped_area(addr, len); - if(!attempt || (attempt >= 0xf0000000UL)) - goto out_putf; - addr = (u32) attempt; - } + retval = -EINVAL; + len = PAGE_ALIGN(len); if(!(flags & MAP_FIXED)) addr = 0; + else if (len > 0xf0000000UL || addr > 0xf0000000UL - len) + goto out_putf; ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; + down(¤t->mm->mmap_sem); flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, (unsigned long) addr, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, off); + up(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < 0xf0000000) ? 0 : retval); + out_putf: - up(¤t->mm->mmap_sem); if (file) fput(file); out: diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 79bd8078e800..01fc28943f43 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -206,8 +206,8 @@ bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then tristate ' Linear (append) mode' CONFIG_MD_LINEAR tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED - tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING - tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 +# tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING +# tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then bool ' Boot support (linear, striped)' CONFIG_MD_BOOT diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 3e5c9a6e6af3..51241640dcc4 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -196,7 +196,6 @@ static int use_virtual_dma=0; static unsigned short virtual_dma_port=0x3f0; void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs); static int set_dor(int fdc, char mask, char data); -static inline int __get_order(unsigned long size); #define K_64 0x10000 /* 64KB */ #include @@ -213,26 +212,12 @@ static inline int __get_order(unsigned long size); /* Dma Memory related stuff */ -/* Pure 2^n version of get_order */ -static inline int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - #ifndef fd_dma_mem_free -#define fd_dma_mem_free(addr, size) free_pages(addr, __get_order(size)) +#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) #endif #ifndef fd_dma_mem_alloc -#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size)) +#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size)) #endif static inline void fallback_on_nodma_alloc(char **addr, size_t l) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 9eab534aac0f..a717929e6d01 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -453,7 +453,7 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) lo->lo_backing_file = NULL; } } - aops = lo->lo_dentry->d_inode->i_mapping->a_ops; + aops = inode->i_mapping->a_ops; /* * If we can't read - sorry. If we only can't write - well, * it's going to be read-only. diff --git a/drivers/block/xd.c b/drivers/block/xd.c index b4c52d6a2e69..aa4c33949114 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -87,21 +87,8 @@ XD_INFO xd_info[XD_MAXDRIVES]; should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */ #include -/* coppied from floppy.c */ -static inline int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} -#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size)) -#define xd_dma_mem_free(addr, size) free_pages(addr, __get_order(size)) +#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size)) +#define xd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) static char *xd_dma_buffer = 0; static XD_SIGNATURE xd_sigs[] __initdata = { diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 42cbaab55571..c34978479f43 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -228,7 +228,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_AGP" != "n" ]; then bool ' Intel 440LX/BX/GX support' CONFIG_AGP_INTEL bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810 - bool ' VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA + bool ' VIA chipset support' CONFIG_AGP_VIA bool ' AMD Irongate support' CONFIG_AGP_AMD bool ' Generic SiS support' CONFIG_AGP_SIS bool ' ALI M1541 support' CONFIG_AGP_ALI diff --git a/drivers/char/console.c b/drivers/char/console.c index 85c638ef2fee..49c7b17fdeb2 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -177,12 +177,13 @@ static struct vc_data *master_display_fg = NULL; * Unfortunately, we need to delay tty echo when we're currently writing to the * console since the code is (and always was) not re-entrant, so we insert * all filp requests to con_task_queue instead of tq_timer and run it from - * the console_bh. + * the console_tasklet. The console_tasklet is protected by the IRQ + * protected console_lock. */ DECLARE_TASK_QUEUE(con_task_queue); /* - * For the same reason, we defer scrollback to the console_bh. + * For the same reason, we defer scrollback to the console tasklet. */ static int scrollback_delta = 0; @@ -224,7 +225,7 @@ static inline unsigned short *screenpos(int currcons, int offset, int viewed) static inline void scrolldelta(int lines) { scrollback_delta += lines; - mark_bh(CONSOLE_BH); + tasklet_schedule(&console_tasklet); } static void scrup(int currcons, unsigned int t, unsigned int b, int nr) @@ -546,16 +547,12 @@ void redraw_screen(int new_console, int is_switch) { int redraw = 1; int currcons, old_console; - static int lock = 0; - if (lock) - return; if (!vc_cons_allocated(new_console)) { /* strange ... */ - printk("redraw_screen: tty %d not allocated ??\n", new_console+1); + /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */ return; } - lock = 1; if (is_switch) { currcons = fg_console; @@ -591,7 +588,6 @@ void redraw_screen(int new_console, int is_switch) set_leds(); compute_shiftstate(); } - lock = 0; } /* @@ -1785,6 +1781,19 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c) } } +/* This is a temporary buffer used to prepare a tty console write + * so that we can easily avoid touching user space while holding the + * console spinlock. It is allocated in con_init and is shared by + * this code and the vc_screen read/write tty calls. + * + * We have to allocate this statically in the kernel data section + * since console_init (and thus con_init) are called before any + * kernel memory allocation is available. + */ +char con_buf[PAGE_SIZE]; +#define CON_BUF_SIZE PAGE_SIZE +DECLARE_MUTEX(con_buf_sem); + static int do_con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { @@ -1814,12 +1823,28 @@ static int do_con_write(struct tty_struct * tty, int from_user, return 0; } + down(&con_buf_sem); + if (from_user) { - /* just to make sure that noone lurks at places he shouldn't see. */ - if (verify_area(VERIFY_READ, buf, count)) - return 0; /* ?? are error codes legal here ?? */ + if (count > CON_BUF_SIZE) + count = CON_BUF_SIZE; + if (copy_from_user(con_buf, buf, count)) { + n = 0; /* ?? are error codes legal here ?? */ + goto out; + } + + buf = con_buf; } + /* At this point 'buf' is guarenteed to be a kernel buffer + * and therefore no access to userspace (and therefore sleeping) + * will be needed. The con_buf_sem serializes all tty based + * console rendering and vcs write/read operations. We hold + * the console spinlock during the entire write. + */ + + spin_lock_irq(&console_lock); + himask = hi_font_mask; charmask = himask ? 0x1ff : 0xff; @@ -1827,15 +1852,11 @@ static int do_con_write(struct tty_struct * tty, int from_user, if (IS_FG) hide_cursor(currcons); - disable_bh(CONSOLE_BH); while (!tty->stopped && count) { - enable_bh(CONSOLE_BH); - if (from_user) - __get_user(c, buf); - else - c = *buf; - buf++; n++; count--; - disable_bh(CONSOLE_BH); + c = *buf; + buf++; + n++; + count--; if (utf) { /* Combine UTF-8 into Unicode */ @@ -1940,23 +1961,34 @@ static int do_con_write(struct tty_struct * tty, int from_user, do_con_trol(tty, currcons, c); } FLUSH - enable_bh(CONSOLE_BH); + spin_unlock_irq(&console_lock); + +out: + up(&con_buf_sem); + return n; #undef FLUSH } /* - * This is the console switching bottom half handler. + * This is the console switching tasklet. * - * Doing console switching in a bottom half handler allows + * Doing console switching in a tasklet allows * us to do the switches asynchronously (needed when we want - * to switch due to a keyboard interrupt), while still giving - * us the option to easily disable it to avoid races when we - * need to write to the console. + * to switch due to a keyboard interrupt). Synchronization + * with other console code and prevention of re-entrancy is + * ensured with console_lock. */ -static void console_bh(void) +static void console_softint(unsigned long ignored) { + /* Runs the task queue outside of the console lock. These + * callbacks can come back into the console code and thus + * will perform their own locking. + */ run_task_queue(&con_task_queue); + + spin_lock_irq(&console_lock); + if (want_console >= 0) { if (want_console != fg_console && vc_cons_allocated(want_console)) { hide_cursor(fg_console); @@ -1978,6 +2010,8 @@ static void console_bh(void) sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta); scrollback_delta = 0; } + + spin_unlock_irq(&console_lock); } #ifdef CONFIG_VT_CONSOLE @@ -1985,10 +2019,7 @@ static void console_bh(void) /* * Console on virtual terminal * - * NOTE NOTE NOTE! This code can do no global locking. In particular, - * we can't disable interrupts or bottom half handlers globally, because - * we can be called from contexts that hold critical spinlocks, and - * trying do get a global lock at this point will lead to deadlocks. + * The console_lock must be held when we get here. */ void vt_console_print(struct console *co, const char * b, unsigned count) @@ -2015,7 +2046,7 @@ void vt_console_print(struct console *co, const char * b, unsigned count) if (!vc_cons_allocated(currcons)) { /* impossible */ - printk("vt_console_print: tty %d not allocated ??\n", currcons+1); + /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ goto quit; } @@ -2305,6 +2336,8 @@ static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, struct tty_driver console_driver; static int console_refcount; +DECLARE_TASKLET_DISABLED(console_tasklet, console_softint, 0); + void __init con_init(void) { const char *display_desc = NULL; @@ -2393,7 +2426,8 @@ void __init con_init(void) register_console(&vt_console_driver); #endif - init_bh(CONSOLE_BH, console_bh); + tasklet_enable(&console_tasklet); + tasklet_schedule(&console_tasklet); } #ifndef VT_SINGLE_DRIVER @@ -2744,9 +2778,11 @@ int con_font_op(int currcons, struct console_font_op *op) } op->data = temp; } - disable_bh(CONSOLE_BH); + + spin_lock_irq(&console_lock); rc = sw->con_font_op(vc_cons[currcons].d, op); - enable_bh(CONSOLE_BH); + spin_unlock_irq(&console_lock); + op->data = old_op.data; if (!rc && !set) { int c = (op->width+7)/8 * 32 * op->charcount; diff --git a/drivers/char/dz.c b/drivers/char/dz.c index 56cef67b391b..da4f476d1951 100644 --- a/drivers/char/dz.c +++ b/drivers/char/dz.c @@ -1427,6 +1427,7 @@ static void dz_console_put_char (unsigned char ch) * dz_console_print () * * dz_console_print is registered for printk. + * The console_lock must be held when we get here. * ------------------------------------------------------------------- */ static void dz_console_print (struct console *cons, diff --git a/drivers/char/esp.c b/drivers/char/esp.c index ff800e6c4568..e3cea9e5d4be 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -203,20 +203,6 @@ static inline void serial_out(struct esp_struct *info, int offset, outb(value, info->port+offset); } -static inline int __get_order(unsigned long size) -{ - int order; - - size = (size + PAGE_SIZE -1) >> PAGE_SHIFT; - order = -1; - do { - size >>= 1; - order++; - } while (size); - - return order; -} - /* * ------------------------------------------------------------ * rs_stop() and rs_start() @@ -965,14 +951,14 @@ static int startup(struct esp_struct * info) if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) { dma_buffer = (char *)__get_dma_pages( - GFP_KERNEL, __get_order(DMA_BUFFER_SZ)); + GFP_KERNEL, get_order(DMA_BUFFER_SZ)); /* use PIO mode if DMA buf/chan cannot be allocated */ if (!dma_buffer) info->stat_flags |= ESP_STAT_USE_PIO; else if (request_dma(dma, "esp serial")) { free_pages((unsigned int)dma_buffer, - __get_order(DMA_BUFFER_SZ)); + get_order(DMA_BUFFER_SZ)); dma_buffer = 0; info->stat_flags |= ESP_STAT_USE_PIO; } @@ -1076,7 +1062,7 @@ static void shutdown(struct esp_struct * info) if (!current_port) { free_dma(dma); free_pages((unsigned int)dma_buffer, - __get_order(DMA_BUFFER_SZ)); + get_order(DMA_BUFFER_SZ)); dma_buffer = 0; } } @@ -2785,7 +2771,7 @@ void cleanup_module(void) if (dma_buffer) free_pages((unsigned int)dma_buffer, - __get_order(DMA_BUFFER_SZ)); + get_order(DMA_BUFFER_SZ)); if (tmp_buf) free_page((unsigned long)tmp_buf); diff --git a/drivers/char/ftape/lowlevel/ftape-buffer.c b/drivers/char/ftape/lowlevel/ftape-buffer.c index 8de9805625f1..d7d31dbbbcd9 100644 --- a/drivers/char/ftape/lowlevel/ftape-buffer.c +++ b/drivers/char/ftape/lowlevel/ftape-buffer.c @@ -39,20 +39,6 @@ /* DMA'able memory allocation stuff. */ -/* Pure 2^n version of get_order */ -static inline int __get_order(size_t size) -{ - unsigned long order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static inline void *dmaalloc(size_t size) { unsigned long addr; @@ -60,7 +46,7 @@ static inline void *dmaalloc(size_t size) if (size == 0) { return NULL; } - addr = __get_dma_pages(GFP_KERNEL, __get_order(size)); + addr = __get_dma_pages(GFP_KERNEL, get_order(size)); if (addr) { int i; @@ -80,7 +66,7 @@ static inline void dmafree(void *addr, size_t size) i < MAP_NR((unsigned long)addr+size); i++) { mem_map_unreserve (i); } - free_pages((unsigned long) addr, __get_order(size)); + free_pages((unsigned long) addr, get_order(size)); } } diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index a9634ad91958..77dc4625b5c8 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -2051,7 +2051,8 @@ void cleanup_module(void) re_schedule = 0; current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ); - disable_bh(ISICOM_BH); + + remove_bh(ISICOM_BH); #ifdef ISICOM_DEBUG printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 2315edf77bc6..a065669d040b 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -208,7 +208,7 @@ void handle_scancode(unsigned char scancode, int down) pm_access(pm_kbd); do_poke_blanked_console = 1; - mark_bh(CONSOLE_BH); + tasklet_schedule(&console_tasklet); add_keyboard_randomness(scancode | up_flag); tty = ttytab? ttytab[fg_console]: NULL; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 6c1230a1dd88..a68742c18e39 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -661,6 +661,8 @@ static struct file_operations lp_fops = { * non-zero to get the latter behaviour. */ #define CONSOLE_LP_STRICT 1 +/* The console_lock must be held when we get here. */ + static void lp_console_write (struct console *co, const char *s, unsigned count) { diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c index 75f27e8305da..2e451ce179f4 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -1198,7 +1198,6 @@ int __init pcxe_init(void) memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs); init_bh(DIGI_BH,do_pcxe_bh); - enable_bh(DIGI_BH); timer_table[DIGI_TIMER].fn = pcxxpoll; timer_table[DIGI_TIMER].expires = 0; diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 53e67aea72ab..e728197e7013 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -4664,6 +4664,8 @@ static inline void wait_for_xmitr(struct async_struct *info) /* * Print a string to the serial port trying not to disturb * any possible real use of the port... + * + * The console_lock must be held when we get here. */ static void serial_console_write(struct console *co, const char *s, unsigned count) diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 885b236fd172..35b480a1ce71 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -2729,6 +2729,8 @@ void console_setup(char *str, int *ints) * * Of course, once the console has been registered, we had better ensure * that serial167_init() doesn't leave the chip non-functional. + * + * The console_lock must be held when we get here. */ void serial167_console_write(struct console *co, const char *str, unsigned count) diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index 7a9257ae9c3a..4f6a1cef3ecd 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -2774,23 +2774,6 @@ static struct file_operations qic02_tape_fops = { }; -/* Why is this not is one place? */ -/* Pure 2^n version of get_order */ -static inline int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do - { - size >>= 1; - order++; - } while (size); - return order; -} - - static void qic02_release_resources(void) { free_irq(QIC02_TAPE_IRQ, NULL); @@ -2798,7 +2781,7 @@ static void qic02_release_resources(void) release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); if (buffaddr) { - free_pages(buffaddr, __get_order(TPQBUF_SIZE)); + free_pages(buffaddr, get_order(TPQBUF_SIZE)); } buffaddr = 0; /* Better to cause a panic than overwite someone else */ status_zombie = YES; @@ -2850,7 +2833,7 @@ static int qic02_get_resources(void) /* Setup the page-address for the dma transfer. */ /*** TODO: does _get_dma_pages() really return the physical address?? ****/ - buffaddr = __get_dma_pages(GFP_KERNEL,__get_order(TPQBUF_SIZE)); + buffaddr = __get_dma_pages(GFP_KERNEL,get_order(TPQBUF_SIZE)); if (!buffaddr) { diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index e099b4ac39bb..2aa610a9cef8 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -80,7 +82,14 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) return file->f_pos; } -#define RETURN(x) { enable_bh(CONSOLE_BH); return x; } +/* We share this temporary buffer with the console write code + * so that we can easily avoid touching user space while holding the + * console spinlock. + */ +extern char con_buf[PAGE_SIZE]; +#define CON_BUF_SIZE PAGE_SIZE +extern struct semaphore con_buf_sem; + static ssize_t vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) { @@ -88,13 +97,20 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) unsigned int currcons = MINOR(inode->i_rdev); long p = *ppos; long viewed, attr, size, read; - char *buf0; + char *con_buf0; int col, maxcol; unsigned short *org = NULL; + ssize_t ret, orig_count; + + down(&con_buf_sem); + + /* Select the proper current console and verify + * sanity of the situation under the console lock. + */ + spin_lock_irq(&console_lock); attr = (currcons & 128); currcons = (currcons & 127); - disable_bh(CONSOLE_BH); if (currcons == 0) { currcons = fg_console; viewed = 1; @@ -102,23 +118,33 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) currcons--; viewed = 0; } + ret = -ENXIO; if (!vc_cons_allocated(currcons)) - RETURN( -ENXIO ); + goto unlock_out; size = vcs_size(inode); + ret = -EINVAL; if (p < 0 || p > size) - RETURN( -EINVAL ); + goto unlock_out; if (count > size - p) count = size - p; + if (count > CON_BUF_SIZE) + count = CON_BUF_SIZE; - buf0 = buf; + /* Perform the whole read into the local con_buf. + * Then we can drop the console spinlock and safely + * attempt to move it to userspace. + */ + + con_buf0 = con_buf; + orig_count = count; maxcol = video_num_columns; if (!attr) { org = screen_pos(currcons, p, viewed); col = p % maxcol; p += maxcol - col; while (count-- > 0) { - put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); + *con_buf0++ = (vcs_scr_readw(currcons, org++) & 0xff); if (++col == maxcol) { org = screen_pos(currcons, p, viewed); col = 0; @@ -127,24 +153,38 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) } } else { if (p < HEADER_SIZE) { - char header[HEADER_SIZE]; - header[0] = (char) video_num_lines; - header[1] = (char) video_num_columns; - getconsxy(currcons, header+2); - while (p < HEADER_SIZE && count > 0) - { count--; put_user(header[p++], buf++); } + size_t tmp_count; + + con_buf0[0] = (char) video_num_lines; + con_buf0[1] = (char) video_num_columns; + getconsxy(currcons, con_buf0 + 2); + + tmp_count = HEADER_SIZE - p; + if (tmp_count > count) + tmp_count = count; + + /* Advance state pointers and move on. */ + count -= tmp_count; + buf += tmp_count; + p += tmp_count; + con_buf0 += tmp_count; } p -= HEADER_SIZE; col = (p/2) % maxcol; if (count > 0) { + char tmp_byte; + org = screen_pos(currcons, p/2, viewed); if ((p & 1) && count > 0) { - count--; #ifdef __BIG_ENDIAN - put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); + tmp_byte = vcs_scr_readw(currcons, org++) & 0xff; #else - put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); + tmp_byte = vcs_scr_readw(currcons, org++) >> 8; #endif + + *con_buf0++ = tmp_byte; + + count--; p++; if (++col == maxcol) { org = screen_pos(currcons, p/2, viewed); @@ -154,26 +194,59 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) p /= 2; p += maxcol - col; } - while (count > 1) { - put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf); - buf += 2; - count -= 2; - if (++col == maxcol) { - org = screen_pos(currcons, p, viewed); - col = 0; - p += maxcol; + + if (count > 1) { + size_t tmp_count = count; + unsigned short *tmp_buf = (unsigned short *)con_buf0; + + while (tmp_count > 1) { + *tmp_buf++ = vcs_scr_readw(currcons, org++); + tmp_count -= 2; + if (++col == maxcol) { + org = screen_pos(currcons, p, viewed); + col = 0; + p += maxcol; + } } + + /* Advance pointers, and move on. */ + count -= (char *)tmp_buf - con_buf0; + con_buf0 += (char *)tmp_buf - con_buf0; } - if (count > 0) + if (count > 0) { + char tmp_byte; + #ifdef __BIG_ENDIAN - put_user(vcs_scr_readw(currcons, org) >> 8, buf++); + tmp_byte = vcs_scr_readw(currcons, org) >> 8; #else - put_user(vcs_scr_readw(currcons, org) & 0xff, buf++); + tmp_byte = vcs_scr_readw(currcons, org) & 0xff; #endif + + *con_buf0++ = tmp_byte; + } } - read = buf - buf0; - *ppos += read; - RETURN( read ); + + /* Finally, temporarily drop the console lock and push + * all the data to userspace from our temporary buffer. + */ + + spin_unlock_irq(&console_lock); + ret = copy_to_user(buf, con_buf0, orig_count); + spin_lock_irq(&console_lock); + + if (ret) { + ret = -EFAULT; + } else { + read = orig_count; + *ppos += read; + ret = read; + } + +unlock_out: + spin_unlock_irq(&console_lock); + + up(&con_buf_sem); + return ret; } static ssize_t @@ -183,13 +256,21 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) unsigned int currcons = MINOR(inode->i_rdev); long p = *ppos; long viewed, attr, size, written; - const char *buf0; + char *con_buf0; int col, maxcol; u16 *org0 = NULL, *org = NULL; + size_t ret, orig_count; + + down(&con_buf_sem); + + /* Select the proper current console and verify + * sanity of the situation under the console lock. + */ + spin_lock_irq(&console_lock); attr = (currcons & 128); currcons = (currcons & 127); - disable_bh(CONSOLE_BH); + if (currcons == 0) { currcons = fg_console; viewed = 1; @@ -197,26 +278,59 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) currcons--; viewed = 0; } + ret = -ENXIO; if (!vc_cons_allocated(currcons)) - RETURN( -ENXIO ); + goto unlock_out; size = vcs_size(inode); + ret = -EINVAL; if (p < 0 || p > size) - RETURN( -EINVAL ); + goto unlock_out; + if (count > size - p) + count = size - p; + if (count > CON_BUF_SIZE) + count = CON_BUF_SIZE; + + /* Temporarily drop the console lock so that we can read + * in the write data from userspace safely. + */ + spin_unlock_irq(&console_lock); + ret = copy_from_user(con_buf, buf, count); + spin_lock_irq(&console_lock); + + if (ret) { + ret = -EFAULT; + goto unlock_out; + } + + /* The vcs_size might have changed while we slept to grab + * the user buffer, so recheck. + */ + size = vcs_size(inode); + ret = -EINVAL; + if (p > size) + goto unlock_out; if (count > size - p) count = size - p; - buf0 = buf; + /* OK, now actually push the write to the console + * under the lock using the local kernel buffer. + */ + + con_buf0 = con_buf; + orig_count = count; maxcol = video_num_columns; if (!attr) { org0 = org = screen_pos(currcons, p, viewed); col = p % maxcol; p += maxcol - col; + while (count > 0) { - unsigned char c; + unsigned char c = *con_buf0++; + count--; - get_user(c, (const unsigned char*)buf++); - vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org); + vcs_scr_writew(currcons, + (vcs_scr_readw(currcons, org) & 0xff00) | c, org); org++; if (++col == maxcol) { org = screen_pos(currcons, p, viewed); @@ -227,20 +341,24 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) } else { if (p < HEADER_SIZE) { char header[HEADER_SIZE]; - getconsxy(currcons, header+2); - while (p < HEADER_SIZE && count > 0) - { count--; get_user(header[p++], buf++); } + + getconsxy(currcons, header + 2); + while (p < HEADER_SIZE && count > 0) { + count--; + header[p++] = *con_buf0++; + } if (!viewed) - putconsxy(currcons, header+2); + putconsxy(currcons, header + 2); } p -= HEADER_SIZE; col = (p/2) % maxcol; if (count > 0) { org0 = org = screen_pos(currcons, p/2, viewed); if ((p & 1) && count > 0) { - char c; + char c; + count--; - get_user(c,buf++); + c = *con_buf0++; #ifdef __BIG_ENDIAN vcs_scr_writew(currcons, c | (vcs_scr_readw(currcons, org) & 0xff00), org); @@ -260,9 +378,10 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) } while (count > 1) { unsigned short w; - get_user(w, (const unsigned short *) buf); + + w = *((const unsigned short *)con_buf0); vcs_scr_writew(currcons, w, org++); - buf += 2; + con_buf0 += 2; count -= 2; if (++col == maxcol) { org = screen_pos(currcons, p, viewed); @@ -272,7 +391,8 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) } if (count > 0) { unsigned char c; - get_user(c, (const unsigned char*)buf++); + + c = *con_buf0++; #ifdef __BIG_ENDIAN vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org); #else @@ -282,9 +402,16 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos) } if (org0) update_region(currcons, (unsigned long)(org0), org-org0); - written = buf - buf0; + written = orig_count; *ppos += written; - RETURN( written ); + ret = written; + +unlock_out: + spin_unlock_irq(&console_lock); + + up(&con_buf_sem); + + return ret; } static int diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 15232f8321de..b6b2263a0f3a 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -1045,6 +1045,7 @@ static void scc_ch_write (char ch) *p = ch; } +/* The console_lock must be held when we get here. */ static void scc_console_write (struct console *co, const char *str, unsigned count) { diff --git a/drivers/char/vt.c b/drivers/char/vt.c index e52eec625fdb..6b1d19af5465 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -804,12 +805,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * When we actually do the console switch, * make sure we are atomic with respect to * other console switches.. - * - * Damn! Was it difficult to make this clean? */ - disable_bh(CONSOLE_BH); + spin_lock_irq(&console_lock); complete_change_console(newvt); - enable_bh(CONSOLE_BH); + spin_unlock_irq(&console_lock); } } diff --git a/drivers/char/zr36120_mem.c b/drivers/char/zr36120_mem.c index 5e81049eb064..082cfee061e6 100644 --- a/drivers/char/zr36120_mem.c +++ b/drivers/char/zr36120_mem.c @@ -35,17 +35,6 @@ /* Memory management functions */ /*******************************/ -inline int __get_order(unsigned long size) -{ - int order = 0; - size = (size+PAGE_SIZE-1)/PAGE_SIZE; - while (size) { - size /= 2; - order++; - } - return order; -} - void* bmalloc(unsigned long size) { void* mem; @@ -56,7 +45,7 @@ void* bmalloc(unsigned long size) * The following function got a lot of memory at boottime, * so we know its always there... */ - mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,__get_order(size)); + mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,get_order(size)); #endif if (mem) { unsigned long adr = (unsigned long)mem; @@ -82,7 +71,7 @@ void bfree(void* mem, unsigned long size) #ifdef CONFIG_BIGPHYS_AREA bigphysarea_free_pages(mem); #else - free_pages((unsigned long)mem,__get_order(size)); + free_pages((unsigned long)mem,get_order(size)); #endif } } diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 2081f12fe68b..a73c26766382 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -12,68 +12,99 @@ 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 + if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then + if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then + bool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + fi + fi + 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 + if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then + bool ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 + fi + bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON +fi +if [ "$CONFIG_PROC_FS" != "n" ]; then +if [ "$CONFIG_MODULES" != "n" ]; then + bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN +fi fi +endmenu diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 04be19f9cd69..c945517165bd 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -1,6 +1,6 @@ SUB_DIRS := MOD_SUB_DIRS := -ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert +ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert hysdn L_OBJS := LX_OBJS := @@ -137,5 +137,9 @@ else endif endif +ifeq ($(CONFIG_HYSDN),y) + MOD_SUB_DIRS += hysdn +endif + include $(TOPDIR)/Rules.make diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile index 111c39466fb9..bfeb81939a0b 100644 --- a/drivers/isdn/avmb1/Makefile +++ b/drivers/isdn/avmb1/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.7 1999/09/15 08:16:03 calle Exp $ +# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $ # # Makefile for the CAPI and AVM-B1 device drivers. # @@ -11,6 +11,11 @@ # parent makes.. # # $Log: Makefile,v $ +# Revision 1.8 2000/01/25 14:33:38 calle +# - Added Support AVM B1 PCI V4.0 (tested with prototype) +# - splitted up t1pci.c into b1dma.c for common function with b1pciv4 +# - support for revision register +# # Revision 1.7 1999/09/15 08:16:03 calle # Implementation of 64Bit extention complete. # @@ -99,7 +104,7 @@ ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) ifdef CONFIG_ISDN_DRV_AVMB1_C4 O_OBJS += c4.o endif - OX_OBJS += capiutil.o capidrv.o b1.o + OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o else ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) O_TARGET += kernelcapi.o @@ -123,7 +128,7 @@ else ifdef CONFIG_ISDN_DRV_AVMB1_C4 M_OBJS += c4.o endif - MX_OBJS += capiutil.o capidrv.o b1.o + MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o endif endif diff --git a/drivers/isdn/avmb1/avmcard.h b/drivers/isdn/avmb1/avmcard.h index f4b5df689119..56fa0fba6d79 100644 --- a/drivers/isdn/avmb1/avmcard.h +++ b/drivers/isdn/avmb1/avmcard.h @@ -1,9 +1,14 @@ /* - * $Id: avmcard.h,v 1.6 1999/11/05 16:38:01 calle Exp $ + * $Id: avmcard.h,v 1.7 2000/01/25 14:33:38 calle Exp $ * * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: avmcard.h,v $ + * Revision 1.7 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.6 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -92,6 +97,8 @@ typedef struct avmcard { unsigned irq; unsigned long membase; enum avmcardtype cardtype; + unsigned char revision; + unsigned char class; int cardnr; /* for t1isa */ char msgbuf[128]; /* capimsg msg part */ @@ -228,8 +235,9 @@ extern int b1_irq_table[16]; #define B1_WRITE 0x01 #define B1_INSTAT 0x02 #define B1_OUTSTAT 0x03 -#define B1_RESET 0x10 #define B1_ANALYSE 0x04 +#define B1_REVISION 0x05 +#define B1_RESET 0x10 #define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l) @@ -561,10 +569,13 @@ static inline void b1_setinterrupt(unsigned int base, unsigned irq, } } +/* b1.c */ int b1_detect(unsigned int base, enum avmcardtype cardtype); +void b1_getrevision(avmcard *card); int b1_load_t4file(avmcard *card, capiloaddatapart * t4file); int b1_load_config(avmcard *card, capiloaddatapart * config); int b1_loaded(avmcard *card); + int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); void b1_reset_ctr(struct capi_ctr *ctrl); void b1_register_appl(struct capi_ctr *ctrl, __u16 appl, @@ -577,5 +588,21 @@ void b1_handle_interrupt(avmcard * card); int b1ctl_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl); +/* b1dma.c */ +int b1pciv4_detect(avmcard *card); +int t1pci_detect(avmcard *card); +void b1dma_reset(avmcard *card); +void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs); + +int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); +void b1dma_reset_ctr(struct capi_ctr *ctrl); +void b1dma_remove_ctr(struct capi_ctr *ctrl); +void b1dma_register_appl(struct capi_ctr *ctrl, + __u16 appl, + capi_register_params *rp); +void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl); +void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); +int b1dmactl_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl); #endif /* _AVMCARD_H_ */ diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c index 900b31c8c163..65c4368cdf96 100644 --- a/drivers/isdn/avmb1/b1.c +++ b/drivers/isdn/avmb1/b1.c @@ -1,11 +1,16 @@ /* - * $Id: b1.c,v 1.12 1999/11/05 16:38:01 calle Exp $ + * $Id: b1.c,v 1.13 2000/01/25 14:33:38 calle Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.13 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.12 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -86,7 +91,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.12 $"; +static char *revision = "$Revision: 1.13 $"; /* ------------------------------------------------------------- */ @@ -158,6 +163,12 @@ int b1_detect(unsigned int base, enum avmcardtype cardtype) return 0; } +void b1_getrevision(avmcard *card) +{ + card->class = inb(card->port + B1_ANALYSE); + card->revision = inb(card->port + B1_REVISION); +} + int b1_load_t4file(avmcard *card, capiloaddatapart * t4file) { unsigned char buf[256]; @@ -688,6 +699,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off, EXPORT_SYMBOL(b1_irq_table); EXPORT_SYMBOL(b1_detect); +EXPORT_SYMBOL(b1_getrevision); EXPORT_SYMBOL(b1_load_t4file); EXPORT_SYMBOL(b1_load_config); EXPORT_SYMBOL(b1_loaded); diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c new file mode 100644 index 000000000000..04eb29aba1ef --- /dev/null +++ b/drivers/isdn/avmb1/b1dma.c @@ -0,0 +1,983 @@ +/* + * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $ + * + * Common module for AVM B1 cards that support dma with AMCC + * + * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1dma.c,v $ + * Revision 1.2 2000/01/25 14:44:47 calle + * typo in b1pciv4_detect(). + * + * Revision 1.1 2000/01/25 14:36:43 calle + * common function for T1 PCI and B1 PCI V4. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "capilli.h" +#include "avmcard.h" +#include "capicmd.h" +#include "capiutil.h" + +static char *revision = "$Revision: 1.2 $"; + +/* ------------------------------------------------------------- */ + +MODULE_AUTHOR("Carsten Paeth "); + +int suppress_pollack = 0; +MODULE_PARM(suppress_pollack, "0-1i"); + +/* ------------------------------------------------------------- */ + +static void b1dma_dispatch_tx(avmcard *card); + +/* ------------------------------------------------------------- */ + +/* S5933 */ + +#define AMCC_RXPTR 0x24 +#define AMCC_RXLEN 0x28 +#define AMCC_TXPTR 0x2c +#define AMCC_TXLEN 0x30 + +#define AMCC_INTCSR 0x38 +# define EN_READ_TC_INT 0x00008000L +# define EN_WRITE_TC_INT 0x00004000L +# define EN_TX_TC_INT EN_READ_TC_INT +# define EN_RX_TC_INT EN_WRITE_TC_INT +# define AVM_FLAG 0x30000000L + +# define ANY_S5933_INT 0x00800000L +# define READ_TC_INT 0x00080000L +# define WRITE_TC_INT 0x00040000L +# define TX_TC_INT READ_TC_INT +# define RX_TC_INT WRITE_TC_INT +# define MASTER_ABORT_INT 0x00100000L +# define TARGET_ABORT_INT 0x00200000L +# define BUS_MASTER_INT 0x00200000L +# define ALL_INT 0x000C0000L + +#define AMCC_MCSR 0x3c +# define A2P_HI_PRIORITY 0x00000100L +# define EN_A2P_TRANSFERS 0x00000400L +# define P2A_HI_PRIORITY 0x00001000L +# define EN_P2A_TRANSFERS 0x00004000L +# define RESET_A2P_FLAGS 0x04000000L +# define RESET_P2A_FLAGS 0x02000000L + +/* ------------------------------------------------------------- */ + +#define b1dmaoutmeml(addr, value) writel(value, addr) +#define b1dmainmeml(addr) readl(addr) +#define b1dmaoutmemw(addr, value) writew(value, addr) +#define b1dmainmemw(addr) readw(addr) +#define b1dmaoutmemb(addr, value) writeb(value, addr) +#define b1dmainmemb(addr) readb(addr) + +/* ------------------------------------------------------------- */ + +static inline int b1dma_tx_empty(unsigned int port) +{ + return inb(port + 0x03) & 0x1; +} + +static inline int b1dma_rx_full(unsigned int port) +{ + return inb(port + 0x02) & 0x1; +} + +static int b1dma_tolink(avmcard *card, void *buf, unsigned int len) +{ + unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ + unsigned char *s = (unsigned char *)buf; + while (len--) { + while ( !b1dma_tx_empty(card->port) + && time_before(jiffies, stop)); + if (!b1dma_tx_empty(card->port)) + return -1; + t1outp(card->port, 0x01, *s++); + } + return 0; +} + +static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len) +{ + unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ + unsigned char *s = (unsigned char *)buf; + while (len--) { + while ( !b1dma_rx_full(card->port) + && time_before(jiffies, stop)); + if (!b1dma_rx_full(card->port)) + return -1; + *s++ = t1inp(card->port, 0x00); + } + return 0; +} + +static int WriteReg(avmcard *card, __u32 reg, __u8 val) +{ + __u8 cmd = 0x00; + if ( b1dma_tolink(card, &cmd, 1) == 0 + && b1dma_tolink(card, ®, 4) == 0) { + __u32 tmp = val; + return b1dma_tolink(card, &tmp, 4); + } + return -1; +} + +static __u8 ReadReg(avmcard *card, __u32 reg) +{ + __u8 cmd = 0x01; + if ( b1dma_tolink(card, &cmd, 1) == 0 + && b1dma_tolink(card, ®, 4) == 0) { + __u32 tmp; + if (b1dma_fromlink(card, &tmp, 4) == 0) + return (__u8)tmp; + } + return 0xff; +} + +/* ------------------------------------------------------------- */ + +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; +} + +/* ------------------------------------------------------------- */ + +void b1dma_reset(avmcard *card) +{ + unsigned long flags; + + save_flags(flags); + cli(); + card->csr = 0x0; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0); + b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0); + + t1outp(card->port, 0x10, 0x00); + t1outp(card->port, 0x07, 0x00); + + restore_flags(flags); + + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + if (card->cardtype == avm_t1pci) + udelay(42 * 1000); + else + udelay(10 * 1000); +} + +/* ------------------------------------------------------------- */ + +int b1dma_detect(avmcard *card) +{ + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ + udelay(10 * 1000); + b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); + udelay(42 * 1000); + + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0); + b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0); + card->csr = 0x0; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + + if (b1dmainmeml(card->mbase+AMCC_MCSR) != 0x000000E6) + return 1; + + b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0xffffffff); + b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0xffffffff); + if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc + || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc) + return 2; + + b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0x0); + b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0x0); + if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0x0 + || b1dmainmeml(card->mbase+AMCC_TXPTR) != 0x0) + return 3; + + t1outp(card->port, 0x10, 0x00); + t1outp(card->port, 0x07, 0x00); + + t1outp(card->port, 0x02, 0x02); + t1outp(card->port, 0x03, 0x02); + + if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02 + || t1inp(card->port, 0x3) != 0x03) + return 4; + + t1outp(card->port, 0x02, 0x00); + t1outp(card->port, 0x03, 0x00); + + if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00 + || t1inp(card->port, 0x3) != 0x01) + return 5; + + return 0; +} + +int t1pci_detect(avmcard *card) +{ + int ret; + + if ((ret = b1dma_detect(card)) != 0) + return ret; + + /* Transputer test */ + + if ( WriteReg(card, 0x80001000, 0x11) != 0 + || WriteReg(card, 0x80101000, 0x22) != 0 + || WriteReg(card, 0x80201000, 0x33) != 0 + || WriteReg(card, 0x80301000, 0x44) != 0) + return 6; + + if ( ReadReg(card, 0x80001000) != 0x11 + || ReadReg(card, 0x80101000) != 0x22 + || ReadReg(card, 0x80201000) != 0x33 + || ReadReg(card, 0x80301000) != 0x44) + return 7; + + if ( WriteReg(card, 0x80001000, 0x55) != 0 + || WriteReg(card, 0x80101000, 0x66) != 0 + || WriteReg(card, 0x80201000, 0x77) != 0 + || WriteReg(card, 0x80301000, 0x88) != 0) + return 8; + + if ( ReadReg(card, 0x80001000) != 0x55 + || ReadReg(card, 0x80101000) != 0x66 + || ReadReg(card, 0x80201000) != 0x77 + || ReadReg(card, 0x80301000) != 0x88) + return 9; + + return 0; +} + +int b1pciv4_detect(avmcard *card) +{ + int ret, i; + + if ((ret = b1dma_detect(card)) != 0) + return ret; + + for (i=0; i < 5 ; i++) { + if (WriteReg(card, 0x80A00000, 0x21) != 0) + return 6; + if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01) + return 7; + } + for (i=0; i < 5 ; i++) { + if (WriteReg(card, 0x80A00000, 0x20) != 0) + return 8; + if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00) + return 9; + } + + return 0; +} + +/* ------------------------------------------------------------- */ + +static void b1dma_dispatch_tx(avmcard *card) +{ + avmcard_dmainfo *dma = card->dma; + unsigned long flags; + struct sk_buff *skb; + __u8 cmd, subcmd; + __u16 len; + __u32 txlen; + int inint; + void *p; + + save_flags(flags); + cli(); + + inint = card->interrupt; + + if (card->csr & EN_TX_TC_INT) { /* tx busy */ + restore_flags(flags); + return; + } + + skb = skb_dequeue(&dma->send_queue); + if (!skb) { +#ifdef CONFIG_B1DMA_DEBUG + printk(KERN_DEBUG "tx(%d): underrun\n", inint); +#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_B1DMA_DEBUG + printk(KERN_DEBUG "tx(%d): put msg len=%d\n", + inint, txlen); +#endif + } else { + txlen = skb->len-2; +#ifdef CONFIG_B1DMA_POLLDEBUG + if (skb->data[2] == SEND_POLLACK) + printk(KERN_INFO "%s: send ack\n", card->name); +#endif +#ifdef CONFIG_B1DMA_DEBUG + printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n", + inint, skb->data[2], txlen); +#endif + memcpy(dma->sendbuf, skb->data+2, skb->len-2); + } + txlen = (txlen + 3) & ~3; + + b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf)); + b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen); + + card->csr |= EN_TX_TC_INT; + + if (!inint) + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + + 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); + b1dma_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +static void b1dma_handle_rx(avmcard *card) +{ + avmctrl_info *cinfo = &card->ctrlinfo[0]; + avmcard_dmainfo *dma = card->dma; + struct capi_ctr *ctrl = cinfo->capi_ctrl; + struct sk_buff *skb; + void *p = dma->recvbuf+4; + __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; + __u8 b1cmd = _get_byte(&p); + +#ifdef CONFIG_B1DMA_DEBUG + printk(KERN_DEBUG "rx: 0x%x %lu\n", 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); + + 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); + 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); + + ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); + + break; + + case RECEIVE_FREE_NCCI: + + ApplId = _get_word(&p); + NCCI = _get_word(&p); + + if (NCCI != 0xffffffff) + ctrl->free_ncci(ctrl, ApplId, NCCI); + else ctrl->appl_released(ctrl, ApplId); + break; + + case RECEIVE_START: +#ifdef CONFIG_B1DMA_POLLDEBUG + printk(KERN_INFO "%s: receive poll\n", card->name); +#endif + if (!suppress_pollack) + queue_pollack(card); + ctrl->resume_output(ctrl); + break; + + case RECEIVE_STOP: + ctrl->suspend_output(ctrl); + break; + + case RECEIVE_INIT: + + 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(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: b1dma_interrupt: 0x%x ???\n", + card->name, b1cmd); + return; + } +} + +/* ------------------------------------------------------------- */ + +static void b1dma_handle_interrupt(avmcard *card) +{ + __u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR); + __u32 newcsr; + + if ((status & ANY_S5933_INT) == 0) + return; + + newcsr = card->csr | (status & ALL_INT); + if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; + if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr); + + if ((status & RX_TC_INT) != 0) { + __u8 *recvbuf = card->dma->recvbuf; + __u32 rxlen; + if (card->dma->recvlen == 0) { + card->dma->recvlen = *((__u32 *)recvbuf); + rxlen = (card->dma->recvlen + 3) & ~3; + b1dmaoutmeml(card->mbase+AMCC_RXPTR, + virt_to_phys(recvbuf+4)); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen); + } else { + b1dma_handle_rx(card); + card->dma->recvlen = 0; + b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf)); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4); + } + } + + if ((status & TX_TC_INT) != 0) { + card->csr &= ~EN_TX_TC_INT; + b1dma_dispatch_tx(card); + } else if (card->csr & EN_TX_TC_INT) { + if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) { + card->csr &= ~EN_TX_TC_INT; + b1dma_dispatch_tx(card); + } + } + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); +} + +void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "b1dma: interrupt: wrong device\n"); + return; + } + if (card->interrupt) { + printk(KERN_ERR "%s: reentering interrupt hander\n", card->name); + return; + } + + card->interrupt = 1; + + b1dma_handle_interrupt(card); + + card->interrupt = 0; +} + +/* ------------------------------------------------------------- */ + +static int b1dma_loaded(avmcard *card) +{ + unsigned long stop; + unsigned char ans; + unsigned long tout = 2; + unsigned int base = card->port; + + for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { + if (b1_tx_empty(base)) + break; + } + if (!b1_tx_empty(base)) { + printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n", + card->name); + return 0; + } + b1_put_byte(base, SEND_POLLACK); + for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { + if (b1_rx_full(base)) { + if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) { + return 1; + } + printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans); + return 0; + } + } + printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name); + return 0; +} + +/* ------------------------------------------------------------- */ + +static void b1dma_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); + b1dma_dispatch_tx(card); +} + +int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + unsigned long flags; + int retval; + + b1dma_reset(card); + + if ((retval = b1_load_t4file(card, &data->firmware))) { + b1dma_reset(card); + printk(KERN_ERR "%s: failed to load t4file!!\n", + card->name); + return retval; + } + + if (data->configuration.len > 0 && data->configuration.data) { + if ((retval = b1_load_config(card, &data->configuration))) { + b1dma_reset(card); + printk(KERN_ERR "%s: failed to load config!!\n", + card->name); + return retval; + } + } + + if (!b1dma_loaded(card)) { + b1dma_reset(card); + printk(KERN_ERR "%s: failed to load t4file.\n", card->name); + return -EIO; + } + + save_flags(flags); + cli(); + + card->csr = AVM_FLAG; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + b1dmaoutmeml(card->mbase+AMCC_MCSR, + EN_A2P_TRANSFERS|EN_P2A_TRANSFERS + |A2P_HI_PRIORITY|P2A_HI_PRIORITY + |RESET_A2P_FLAGS|RESET_P2A_FLAGS); + t1outp(card->port, 0x07, 0x30); + t1outp(card->port, 0x10, 0xF0); + + card->dma->recvlen = 0; + b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf)); + b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4); + card->csr |= EN_RX_TC_INT; + b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr); + restore_flags(flags); + + b1dma_send_init(card); + + return 0; +} + +void b1dma_reset_ctr(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + + b1dma_reset(card); + + memset(cinfo->version, 0, sizeof(cinfo->version)); + ctrl->reseted(ctrl); +} + + +/* ------------------------------------------------------------- */ + + +void b1dma_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 (want > 0) nconn = want; + else nconn = ctrl->profile.nbchannel * -want; + if (nconn == 0) nconn = ctrl->profile.nbchannel; + + 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); + b1dma_dispatch_tx(card); + + ctrl->appl_registered(ctrl, appl); +} + +/* ------------------------------------------------------------- */ + +void b1dma_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; + + 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); + b1dma_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +void b1dma_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); + b1dma_dispatch_tx(card); +} + +/* ------------------------------------------------------------- */ + +int b1dmactl_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; + unsigned long flags; + __u8 flag; + int len = 0; + char *s; + __u32 txaddr, txlen, rxaddr, rxlen, csr; + + 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); + + save_flags(flags); + cli(); + + txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c)); + txaddr -= (__u32)card->dma->sendbuf; + txlen = b1dmainmeml(card->mbase+0x30); + + rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24)); + rxaddr -= (__u32)card->dma->recvbuf; + rxlen = b1dmainmeml(card->mbase+0x28); + + csr = b1dmainmeml(card->mbase+AMCC_INTCSR); + + restore_flags(flags); + + len += sprintf(page+len, "%-16s 0x%lx\n", + "csr (cached)", (unsigned long)card->csr); + len += sprintf(page+len, "%-16s 0x%lx\n", + "csr", (unsigned long)csr); + len += sprintf(page+len, "%-16s %lu\n", + "txoff", (unsigned long)txaddr); + len += sprintf(page+len, "%-16s %lu\n", + "txlen", (unsigned long)txlen); + len += sprintf(page+len, "%-16s %lu\n", + "rxoff", (unsigned long)rxaddr); + len += sprintf(page+len, "%-16s %lu\n", + "rxlen", (unsigned long)rxlen); + + if (off+count >= len) + *eof = 1; + if (len < off) + return 0; + *start = page + off; + return ((count < len-off) ? count : len-off); +} + +/* ------------------------------------------------------------- */ + +EXPORT_SYMBOL(b1dma_reset); +EXPORT_SYMBOL(t1pci_detect); +EXPORT_SYMBOL(b1pciv4_detect); +EXPORT_SYMBOL(b1dma_interrupt); + +EXPORT_SYMBOL(b1dma_load_firmware); +EXPORT_SYMBOL(b1dma_reset_ctr); +EXPORT_SYMBOL(b1dma_register_appl); +EXPORT_SYMBOL(b1dma_release_appl); +EXPORT_SYMBOL(b1dma_send_message); +EXPORT_SYMBOL(b1dmactl_read_proc); + +#ifdef MODULE +#define b1dma_init init_module +void cleanup_module(void); +#endif + +int b1dma_init(void) +{ + char *p; + char rev[10]; + + if ((p = strchr(revision, ':'))) { + strncpy(rev, p + 1, sizeof(rev)); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, "1.0"); + + printk(KERN_INFO "b1dma: revision %s\n", rev); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +} +#endif diff --git a/drivers/isdn/avmb1/b1isa.c b/drivers/isdn/avmb1/b1isa.c index 01972b2d21df..590e825b6d82 100644 --- a/drivers/isdn/avmb1/b1isa.c +++ b/drivers/isdn/avmb1/b1isa.c @@ -1,11 +1,19 @@ /* - * $Id: b1isa.c,v 1.5 1999/11/05 16:38:01 calle Exp $ + * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 calle Exp $ * * Module for AVM B1 ISA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1isa.c,v $ + * Revision 1.7 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.6 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * * Revision 1.5 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -61,7 +69,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.7 $"; /* ------------------------------------------------------------- */ @@ -69,10 +77,6 @@ MODULE_AUTHOR("Carsten Paeth "); /* ------------------------------------------------------------- */ -static struct capi_driver_interface *di; - -/* ------------------------------------------------------------- */ - static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) { avmcard *card; @@ -96,6 +100,10 @@ static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) } /* ------------------------------------------------------------- */ +static struct capi_driver_interface *di; + +/* ------------------------------------------------------------- */ + static void b1isa_remove_ctr(struct capi_ctr *ctrl) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); @@ -122,10 +130,13 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) avmcard *card; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "b1isa: no memory.\n"); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -133,6 +144,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) if (!cinfo) { printk(KERN_WARNING "b1isa: no memory.\n"); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -149,12 +161,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } if (b1_irq_table[card->irq & 0xf] == 0) { printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } if ( card->port != 0x150 && card->port != 0x250 @@ -162,6 +176,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } b1_reset(card->port); @@ -170,9 +185,11 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } b1_reset(card->port); + b1_getrevision(card); request_region(p->port, AVMB1_PORTLEN, card->name); @@ -182,6 +199,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -192,10 +210,14 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - MOD_INC_USE_COUNT; + printk(KERN_INFO + "%s: AVM B1 ISA at i/o %#x, irq %d, revision %d\n", + driver->name, card->port, card->irq, card->revision); + return 0; } @@ -205,11 +227,12 @@ static char *b1isa_procinfo(struct capi_ctr *ctrl) if (!cinfo) return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d", + sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", 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->irq : 0, + cinfo->card ? cinfo->card->revision : 0 ); return cinfo->infobuf; } diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c index f4e87b12fd02..f7affea0d8ec 100644 --- a/drivers/isdn/avmb1/b1pci.c +++ b/drivers/isdn/avmb1/b1pci.c @@ -1,11 +1,20 @@ /* - * $Id: b1pci.c,v 1.18 1999/11/05 16:38:01 calle Exp $ + * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.20 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.19 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.18 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -66,7 +75,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.18 $"; +static char *revision = "$Revision: 1.20 $"; /* ------------------------------------------------------------- */ @@ -138,11 +147,12 @@ static char *b1pci_procinfo(struct capi_ctr *ctrl) if (!cinfo) return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d", + sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", 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->irq : 0, + cinfo->card ? cinfo->card->revision : 0 ); return cinfo->infobuf; } @@ -155,10 +165,13 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) avmctrl_info *cinfo; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -166,6 +179,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -182,6 +196,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } b1_reset(card->port); @@ -190,9 +205,11 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } b1_reset(card->port); + b1_getrevision(card); request_region(p->port, AVMB1_PORTLEN, card->name); @@ -203,6 +220,7 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -214,10 +232,19 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - MOD_INC_USE_COUNT; + if (card->revision >= 4) { + printk(KERN_INFO + "%s: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n", + driver->name, card->port, card->irq, card->revision); + } else { + printk(KERN_INFO + "%s: AVM B1 PCI at i/o %#x, irq %d, revision %d\n", + driver->name, card->port, card->irq, card->revision); + } return 0; } @@ -241,6 +268,187 @@ static struct capi_driver b1pci_driver = { 0, /* no add_card function */ }; +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface *div4; + +/* ------------------------------------------------------------- */ + +static void b1pciv4_remove_ctr(struct capi_ctr *ctrl) +{ + avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); + avmcard *card = cinfo->card; + + b1dma_reset(card); + + div4->detach_ctr(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; +} + +static char *b1pciv4_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 r%d", + 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, + cinfo->card ? cinfo->card->revision : 0 + ); + return cinfo->infobuf; +} + +/* ------------------------------------------------------------- */ + +static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p) +{ + unsigned long base, page_offset; + avmcard *card; + avmctrl_info *cinfo; + int retval; + + 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), GFP_ATOMIC); + if (!cinfo) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + kfree(card->dma); + kfree(card); + return -ENOMEM; + } + memset(cinfo, 0, sizeof(avmctrl_info)); + card->ctrlinfo = cinfo; + cinfo->card = card; + sprintf(card->name, "b1pciv4-%x", p->port); + card->port = p->port; + card->irq = p->irq; + card->membase = p->membase; + card->cardtype = avm_b1pci; + + 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 (card->mbase) { + card->mbase += page_offset; + } else { + printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", + driver->name, card->membase); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EIO; + } + + b1dma_reset(card); + + if ((retval = b1pciv4_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; + } + b1dma_reset(card); + b1_getrevision(card); + + request_region(p->port, AVMB1_PORTLEN, card->name); + + retval = request_irq(card->irq, b1dma_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; + } + + cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo); + if (!cinfo->capi_ctrl) { + printk(KERN_ERR "%s: attach controller failed.\n", driver->name); + iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK)); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + return -EBUSY; + } + card->cardnr = cinfo->capi_ctrl->cnr; + + skb_queue_head_init(&card->dma->send_queue); + + printk(KERN_INFO + "%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n", + driver->name, card->port, card->irq, + card->membase, card->revision); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* ------------------------------------------------------------- */ + + +static struct capi_driver b1pciv4_driver = { + "b1pciv4", + "0.0", + b1dma_load_firmware, + b1dma_reset_ctr, + b1pciv4_remove_ctr, + b1dma_register_appl, + b1dma_release_appl, + b1dma_send_message, + + b1pciv4_procinfo, + b1dmactl_read_proc, + 0, /* use standard driver_read_proc */ + + 0, /* no add_card function */ +}; + +#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */ + #ifdef MODULE #define b1pci_init init_module void cleanup_module(void); @@ -248,9 +456,55 @@ void cleanup_module(void); static int ncards = 0; +static int add_card(struct pci_dev *dev) +{ + struct capi_driver *driver = &b1pci_driver; + struct capicardparams param; + int retval; + + if (dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK) { /* B1 PCI V4 */ +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + driver = &b1pciv4_driver; +#endif + param.membase = dev->resource[ 0].start & PCI_BASE_ADDRESS_MEM_MASK; + param.port = dev->resource[ 2].start & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; + printk(KERN_INFO + "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", + driver->name, param.port, param.irq, param.membase); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + retval = b1pciv4_add_card(driver, ¶m); +#else + retval = b1pci_add_card(driver, ¶m); +#endif + if (retval != 0) { + printk(KERN_ERR + "%s: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n", + driver->name, param.port, param.irq, param.membase); + } + } else { + param.membase = 0; + param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; + printk(KERN_INFO + "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", + driver->name, param.port, param.irq); + retval = b1pci_add_card(driver, ¶m); + if (retval != 0) { + printk(KERN_ERR + "%s: no AVM-B1 at i/o %#x, irq %d detected\n", + driver->name, param.port, param.irq); + } + } + return retval; +} + int b1pci_init(void) { struct capi_driver *driver = &b1pci_driver; +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + struct capi_driver *driverv4 = &b1pciv4_driver; +#endif struct pci_dev *dev = NULL; char *p; int retval; @@ -271,26 +525,32 @@ int b1pci_init(void) return -EIO; } +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision); + + div4 = attach_capi_driver(driverv4); + + if (!div4) { + detach_capi_driver(driver); + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driverv4->name); + return -EIO; + } +#endif + #ifdef CONFIG_PCI if (!pci_present()) { printk(KERN_ERR "%s: no PCI bus present\n", driver->name); detach_capi_driver(driver); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + detach_capi_driver(driverv4); +#endif return -EIO; } while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) { - struct capicardparams param; - - param.port = dev->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; - param.irq = dev->irq; - printk(KERN_INFO - "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", - driver->name, param.port, param.irq); - retval = b1pci_add_card(driver, ¶m); + retval = add_card(dev); if (retval != 0) { - printk(KERN_ERR - "%s: no AVM-B1 at i/o %#x, irq %d detected\n", - driver->name, param.port, param.irq); #ifdef MODULE cleanup_module(); #endif @@ -315,5 +575,8 @@ int b1pci_init(void) void cleanup_module(void) { detach_capi_driver(&b1pci_driver); +#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 + detach_capi_driver(&b1pciv4_driver); +#endif } #endif diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c index 79e34316481a..6e39c43d2b68 100644 --- a/drivers/isdn/avmb1/b1pcmcia.c +++ b/drivers/isdn/avmb1/b1pcmcia.c @@ -1,11 +1,19 @@ /* - * $Id: b1pcmcia.c,v 1.5 1999/11/05 16:38:01 calle Exp $ + * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.7 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.6 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * * Revision 1.5 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -62,7 +70,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.5 $"; +static char *revision = "$Revision: 1.7 $"; /* ------------------------------------------------------------- */ @@ -126,12 +134,16 @@ static int b1pcmcia_add_card(struct capi_driver *driver, { avmctrl_info *cinfo; avmcard *card; + char *cardname; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -139,6 +151,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver, if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -159,9 +172,11 @@ static int b1pcmcia_add_card(struct capi_driver *driver, driver->name, card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } b1_reset(card->port); + b1_getrevision(card); retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card); if (retval) { @@ -169,6 +184,7 @@ static int b1pcmcia_add_card(struct capi_driver *driver, driver->name, card->irq); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -179,10 +195,19 @@ static int b1pcmcia_add_card(struct capi_driver *driver, free_irq(card->irq, card); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } + switch (cardtype) { + case avm_m1: cardname = "M1"; break; + case avm_m2: cardname = "M2"; break; + default : cardname = "B1 PCMCIA"; break; + } + + printk(KERN_INFO + "%s: AVM %s at i/o %#x, irq %d, revision %d\n", + driver->name, cardname, card->port, card->irq, card->revision); - MOD_INC_USE_COUNT; return cinfo->capi_ctrl->cnr; } @@ -194,11 +219,12 @@ static char *b1pcmcia_procinfo(struct capi_ctr *ctrl) if (!cinfo) return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d", + sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", 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->irq : 0, + cinfo->card ? cinfo->card->revision : 0 ); return cinfo->infobuf; } diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c new file mode 100644 index 000000000000..7483370cf269 --- /dev/null +++ b/drivers/isdn/avmb1/c4.c @@ -0,0 +1,1326 @@ +/* + * $Id: c4.c,v 1.4 2000/02/02 18:36:03 calle Exp $ + * + * Module for AVM C4 card. + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: c4.c,v $ + * Revision 1.4 2000/02/02 18:36:03 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.3 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * + * 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.4 $"; + +#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 base, page_offset; + avmctrl_info *cinfo; + avmcard *card; + int retval; + int i; + + MOD_INC_USE_COUNT; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; + 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); + MOD_DEC_USE_COUNT; + 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); + MOD_DEC_USE_COUNT; + 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); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + base = card->membase & PAGE_MASK; + page_offset = card->membase - base; + card->mbase = ioremap_nocache(base, page_offset + 128); + if (card->mbase) { + card->mbase += page_offset; + } else { + printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", + driver->name, card->membase); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -EIO; + } + + 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); + MOD_DEC_USE_COUNT; + 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); + MOD_DEC_USE_COUNT; + 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); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + if (i == 0) + card->cardnr = cinfo->capi_ctrl->cnr; + } + + skb_queue_head_init(&card->dma->send_queue); + + printk(KERN_INFO + "%s: AVM C4 at i/o %#x, irq %d, mem %#lx\n", + driver->name, card->port, card->irq, card->membase); + + 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 + + +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->resource[ 1].start & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; + param.membase = dev->resource[ 0].start & 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/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index 6214a7c75bb6..c214b0b28dab 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -511,13 +511,18 @@ capi_release(struct inode *inode, struct file *file) static struct file_operations capi_fops = { - llseek: capi_llseek, - read: capi_read, - write: capi_write, - poll: capi_poll, - ioctl: capi_ioctl, - open: capi_open, - release: capi_release, + capi_llseek, + capi_read, + capi_write, + NULL, /* capi_readdir */ + capi_poll, + capi_ioctl, + NULL, /* capi_mmap */ + capi_open, + NULL, /* capi_flush */ + capi_release, + NULL, /* capi_fsync */ + NULL, /* capi_fasync */ }; /* -------- /proc functions ----------------------------------- */ diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c index 6db170e42486..79bb370d12fa 100644 --- a/drivers/isdn/avmb1/capidrv.c +++ b/drivers/isdn/avmb1/capidrv.c @@ -1,11 +1,14 @@ /* - * $Id: capidrv.c,v 1.28 1999/11/05 16:22:37 calle Exp $ + * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.29 1999/12/06 17:13:06 calle + * Added controller watchdog. + * * Revision 1.28 1999/11/05 16:22:37 calle * Bugfix: Missing break in switch on ISDN_CMD_HANGUP. * @@ -168,7 +171,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.28 $"; +static char *revision = "$Revision: 1.29 $"; int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); @@ -196,6 +199,7 @@ struct capidrv_contr { int state; __u32 cipmask; __u32 cipmask2; + struct timer_list listentimer; /* * ID of capi message sent @@ -2188,6 +2192,29 @@ static void disable_dchannel_trace(capidrv_contr *card) send_message(card, &cmdcmsg); } +static void send_listen(capidrv_contr *card) +{ + capi_fill_LISTEN_REQ(&cmdcmsg, global.appid, + card->msgid++, + card->contrnr, /* controller */ + 1 << 6, /* Infomask */ + card->cipmask, + card->cipmask2, + 0, 0); + send_message(card, &cmdcmsg); + listen_change_state(card, EV_LISTEN_REQ); +} + +static void listentimerfunc(unsigned long x) +{ + capidrv_contr *card = (capidrv_contr *)x; + if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE) + printk(KERN_ERR "%s: controller dead ??\n", card->name); + send_listen(card); + mod_timer(&card->listentimer, jiffies + 60*HZ); +} + + static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) { capidrv_contr *card; @@ -2202,6 +2229,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) return -1; } memset(card, 0, sizeof(capidrv_contr)); + init_timer(&card->listentimer); strcpy(card->name, id); card->contrnr = contr; card->nbchan = profp->nbchannel; @@ -2258,15 +2286,11 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) card->cipmask = 0x1FFF03FF; /* any */ card->cipmask2 = 0; - capi_fill_LISTEN_REQ(&cmdcmsg, global.appid, - card->msgid++, - contr, /* controller */ - 1 << 6, /* Infomask */ - card->cipmask, - card->cipmask2, - 0, 0); - send_message(card, &cmdcmsg); - listen_change_state(card, EV_LISTEN_REQ); + send_listen(card); + + card->listentimer.data = (unsigned long)card; + card->listentimer.function = listentimerfunc; + mod_timer(&card->listentimer, jiffies + 60*HZ); printk(KERN_INFO "%s: now up (%d B channels)\n", card->name, card->nbchan); @@ -2312,6 +2336,7 @@ static int capidrv_delcontr(__u16 contr) printk(KERN_ERR "capidrv: bug in free_plci()\n"); } kfree(card->bchans); + del_timer(&card->listentimer); printk(KERN_INFO "%s: now down.\n", card->name); diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c index 84fb0d2f7b65..d82fbc496b55 100644 --- a/drivers/isdn/avmb1/kcapi.c +++ b/drivers/isdn/avmb1/kcapi.c @@ -1,11 +1,18 @@ /* - * $Id: kcapi.c,v 1.10 1999/10/26 15:30:32 calle Exp $ + * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $ * * Kernel CAPI 2.0 Module * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kcapi.c,v $ + * Revision 1.12 2000/01/28 16:45:39 calle + * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), + * will search named driver and call the add_card function if one exist. + * + * Revision 1.11 1999/11/23 13:29:29 calle + * Bugfix: incoming capi message were never traced. + * * Revision 1.10 1999/10/26 15:30:32 calle * Generate error message if user want to add card, but driver module is * not loaded. @@ -79,7 +86,7 @@ #include #endif -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.12 $"; /* ------------------------------------------------------------- */ @@ -154,10 +161,6 @@ static int ncards = 0; static struct sk_buff_head recv_queue; static struct capi_interface_user *capi_users = 0; static struct capi_driver *drivers; -#ifdef CONFIG_AVMB1_COMPAT -static struct capi_driver *b1isa_driver; -static struct capi_driver *t1isa_driver; -#endif static long notify_up_set = 0; static long notify_down_set = 0; @@ -703,9 +706,9 @@ static void controllercb_handle_capimsg(struct capi_ctr * card, if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) { card->nrecvdatapkt++; if (card->traceflag > 2) showctl |= 2; - if (card->traceflag) showctl |= 2; } else { card->nrecvctlpkt++; + if (card->traceflag) showctl |= 2; } showctl |= (card->traceflag & 1); if (showctl & 2) { @@ -877,8 +880,14 @@ drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata) *pp = card; driver->ncontroller++; sprintf(card->procfn, "capi/controllers/%d", card->cnr); - card->procent = create_proc_read_entry(card->procfn, 0, 0, - driver->ctr_read_proc, card); + card->procent = create_proc_entry(card->procfn, 0, 0); + if (card->procent) { + card->procent->read_proc = + (int (*)(char *,char **,off_t,int,int *,void *)) + driver->ctr_read_proc; + card->procent->data = card; + } + ncards++; printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n", card->cnr, card->name); @@ -947,18 +956,18 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver) driver->next = 0; *pp = driver; printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name); -#ifdef CONFIG_AVMB1_COMPAT - if (strcmp(driver->name, "b1isa") == 0 && driver->add_card) - b1isa_driver = driver; - if (strcmp(driver->name, "t1isa") == 0 && driver->add_card) - t1isa_driver = driver; -#endif sprintf(driver->procfn, "capi/drivers/%s", driver->name); - driver->procent = create_proc_read_entry(driver->procfn, 0, 0, - driver->driver_read_proc - ? driver->driver_read_proc - : driver_read_proc, - driver); + driver->procent = create_proc_entry(driver->procfn, 0, 0); + if (driver->procent) { + if (driver->driver_read_proc) { + driver->procent->read_proc = + (int (*)(char *,char **,off_t,int,int *,void *)) + driver->driver_read_proc; + } else { + driver->procent->read_proc = driver_read_proc; + } + driver->procent->data = driver; + } return &di; } @@ -968,10 +977,6 @@ void detach_capi_driver(struct capi_driver *driver) for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ; if (*pp) { *pp = (*pp)->next; -#ifdef CONFIG_AVMB1_COMPAT - if (driver == b1isa_driver) b1isa_driver = 0; - if (driver == t1isa_driver) t1isa_driver = 0; -#endif printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name); } else { printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name); @@ -1186,6 +1191,15 @@ static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp) return CAPI_NOERROR; } +static struct capi_driver *find_driver(char *name) +{ + struct capi_driver *dp; + for (dp = drivers; dp; dp = dp->next) + if (strcmp(dp->name, name) == 0) + return dp; + return 0; +} + #ifdef CONFIG_AVMB1_COMPAT static int old_capi_manufacturer(unsigned int cmd, void *data) { @@ -1217,9 +1231,15 @@ static int old_capi_manufacturer(unsigned int cmd, void *data) cparams.cardnr = cdef.cardnr; switch (cdef.cardtype) { - case AVM_CARDTYPE_B1: driver = b1isa_driver; break; - case AVM_CARDTYPE_T1: driver = t1isa_driver; break; - default: driver = 0; + case AVM_CARDTYPE_B1: + driver = find_driver("b1isa"); + break; + case AVM_CARDTYPE_T1: + driver = find_driver("t1isa"); + break; + default: + driver = 0; + break; } if (!driver) { printk(KERN_ERR "kcapi: driver not loaded.\n"); @@ -1331,9 +1351,7 @@ static int old_capi_manufacturer(unsigned int cmd, void *data) return -ESRCH; gdef.cardstate = card->cardstate; - if (card->driver == b1isa_driver) - gdef.cardtype = AVM_CARDTYPE_B1; - else if (card->driver == t1isa_driver) + if (card->driver == find_driver("t1isa")) gdef.cardtype = AVM_CARDTYPE_T1; else gdef.cardtype = AVM_CARDTYPE_B1; @@ -1377,7 +1395,6 @@ static int old_capi_manufacturer(unsigned int cmd, void *data) static int capi_manufacturer(unsigned int cmd, void *data) { struct capi_ctr *card; - kcapi_flagdef fdef; int retval; switch (cmd) { @@ -1392,6 +1409,9 @@ static int capi_manufacturer(unsigned int cmd, void *data) return old_capi_manufacturer(cmd, data); #endif case KCAPI_CMD_TRACE: + { + kcapi_flagdef fdef; + if ((retval = copy_from_user((void *) &fdef, data, sizeof(kcapi_flagdef)))) return retval; @@ -1406,6 +1426,44 @@ static int capi_manufacturer(unsigned int cmd, void *data) card->cnr, card->traceflag); return 0; } + + case KCAPI_CMD_ADDCARD: + { + struct capi_driver *driver; + capicardparams cparams; + kcapi_carddef cdef; + + if ((retval = copy_from_user((void *) &cdef, data, + sizeof(cdef)))) + return retval; + + cparams.port = cdef.port; + cparams.irq = cdef.irq; + cparams.membase = cdef.membase; + cparams.cardnr = cdef.cardnr; + cparams.cardtype = 0; + cdef.driver[sizeof(cdef.driver)-1] = 0; + + if ((driver = find_driver(cdef.driver)) == 0) { + printk(KERN_ERR "kcapi: driver \"%s\" not loaded.\n", + cdef.driver); + return -ESRCH; + } + + if (!driver->add_card) { + printk(KERN_ERR "kcapi: driver \"%s\" has no add card function.\n", cdef.driver); + return -EIO; + } + + return driver->add_card(driver, &cparams); + } + + default: + printk(KERN_ERR "kcapi: manufacturer command %d unknown.\n", + cmd); + break; + + } return -EINVAL; } diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c index 22a07f2ade75..e1efd3939ffb 100644 --- a/drivers/isdn/avmb1/t1isa.c +++ b/drivers/isdn/avmb1/t1isa.c @@ -1,11 +1,19 @@ /* - * $Id: t1isa.c,v 1.8 1999/11/05 16:38:01 calle Exp $ + * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.10 2000/02/02 18:36:04 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.9 2000/01/25 14:37:39 calle + * new message after successfull detection including card revision and + * used resources. + * * Revision 1.8 1999/11/05 16:38:01 calle * Cleanups before kernel 2.4: * - Changed all messages to use card->name or driver->name instead of @@ -73,7 +81,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.8 $"; +static char *revision = "$Revision: 1.10 $"; /* ------------------------------------------------------------- */ @@ -413,10 +421,13 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) avmcard *card; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -424,6 +435,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) if (!cinfo) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -440,6 +452,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } @@ -449,6 +462,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, card->port + AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } if (hema_irq_table[card->irq & 0xf] == 0) { @@ -456,6 +470,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->irq); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EINVAL; } for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) { @@ -465,6 +480,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->cardnr, cardp->port); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } } @@ -473,6 +489,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) driver->name, card->port, retval); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } t1_disable_irq(card->port); @@ -487,6 +504,7 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -498,10 +516,14 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) release_region(card->port, AVMB1_PORTLEN); kfree(card->ctrlinfo); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - MOD_INC_USE_COUNT; + printk(KERN_INFO + "%s: AVM T1 ISA at i/o %#x, irq %d, card %d\n", + driver->name, card->port, card->irq, card->cardnr); + return 0; } diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c index d77340bffa20..d24894d9b843 100644 --- a/drivers/isdn/avmb1/t1pci.c +++ b/drivers/isdn/avmb1/t1pci.c @@ -1,11 +1,20 @@ /* - * $Id: t1pci.c,v 1.3 1999/11/13 21:27:16 keil Exp $ + * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.5 2000/02/02 18:36:04 calle + * - Modules are now locked while init_module is running + * - fixed problem with memory mapping if address is not aligned + * + * Revision 1.4 2000/01/25 14:33:38 calle + * - Added Support AVM B1 PCI V4.0 (tested with prototype) + * - splitted up t1pci.c into b1dma.c for common function with b1pciv4 + * - support for revision register + * * Revision 1.3 1999/11/13 21:27:16 keil * remove KERNELVERSION * @@ -38,7 +47,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.5 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG @@ -55,712 +64,20 @@ static char *revision = "$Revision: 1.3 $"; /* ------------------------------------------------------------- */ -int suppress_pollack = 0; - MODULE_AUTHOR("Carsten Paeth "); -MODULE_PARM(suppress_pollack, "0-1i"); - - /* ------------------------------------------------------------- */ static struct capi_driver_interface *di; /* ------------------------------------------------------------- */ -static void t1pci_dispatch_tx(avmcard *card); - -/* ------------------------------------------------------------- */ - -/* S5933 */ - -#define AMCC_RXPTR 0x24 -#define AMCC_RXLEN 0x28 -#define AMCC_TXPTR 0x2c -#define AMCC_TXLEN 0x30 - -#define AMCC_INTCSR 0x38 -# define EN_READ_TC_INT 0x00008000L -# define EN_WRITE_TC_INT 0x00004000L -# define EN_TX_TC_INT EN_READ_TC_INT -# define EN_RX_TC_INT EN_WRITE_TC_INT -# define AVM_FLAG 0x30000000L - -# define ANY_S5933_INT 0x00800000L -# define READ_TC_INT 0x00080000L -# define WRITE_TC_INT 0x00040000L -# define TX_TC_INT READ_TC_INT -# define RX_TC_INT WRITE_TC_INT -# define MASTER_ABORT_INT 0x00100000L -# define TARGET_ABORT_INT 0x00200000L -# define BUS_MASTER_INT 0x00200000L -# define ALL_INT 0x000C0000L - -#define AMCC_MCSR 0x3c -# define A2P_HI_PRIORITY 0x00000100L -# define EN_A2P_TRANSFERS 0x00000400L -# define P2A_HI_PRIORITY 0x00001000L -# define EN_P2A_TRANSFERS 0x00004000L -# define RESET_A2P_FLAGS 0x04000000L -# define RESET_P2A_FLAGS 0x02000000L - -/* ------------------------------------------------------------- */ - -#define t1outmeml(addr, value) writel(value, addr) -#define t1inmeml(addr) readl(addr) -#define t1outmemw(addr, value) writew(value, addr) -#define t1inmemw(addr) readw(addr) -#define t1outmemb(addr, value) writeb(value, addr) -#define t1inmemb(addr) readb(addr) - -/* ------------------------------------------------------------- */ - -static inline int t1pci_tx_empty(unsigned int port) -{ - return inb(port + 0x03) & 0x1; -} - -static inline int t1pci_rx_full(unsigned int port) -{ - return inb(port + 0x02) & 0x1; -} - -static int t1pci_tolink(avmcard *card, void *buf, unsigned int len) -{ - unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ - unsigned char *s = (unsigned char *)buf; - while (len--) { - while ( !t1pci_tx_empty(card->port) - && time_before(jiffies, stop)); - if (!t1pci_tx_empty(card->port)) - return -1; - t1outp(card->port, 0x01, *s++); - } - return 0; -} - -static int t1pci_fromlink(avmcard *card, void *buf, unsigned int len) -{ - unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ - unsigned char *s = (unsigned char *)buf; - while (len--) { - while ( !t1pci_rx_full(card->port) - && time_before(jiffies, stop)); - if (!t1pci_rx_full(card->port)) - return -1; - *s++ = t1inp(card->port, 0x00); - } - return 0; -} - -static int WriteReg(avmcard *card, __u32 reg, __u8 val) -{ - __u8 cmd = 0x00; - if ( t1pci_tolink(card, &cmd, 1) == 0 - && t1pci_tolink(card, ®, 4) == 0) { - __u32 tmp = val; - return t1pci_tolink(card, &tmp, 4); - } - return -1; -} - -static __u8 ReadReg(avmcard *card, __u32 reg) -{ - __u8 cmd = 0x01; - if ( t1pci_tolink(card, &cmd, 1) == 0 - && t1pci_tolink(card, ®, 4) == 0) { - __u32 tmp; - if (t1pci_fromlink(card, &tmp, 4) == 0) - return (__u8)tmp; - } - return 0xff; -} - -/* ------------------------------------------------------------- */ - -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 t1pci_reset(avmcard *card) -{ - unsigned long flags; - - save_flags(flags); - cli(); - card->csr = 0x0; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - t1outmeml(card->mbase+AMCC_MCSR, 0); - t1outmeml(card->mbase+AMCC_RXLEN, 0); - t1outmeml(card->mbase+AMCC_TXLEN, 0); - - t1outp(card->port, T1_RESETLINK, 0x00); - t1outp(card->port, 0x07, 0x00); - - restore_flags(flags); - - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(42 * 1000); - -} - -/* ------------------------------------------------------------- */ - -static int t1pci_detect(avmcard *card) -{ - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ - udelay(10 * 1000); - t1outmeml(card->mbase+AMCC_MCSR, 0); - udelay(42 * 1000); - - t1outmeml(card->mbase+AMCC_RXLEN, 0); - t1outmeml(card->mbase+AMCC_TXLEN, 0); - card->csr = 0x0; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - - if (t1inmeml(card->mbase+AMCC_MCSR) != 0x000000E6) - return 1; - - t1outmeml(card->mbase+AMCC_RXPTR, 0xffffffff); - t1outmeml(card->mbase+AMCC_TXPTR, 0xffffffff); - if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc - || t1inmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc) - return 2; - - t1outmeml(card->mbase+AMCC_RXPTR, 0x0); - t1outmeml(card->mbase+AMCC_TXPTR, 0x0); - if ( t1inmeml(card->mbase+AMCC_RXPTR) != 0x0 - || t1inmeml(card->mbase+AMCC_TXPTR) != 0x0) - return 3; - - t1outp(card->port, T1_RESETLINK, 0x00); - t1outp(card->port, 0x07, 0x00); - - t1outp(card->port, 0x02, 0x02); - t1outp(card->port, 0x03, 0x02); - - if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02 - || t1inp(card->port, 0x3) != 0x03) - return 4; - - t1outp(card->port, 0x02, 0x00); - t1outp(card->port, 0x03, 0x00); - - if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00 - || t1inp(card->port, 0x3) != 0x01) - return 5; - - /* Transputer test */ - - if ( WriteReg(card, 0x80001000, 0x11) != 0 - || WriteReg(card, 0x80101000, 0x22) != 0 - || WriteReg(card, 0x80201000, 0x33) != 0 - || WriteReg(card, 0x80301000, 0x44) != 0) - return 6; - - if ( ReadReg(card, 0x80001000) != 0x11 - || ReadReg(card, 0x80101000) != 0x22 - || ReadReg(card, 0x80201000) != 0x33 - || ReadReg(card, 0x80301000) != 0x44) - return 7; - - if ( WriteReg(card, 0x80001000, 0x55) != 0 - || WriteReg(card, 0x80101000, 0x66) != 0 - || WriteReg(card, 0x80201000, 0x77) != 0 - || WriteReg(card, 0x80301000, 0x88) != 0) - return 8; - - if ( ReadReg(card, 0x80001000) != 0x55 - || ReadReg(card, 0x80101000) != 0x66 - || ReadReg(card, 0x80201000) != 0x77 - || ReadReg(card, 0x80301000) != 0x88) - return 9; - - return 0; -} - -/* ------------------------------------------------------------- */ - -static void t1pci_dispatch_tx(avmcard *card) -{ - avmcard_dmainfo *dma = card->dma; - unsigned long flags; - struct sk_buff *skb; - __u8 cmd, subcmd; - __u16 len; - __u32 txlen; - int inint; - void *p; - - save_flags(flags); - cli(); - - inint = card->interrupt; - - if (card->csr & EN_TX_TC_INT) { /* tx busy */ - restore_flags(flags); - return; - } - - skb = skb_dequeue(&dma->send_queue); - if (!skb) { -#ifdef CONFIG_T1PCI_DEBUG - printk(KERN_DEBUG "tx(%d): underrun\n", inint); -#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_T1PCI_DEBUG - printk(KERN_DEBUG "tx(%d): put msg len=%d\n", - inint, txlen); -#endif - } else { - txlen = skb->len-2; -#ifdef CONFIG_T1PCI_POLLDEBUG - if (skb->data[2] == SEND_POLLACK) - printk(KERN_INFO "%s: ack to t1\n", card->name); -#endif -#ifdef CONFIG_T1PCI_DEBUG - printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n", - inint, skb->data[2], txlen); -#endif - memcpy(dma->sendbuf, skb->data+2, skb->len-2); - } - txlen = (txlen + 3) & ~3; - - t1outmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf)); - t1outmeml(card->mbase+AMCC_TXLEN, txlen); - - card->csr |= EN_TX_TC_INT; - - if (!inint) - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - - 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); - t1pci_dispatch_tx(card); -} - -/* ------------------------------------------------------------- */ - -static void t1pci_handle_rx(avmcard *card) -{ - avmctrl_info *cinfo = &card->ctrlinfo[0]; - avmcard_dmainfo *dma = card->dma; - struct capi_ctr *ctrl = cinfo->capi_ctrl; - struct sk_buff *skb; - void *p = dma->recvbuf+4; - __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; - __u8 b1cmd = _get_byte(&p); - -#ifdef CONFIG_T1PCI_DEBUG - printk(KERN_DEBUG "rx: 0x%x %lu\n", 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); - - 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); - 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); - - ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); - - break; - - case RECEIVE_FREE_NCCI: - - ApplId = _get_word(&p); - NCCI = _get_word(&p); - - if (NCCI != 0xffffffff) - ctrl->free_ncci(ctrl, ApplId, NCCI); - else ctrl->appl_released(ctrl, ApplId); - break; - - case RECEIVE_START: -#ifdef CONFIG_T1PCI_POLLDEBUG - printk(KERN_INFO "%s: poll from t1\n", card->name); -#endif - if (!suppress_pollack) - queue_pollack(card); - ctrl->resume_output(ctrl); - break; - - case RECEIVE_STOP: - ctrl->suspend_output(ctrl); - break; - - case RECEIVE_INIT: - - 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(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: t1pci_interrupt: 0x%x ???\n", - card->name, b1cmd); - return; - } -} - -/* ------------------------------------------------------------- */ - -static void t1pci_handle_interrupt(avmcard *card) -{ - __u32 status = t1inmeml(card->mbase+AMCC_INTCSR); - __u32 newcsr; - - if ((status & ANY_S5933_INT) == 0) - return; - - newcsr = card->csr | (status & ALL_INT); - if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; - if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; - t1outmeml(card->mbase+AMCC_INTCSR, newcsr); - - if ((status & RX_TC_INT) != 0) { - __u8 *recvbuf = card->dma->recvbuf; - __u32 rxlen; - if (card->dma->recvlen == 0) { - card->dma->recvlen = *((__u32 *)recvbuf); - rxlen = (card->dma->recvlen + 3) & ~3; - t1outmeml(card->mbase+AMCC_RXPTR, - virt_to_phys(recvbuf+4)); - t1outmeml(card->mbase+AMCC_RXLEN, rxlen); - } else { - t1pci_handle_rx(card); - card->dma->recvlen = 0; - t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf)); - t1outmeml(card->mbase+AMCC_RXLEN, 4); - } - } - - if ((status & TX_TC_INT) != 0) { - card->csr &= ~EN_TX_TC_INT; - t1pci_dispatch_tx(card); - } else if (card->csr & EN_TX_TC_INT) { - if (t1inmeml(card->mbase+AMCC_TXLEN) == 0) { - card->csr &= ~EN_TX_TC_INT; - t1pci_dispatch_tx(card); - } - } - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); -} - -static void t1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs) -{ - avmcard *card; - - card = (avmcard *) devptr; - - if (!card) { - printk(KERN_WARNING "t1pci: interrupt: wrong device\n"); - return; - } - if (card->interrupt) { - printk(KERN_ERR "%s: reentering interrupt hander\n", card->name); - return; - } - - card->interrupt = 1; - - t1pci_handle_interrupt(card); - - card->interrupt = 0; -} - -/* ------------------------------------------------------------- */ - -static int t1pci_loaded(avmcard *card) -{ - unsigned long stop; - unsigned char ans; - unsigned long tout = 2; - unsigned int base = card->port; - - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_tx_empty(base)) - break; - } - if (!b1_tx_empty(base)) { - printk(KERN_ERR "%s: t1pci_loaded: tx err, corrupted t4 file ?\n", - card->name); - return 0; - } - b1_put_byte(base, SEND_POLLACK); - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_rx_full(base)) { - if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) { - return 1; - } - printk(KERN_ERR "%s: t1pci_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans); - return 0; - } - } - printk(KERN_ERR "%s: t1pci_loaded: firmware not running\n", card->name); - return 0; -} - -/* ------------------------------------------------------------- */ - -static void t1pci_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); - t1pci_dispatch_tx(card); -} - -static int t1pci_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned long flags; - int retval; - - t1pci_reset(card); - - if ((retval = b1_load_t4file(card, &data->firmware))) { - t1pci_reset(card); - printk(KERN_ERR "%s: failed to load t4file!!\n", - card->name); - return retval; - } - - if (data->configuration.len > 0 && data->configuration.data) { - if ((retval = b1_load_config(card, &data->configuration))) { - t1pci_reset(card); - printk(KERN_ERR "%s: failed to load config!!\n", - card->name); - return retval; - } - } - - if (!t1pci_loaded(card)) { - t1pci_reset(card); - printk(KERN_ERR "%s: failed to load t4file.\n", card->name); - return -EIO; - } - - save_flags(flags); - cli(); - - card->csr = AVM_FLAG; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - t1outmeml(card->mbase+AMCC_MCSR, - EN_A2P_TRANSFERS|EN_P2A_TRANSFERS - |A2P_HI_PRIORITY|P2A_HI_PRIORITY - |RESET_A2P_FLAGS|RESET_P2A_FLAGS); - t1outp(card->port, 0x07, 0x30); - t1outp(card->port, 0x10, 0xF0); - - card->dma->recvlen = 0; - t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf)); - t1outmeml(card->mbase+AMCC_RXLEN, 4); - card->csr |= EN_RX_TC_INT; - t1outmeml(card->mbase+AMCC_INTCSR, card->csr); - restore_flags(flags); - - t1pci_send_init(card); - - return 0; -} - -void t1pci_reset_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - - t1pci_reset(card); - - memset(cinfo->version, 0, sizeof(cinfo->version)); - ctrl->reseted(ctrl); -} - static void t1pci_remove_ctr(struct capi_ctr *ctrl) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; - t1pci_reset(card); + b1dma_reset(card); di->detach_ctr(ctrl); free_irq(card->irq, card); @@ -776,210 +93,20 @@ static void t1pci_remove_ctr(struct capi_ctr *ctrl) /* ------------------------------------------------------------- */ - -void t1pci_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 (want > 0) nconn = want; - else nconn = ctrl->profile.nbchannel * -want; - if (nconn == 0) nconn = ctrl->profile.nbchannel; - - 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); - t1pci_dispatch_tx(card); - - ctrl->appl_registered(ctrl, appl); -} - -/* ------------------------------------------------------------- */ - -void t1pci_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; - - 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); - t1pci_dispatch_tx(card); -} - -/* ------------------------------------------------------------- */ - - -static void t1pci_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); - t1pci_dispatch_tx(card); -} - -/* ------------------------------------------------------------- */ - -static char *t1pci_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 t1pci_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; - unsigned long flags; - __u8 flag; - int len = 0; - char *s; - __u32 txaddr, txlen, rxaddr, rxlen, csr; - - 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); - - save_flags(flags); - cli(); - - txaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x2c)); - txaddr -= (__u32)card->dma->sendbuf; - txlen = t1inmeml(card->mbase+0x30); - - rxaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x24)); - rxaddr -= (__u32)card->dma->recvbuf; - rxlen = t1inmeml(card->mbase+0x28); - - csr = t1inmeml(card->mbase+AMCC_INTCSR); - - restore_flags(flags); - - len += sprintf(page+len, "%-16s 0x%lx\n", - "csr (cached)", (unsigned long)card->csr); - len += sprintf(page+len, "%-16s 0x%lx\n", - "csr", (unsigned long)csr); - len += sprintf(page+len, "%-16s %lu\n", - "txoff", (unsigned long)txaddr); - len += sprintf(page+len, "%-16s %lu\n", - "txlen", (unsigned long)txlen); - len += sprintf(page+len, "%-16s %lu\n", - "rxoff", (unsigned long)rxaddr); - len += sprintf(page+len, "%-16s %lu\n", - "rxlen", (unsigned long)rxlen); - - if (off+count >= len) - *eof = 1; - if (len < off) - return 0; - *start = page + off; - return ((count < len-off) ? count : len-off); -} - -/* ------------------------------------------------------------- */ - static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) { - unsigned long page_offset, base; + unsigned long base, page_offset; avmcard *card; avmctrl_info *cinfo; int retval; + MOD_INC_USE_COUNT; + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); if (!card) { printk(KERN_WARNING "%s: no memory.\n", driver->name); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card, 0, sizeof(avmcard)); @@ -987,6 +114,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) if (!card->dma) { printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(card->dma, 0, sizeof(avmcard_dmainfo)); @@ -995,6 +123,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) printk(KERN_WARNING "%s: no memory.\n", driver->name); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -ENOMEM; } memset(cinfo, 0, sizeof(avmctrl_info)); @@ -1013,14 +142,26 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } - base = card->membase & PAGE_MASK; + base = card->membase & PAGE_MASK; page_offset = card->membase - base; card->mbase = ioremap_nocache(base, page_offset + 64); + if (card->mbase) { + card->mbase += page_offset; + } else { + printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n", + driver->name, card->membase); + kfree(card->ctrlinfo); + kfree(card->dma); + kfree(card); + MOD_DEC_USE_COUNT; + return -EIO; + } - t1pci_reset(card); + b1dma_reset(card); if ((retval = t1pci_detect(card)) != 0) { printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n", @@ -1029,13 +170,14 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EIO; } - t1pci_reset(card); + b1dma_reset(card); request_region(p->port, AVMB1_PORTLEN, card->name); - retval = request_irq(card->irq, t1pci_interrupt, SA_SHIRQ, card->name, card); + retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card); if (retval) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", driver->name, card->irq); @@ -1044,6 +186,7 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } @@ -1056,31 +199,52 @@ static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p) kfree(card->ctrlinfo); kfree(card->dma); kfree(card); + MOD_DEC_USE_COUNT; return -EBUSY; } card->cardnr = cinfo->capi_ctrl->cnr; skb_queue_head_init(&card->dma->send_queue); - MOD_INC_USE_COUNT; + printk(KERN_INFO + "%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n", + driver->name, card->port, card->irq, card->membase); return 0; } /* ------------------------------------------------------------- */ +static char *t1pci_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 struct capi_driver t1pci_driver = { "t1pci", "0.0", - t1pci_load_firmware, - t1pci_reset_ctr, + b1dma_load_firmware, + b1dma_reset_ctr, t1pci_remove_ctr, - t1pci_register_appl, - t1pci_release_appl, - t1pci_send_message, + b1dma_register_appl, + b1dma_release_appl, + b1dma_send_message, t1pci_procinfo, - t1pci_read_proc, + b1dmactl_read_proc, 0, /* use standard driver_read_proc */ 0, /* no add_card function */ diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 38b2944f7edc..110b5a172dd9 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -1,10 +1,10 @@ -/* - * $Id: divert_procfs.c,v 1.5 1999/09/14 20:31:01 werner Exp $ +/* + * $Id: divert_procfs.c,v 1.6 2000/02/14 19:23:03 werner Exp $ * * Filesystem handling for the diversion supplementary services. * * Copyright 1998 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) @@ -17,9 +17,13 @@ * * 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. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divert_procfs.c,v $ + * Revision 1.6 2000/02/14 19:23:03 werner + * + * Changed handling of proc filesystem tables to a more portable version + * * Revision 1.5 1999/09/14 20:31:01 werner * * Removed obsoleted functions for proc fs and synced with new ones. @@ -44,9 +48,9 @@ #include #include #ifdef CONFIG_PROC_FS - #include +#include #else - #include +#include #endif #include #include "isdn_divert.h" @@ -54,220 +58,239 @@ /*********************************/ /* Variables for interface queue */ /*********************************/ -ulong if_used = 0; /* number of interface users */ -static struct divert_info *divert_info_head = NULL; /* head of queue */ -static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */ +ulong if_used = 0; /* number of interface users */ +static struct divert_info *divert_info_head = NULL; /* head of queue */ +static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */ static wait_queue_head_t rd_queue; /*********************************/ /* put an info buffer into queue */ /*********************************/ -void put_info_buffer(char *cp) -{ struct divert_info *ib; - int flags; - - if (if_used <= 0) return; - if (!cp) return; - if (!*cp) return; - if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info)+strlen(cp), GFP_ATOMIC))) return; /* no memory */ - strcpy(ib->info_start,cp); /* set output string */ - ib->next = NULL; - save_flags(flags); - cli(); - ib->usage_cnt = if_used; - if (!divert_info_head) - divert_info_head = ib; /* new head */ - else - divert_info_tail->next = ib; /* follows existing messages */ - divert_info_tail = ib; /* new tail */ - restore_flags(flags); - - /* delete old entrys */ - while (divert_info_head->next) - { if ((divert_info_head->usage_cnt <= 0) && - (divert_info_head->next->usage_cnt <= 0)) - { ib = divert_info_head; - divert_info_head = divert_info_head->next; - kfree(ib); - } - else break; - } /* divert_info_head->next */ - wake_up_interruptible(&(rd_queue)); -} /* put_info_buffer */ +void +put_info_buffer(char *cp) +{ + struct divert_info *ib; + int flags; + + if (if_used <= 0) + return; + if (!cp) + return; + if (!*cp) + return; + if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC))) + return; /* no memory */ + strcpy(ib->info_start, cp); /* set output string */ + ib->next = NULL; + save_flags(flags); + cli(); + ib->usage_cnt = if_used; + if (!divert_info_head) + divert_info_head = ib; /* new head */ + else + divert_info_tail->next = ib; /* follows existing messages */ + divert_info_tail = ib; /* new tail */ + restore_flags(flags); + + /* delete old entrys */ + while (divert_info_head->next) { + if ((divert_info_head->usage_cnt <= 0) && + (divert_info_head->next->usage_cnt <= 0)) { + ib = divert_info_head; + divert_info_head = divert_info_head->next; + kfree(ib); + } else + break; + } /* divert_info_head->next */ + wake_up_interruptible(&(rd_queue)); +} /* put_info_buffer */ /**********************************/ /* deflection device read routine */ /**********************************/ -static ssize_t isdn_divert_read(struct file *file, char *buf, size_t count, loff_t *off) -{ struct divert_info *inf; - int len; - - if (!*((struct divert_info **)file->private_data)) - { if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - interruptible_sleep_on(&(rd_queue)); - } - if (!(inf = *((struct divert_info **)file->private_data))) return(0); - - inf->usage_cnt--; /* new usage count */ - (struct divert_info **)file->private_data = &inf->next; /* next structure */ - if ((len = strlen(inf->info_start)) <= count) - { if (copy_to_user(buf, inf->info_start, len)) - return -EFAULT; - file->f_pos += len; - return(len); - } - return(0); -} /* isdn_divert_read */ +static ssize_t +isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off) +{ + struct divert_info *inf; + int len; + + if (!*((struct divert_info **) file->private_data)) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&(rd_queue)); + } + if (!(inf = *((struct divert_info **) file->private_data))) + return (0); + + inf->usage_cnt--; /* new usage count */ + (struct divert_info **) file->private_data = &inf->next; /* next structure */ + if ((len = strlen(inf->info_start)) <= count) { + if (copy_to_user(buf, inf->info_start, len)) + return -EFAULT; + file->f_pos += len; + return (len); + } + return (0); +} /* isdn_divert_read */ /**********************************/ /* deflection device write routine */ /**********************************/ -static ssize_t isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t *off) +static ssize_t +isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t * off) { - return(-ENODEV); -} /* isdn_divert_write */ + return (-ENODEV); +} /* isdn_divert_write */ /***************************************/ /* select routines for various kernels */ /***************************************/ -static unsigned int isdn_divert_poll(struct file *file, poll_table * wait) -{ unsigned int mask = 0; +static unsigned int +isdn_divert_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = 0; - poll_wait(file, &(rd_queue), wait); - /* mask = POLLOUT | POLLWRNORM; */ - if (*((struct divert_info **)file->private_data)) - { mask |= POLLIN | POLLRDNORM; - } - return mask; -} /* isdn_divert_poll */ + poll_wait(file, &(rd_queue), wait); + /* mask = POLLOUT | POLLWRNORM; */ + if (*((struct divert_info **) file->private_data)) { + mask |= POLLIN | POLLRDNORM; + } + return mask; +} /* isdn_divert_poll */ /****************/ /* Open routine */ /****************/ -static int isdn_divert_open(struct inode *ino, struct file *filep) -{ int flags; - - MOD_INC_USE_COUNT; - save_flags(flags); - cli(); - if_used++; - if (divert_info_head) - (struct divert_info **)filep->private_data = &(divert_info_tail->next); - else - (struct divert_info **)filep->private_data = &divert_info_head; - restore_flags(flags); - /* start_divert(); */ - return(0); -} /* isdn_divert_open */ +static int +isdn_divert_open(struct inode *ino, struct file *filep) +{ + int flags; + + MOD_INC_USE_COUNT; + save_flags(flags); + cli(); + if_used++; + if (divert_info_head) + (struct divert_info **) filep->private_data = &(divert_info_tail->next); + else + (struct divert_info **) filep->private_data = &divert_info_head; + restore_flags(flags); + /* start_divert(); */ + return (0); +} /* isdn_divert_open */ /*******************/ /* close routine */ /*******************/ -static int isdn_divert_close(struct inode *ino, struct file *filep) -{ struct divert_info *inf; - int flags; - - save_flags(flags); - cli(); - if_used--; - inf = *((struct divert_info **)filep->private_data); - while (inf) - { inf->usage_cnt--; - inf = inf->next; - } - restore_flags(flags); - if (if_used <= 0) - while (divert_info_head) - { inf = divert_info_head; - divert_info_head = divert_info_head->next; - kfree(inf); - } - MOD_DEC_USE_COUNT; - return(0); -} /* isdn_divert_close */ +static int +isdn_divert_close(struct inode *ino, struct file *filep) +{ + struct divert_info *inf; + int flags; + + save_flags(flags); + cli(); + if_used--; + inf = *((struct divert_info **) filep->private_data); + while (inf) { + inf->usage_cnt--; + inf = inf->next; + } + restore_flags(flags); + if (if_used <= 0) + while (divert_info_head) { + inf = divert_info_head; + divert_info_head = divert_info_head->next; + kfree(inf); + } + MOD_DEC_USE_COUNT; + return (0); +} /* isdn_divert_close */ /*********/ /* IOCTL */ /*********/ -static int isdn_divert_ioctl(struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ divert_ioctl dioctl; - int i, flags; - divert_rule *rulep; - char *cp; - - if ((i = copy_from_user(&dioctl,(char *) arg, sizeof(dioctl)))) - return(i); - - switch (cmd) - { - case IIOCGETVER: - dioctl.drv_version = DIVERT_IIOC_VERSION ; /* set version */ - break; - - case IIOCGETDRV: - if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0) - return(-EINVAL); - break; - - case IIOCGETNAM: - cp = divert_if.drv_to_name(dioctl.getid.drvid); - if (!cp) return(-EINVAL); - if (!*cp) return(-EINVAL); - strcpy(dioctl.getid.drvnam,cp); - break; - - case IIOCGETRULE: - if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) - return(-EINVAL); - dioctl.getsetrule.rule = *rulep; /* copy data */ - break; - - case IIOCMODRULE: - if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) - return(-EINVAL); - save_flags(flags); - cli(); - *rulep = dioctl.getsetrule.rule; /* copy data */ - restore_flags(flags); - return(0); /* no copy required */ - break; - - case IIOCINSRULE: - return(insertrule(dioctl.getsetrule.ruleidx,&dioctl.getsetrule.rule)); - break; - - case IIOCDELRULE: - return(deleterule(dioctl.getsetrule.ruleidx)); - break; - - case IIOCDODFACT: - return(deflect_extern_action(dioctl.fwd_ctrl.subcmd, - dioctl.fwd_ctrl.callid, - dioctl.fwd_ctrl.to_nr)); - - case IIOCDOCFACT: - case IIOCDOCFDIS: - case IIOCDOCFINT: - if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid)) - return(-EINVAL); /* invalid driver */ - if ((i = cf_command(dioctl.cf_ctrl.drvid, - (cmd == IIOCDOCFACT) ? 1: (cmd == IIOCDOCFDIS) ? 0:2, - dioctl.cf_ctrl.cfproc, - dioctl.cf_ctrl.msn, - dioctl.cf_ctrl.service, - dioctl.cf_ctrl.fwd_nr, - &dioctl.cf_ctrl.procid))) - return(i); - break; - - default: - return(-EINVAL); - } /* switch cmd */ - return(copy_to_user((char *) arg, &dioctl, sizeof(dioctl))); /* success */ -} /* isdn_divert_ioctl */ +static int +isdn_divert_ioctl(struct inode *inode, struct file *file, + uint cmd, ulong arg) +{ + divert_ioctl dioctl; + int i, flags; + divert_rule *rulep; + char *cp; + + if ((i = copy_from_user(&dioctl, (char *) arg, sizeof(dioctl)))) + return (i); + + switch (cmd) { + case IIOCGETVER: + dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */ + break; + + case IIOCGETDRV: + if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0) + return (-EINVAL); + break; + + case IIOCGETNAM: + cp = divert_if.drv_to_name(dioctl.getid.drvid); + if (!cp) + return (-EINVAL); + if (!*cp) + return (-EINVAL); + strcpy(dioctl.getid.drvnam, cp); + break; + + case IIOCGETRULE: + if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) + return (-EINVAL); + dioctl.getsetrule.rule = *rulep; /* copy data */ + break; + + case IIOCMODRULE: + if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) + return (-EINVAL); + save_flags(flags); + cli(); + *rulep = dioctl.getsetrule.rule; /* copy data */ + restore_flags(flags); + return (0); /* no copy required */ + break; + + case IIOCINSRULE: + return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule)); + break; + + case IIOCDELRULE: + return (deleterule(dioctl.getsetrule.ruleidx)); + break; + + case IIOCDODFACT: + return (deflect_extern_action(dioctl.fwd_ctrl.subcmd, + dioctl.fwd_ctrl.callid, + dioctl.fwd_ctrl.to_nr)); + + case IIOCDOCFACT: + case IIOCDOCFDIS: + case IIOCDOCFINT: + if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid)) + return (-EINVAL); /* invalid driver */ + if ((i = cf_command(dioctl.cf_ctrl.drvid, + (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2, + dioctl.cf_ctrl.cfproc, + dioctl.cf_ctrl.msn, + dioctl.cf_ctrl.service, + dioctl.cf_ctrl.fwd_nr, + &dioctl.cf_ctrl.procid))) + return (i); + break; + + default: + return (-EINVAL); + } /* switch cmd */ + return (copy_to_user((char *) arg, &dioctl, sizeof(dioctl))); /* success */ +} /* isdn_divert_ioctl */ #ifdef CONFIG_PROC_FS @@ -279,63 +302,66 @@ isdn_divert_lseek(struct file *file, loff_t offset, int orig) static struct file_operations isdn_fops = { - llseek: isdn_divert_lseek, - read: isdn_divert_read, - write: isdn_divert_write, - poll: isdn_divert_poll, - ioctl: isdn_divert_ioctl, - open: isdn_divert_open, - release: isdn_divert_close, -}; - -struct inode_operations divert_file_inode_operations = { - &isdn_fops, /* default proc file-ops */ + isdn_divert_lseek, + isdn_divert_read, + isdn_divert_write, + NULL, /* isdn_readdir */ + isdn_divert_poll, /* isdn_poll */ + isdn_divert_ioctl, /* isdn_ioctl */ + NULL, /* isdn_mmap */ + isdn_divert_open, + NULL, /* flush */ + isdn_divert_close, + NULL /* fsync */ }; +struct inode_operations divert_file_inode_operations; /****************************/ /* isdn subdir in /proc/net */ /****************************/ static struct proc_dir_entry *isdn_proc_entry = NULL; static struct proc_dir_entry *isdn_divert_entry = NULL; -#endif CONFIG_PROC_FS +#endif /* CONFIG_PROC_FS */ /***************************************************************************/ /* divert_dev_init must be called before the proc filesystem may be used */ /***************************************************************************/ -int divert_dev_init(void) -{ int i; +int +divert_dev_init(void) +{ init_waitqueue_head(&rd_queue); #ifdef CONFIG_PROC_FS - isdn_proc_entry = proc_mkdir("isdn", proc_net); - if (!isdn_proc_entry) - return(-1); - isdn_divert_entry = create_proc_entry("divert",0,isdn_proc_entry); - if (!isdn_divert_entry) - { - remove_proc_entry("isdn",proc_net); - return(-1); - } - isdn_divert_entry->ops = &divert_file_inode_operations; -#endif CONFIG_PROC_FS - - return(0); -} /* divert_dev_init */ + isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net); + if (!isdn_proc_entry) + return (-1); + isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry); + if (!isdn_divert_entry) { + remove_proc_entry("isdn", proc_net); + return (-1); + } + memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations)); + divert_file_inode_operations.default_file_ops = &isdn_fops; + isdn_divert_entry->ops = &divert_file_inode_operations; +#endif /* CONFIG_PROC_FS */ + + return (0); +} /* divert_dev_init */ /***************************************************************************/ /* divert_dev_deinit must be called before leaving isdn when included as */ /* a module. */ /***************************************************************************/ -int divert_dev_deinit(void) -{ int i; +int +divert_dev_deinit(void) +{ #ifdef CONFIG_PROC_FS - remove_proc_entry("divert",isdn_proc_entry); - remove_proc_entry("isdn",proc_net); -#endif CONFIG_PROC_FS - - return(0); -} /* divert_dev_deinit */ + remove_proc_entry("divert", isdn_proc_entry); + remove_proc_entry("isdn", proc_net); +#endif /* CONFIG_PROC_FS */ + return (0); +} /* divert_dev_deinit */ diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h index 88af10416c48..5ad1645189ca 100644 --- a/drivers/isdn/eicon/eicon.h +++ b/drivers/isdn/eicon/eicon.h @@ -1,10 +1,10 @@ -/* $Id: eicon.h,v 1.17 1999/10/26 21:15:33 armin Exp $ +/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $ * - * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * ISDN low-level module for Eicon active ISDN-Cards. * * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.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 @@ -21,6 +21,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon.h,v $ + * Revision 1.19 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * Revision 1.18 1999/11/25 11:43:27 armin + * Fixed statectrl and connect message. + * X.75 fix and HDLC/transparent with autoconnect. + * Minor cleanup. + * * Revision 1.17 1999/10/26 21:15:33 armin * using define for checking phone number len to avoid buffer overflow. * @@ -258,7 +267,7 @@ typedef struct { /* Macro for delay via schedule() */ #define SLEEP(j) { \ - set_current_state(TASK_INTERRUPTIBLE); \ + set_current_state(TASK_UNINTERRUPTIBLE); \ schedule_timeout(j); \ } @@ -277,6 +286,8 @@ typedef struct { #define XLOG_ERR_UNKNOWN (18) #define XLOG_OK (0) +#define TRACE_OK (1) + typedef struct { __u8 Id __attribute__ ((packed)); __u8 uX __attribute__ ((packed)); @@ -494,12 +505,13 @@ typedef struct { typedef struct { int No; /* Channel Number */ unsigned short fsm_state; /* Current D-Channel state */ + unsigned short statectrl; /* State controling bits */ unsigned short eazmask; /* EAZ-Mask for this Channel */ int queued; /* User-Data Bytes in TX queue */ int waitq; /* User-Data Bytes in wait queue */ int waitpq; /* User-Data Bytes in packet queue */ - unsigned short plci; - unsigned short ncci; + struct sk_buff *tskb1; /* temp skb 1 */ + struct sk_buff *tskb2; /* temp skb 2 */ unsigned char l2prot; /* Layer 2 protocol */ unsigned char l3prot; /* Layer 3 protocol */ #ifdef CONFIG_ISDN_TTY_FAX @@ -600,21 +612,16 @@ typedef struct eicon_card { struct eicon_card *next; /* Pointer to next device struct */ int myid; /* Driver-Nr. assigned by linklevel */ unsigned long flags; /* Statusflags */ - unsigned long ilock; /* Semaphores for IRQ-Routines */ struct sk_buff_head rcvq; /* Receive-Message queue */ struct sk_buff_head sndq; /* Send-Message queue */ struct sk_buff_head rackq; /* Req-Ack-Message queue */ struct sk_buff_head sackq; /* Data-Ack-Message queue */ struct sk_buff_head statq; /* Status-Message queue */ int statq_entries; - u_char *ack_msg; /* Ptr to User Data in User skb */ - __u16 need_b3ack; /* Flag: Need ACK for current skb */ - struct sk_buff *sbuf; /* skb which is currently sent */ struct tq_struct snd_tq; /* Task struct for xmit bh */ struct tq_struct rcv_tq; /* Task struct for rcv bh */ struct tq_struct ack_tq; /* Task struct for ack bh */ msn_entry *msn_list; - unsigned short msgnum; /* Message number for sending */ eicon_chan* IdTable[256]; /* Table to find entity */ __u16 ref_in; __u16 ref_out; @@ -696,6 +703,7 @@ extern int eicon_info(char *, int , void *); extern ulong DebugVar; extern void eicon_log(eicon_card * card, int level, const char *fmt, ...); +extern void eicon_putstatus(eicon_card * card, char * buf); #endif /* __KERNEL__ */ diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h index 9ffbd9bdbed3..420d73f6ea8f 100644 --- a/drivers/isdn/eicon/eicon_dsp.h +++ b/drivers/isdn/eicon/eicon_dsp.h @@ -1,10 +1,10 @@ -/* $Id: eicon_dsp.h,v 1.4 1999/07/25 15:12:02 armin Exp $ +/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $ * - * ISDN lowlevel-module for Eicon.Diehl active cards. + * ISDN lowlevel-module for Eicon active cards. * DSP definitions * - * Copyright 1999 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1999,2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.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 @@ -21,6 +21,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_dsp.h,v $ + * Revision 1.5 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * * Revision 1.4 1999/07/25 15:12:02 armin * fix of some debug logs. * enabled ISA-cards option. diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index d8634bdbe587..e53469070f60 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,10 +1,10 @@ -/* $Id: eicon_idi.c,v 1.24 1999/10/26 21:15:33 armin Exp $ +/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $ * - * ISDN lowlevel-module for Eicon.Diehl active cards. + * ISDN lowlevel-module for Eicon active cards. * IDI interface * - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * * Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax @@ -26,6 +26,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.29 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * 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. + * + * Revision 1.26 1999/11/25 11:43:27 armin + * Fixed statectrl and connect message. + * X.75 fix and HDLC/transparent with autoconnect. + * Minor cleanup. + * + * Revision 1.25 1999/11/18 20:30:55 armin + * removed old workaround for ISA cards. + * * Revision 1.24 1999/10/26 21:15:33 armin * using define for checking phone number len to avoid buffer overflow. * @@ -130,7 +149,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.24 $"; +char *eicon_idi_revision = "$Revision: 1.29 $"; eicon_manifbuf *manbuf; @@ -187,16 +206,13 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = LLC; reqbuf->XBuffer.P[l++] = 2; switch(chan->l2prot) { - case ISDN_PROTO_L2_HDLC: - reqbuf->XBuffer.P[l++] = 2; + case ISDN_PROTO_L2_TRANS: + reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: case ISDN_PROTO_L2_X75BUI: - reqbuf->XBuffer.P[l++] = 5; - break; - case ISDN_PROTO_L2_TRANS: - reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = 5; /* X.75 */ break; case ISDN_PROTO_L2_MODEM: if (chan->fsm_state == EICON_STATE_IWAIT) @@ -204,17 +220,18 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) else reqbuf->XBuffer.P[l++] = 10; /* V.42 */ break; + case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_FAX: if (chan->fsm_state == EICON_STATE_IWAIT) reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */ else - reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; default: 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; @@ -404,8 +421,10 @@ eicon_idi_listen_req(eicon_card *card, eicon_chan *chan) idi_do_req(card, chan, ASSIGN, 0); } if (chan->fsm_state == EICON_STATE_NULL) { - idi_do_req(card, chan, INDICATE_REQ, 0); - chan->fsm_state = EICON_STATE_LISTEN; + if (!(chan->statectrl & HAVE_CONN_REQ)) { + idi_do_req(card, chan, INDICATE_REQ, 0); + chan->fsm_state = EICON_STATE_LISTEN; + } } return(0); } @@ -462,6 +481,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan) } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { + chan->statectrl |= WAITING_FOR_HANGUP; idi_do_req(card, chan, HANGUP, 0); chan->fsm_state = EICON_STATE_NULL; } @@ -479,7 +499,6 @@ idi_connect_res(eicon_card *card, eicon_chan *chan) return 1; chan->fsm_state = EICON_STATE_IWAIT; - idi_do_req(card, chan, CALL_RES, 0); /* check if old NetID has been removed */ if (chan->e.B2Id) { @@ -489,6 +508,7 @@ idi_connect_res(eicon_card *card, eicon_chan *chan) } idi_do_req(card, chan, ASSIGN, 1); + idi_do_req(card, chan, CALL_RES, 0); return(0); } @@ -656,9 +676,18 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ - skb_queue_tail(&chan->e.X, skb); - skb_queue_tail(&card->sndq, skb2); - eicon_schedule_tx(card); + if (chan->statectrl & WAITING_FOR_HANGUP) { + /* If the line did not disconnect yet, + we have to delay this command */ + eicon_log(card, 32, "idi_req: Ch%d: delaying conn_req\n", chan->No); + chan->statectrl |= HAVE_CONN_REQ; + chan->tskb1 = skb; + chan->tskb2 = skb2; + } else { + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + eicon_schedule_tx(card); + } eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone); return(0); @@ -1433,6 +1462,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, ""); ccard->interface.statcallb(&cmd); cmd.driver = ccard->myid; @@ -1489,6 +1519,8 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) break; case 2: /* session end */ default: + /* send_edata produces error on some */ + /* fax-machines here, so we don't */ /* idi_send_edata(ccard, chan); */ break; } @@ -1505,6 +1537,7 @@ idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, ""); ccard->interface.statcallb(&cmd); cmd.driver = ccard->myid; @@ -2276,6 +2309,51 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int } } +void +eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len) +{ + int i,j,n; + int buflen = len * 3 + 30; + char *p; + struct trace_s { + unsigned long time; + unsigned short size; + unsigned short code; + unsigned char data[1]; + } *q; + + if (!(p = kmalloc(buflen, GFP_KERNEL))) { + eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n"); + return; + } + memset(p, 0, buflen); + q = (struct trace_s *)buffer; + + if (DebugVar & 512) { + if ((q->code == 3) || (q->code == 4)) { + n = (short) *(q->data); + if (n) { + j = sprintf(p, "DTRC:"); + for (i = 0; i < n; i++) { + j += sprintf(p + j, "%02x ", q->data[i+2]); + } + j += sprintf(p + j, "\n"); + } + } + } else { + j = sprintf(p, "XLOG: %lx %04x %04x ", + q->time, q->size, q->code); + + for (i = 0; i < q->size; i++) { + j += sprintf(p + j, "%02x ", q->data[i]); + } + j += sprintf(p + j, "\n"); + } + if (strlen(p)) + eicon_putstatus(ccard, p); + kfree(p); +} + void idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) { @@ -2307,7 +2385,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) else dlev = 128; - eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No, + eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%x Id=%x Ch=%x MInd=%x MLen=%x Len=%x\n", chan->No, ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); free_buff = 1; @@ -2347,12 +2425,25 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } else { if (chan->e.B2Id) idi_do_req(ccard, chan, REMOVE, 1); - chan->fsm_state = EICON_STATE_NULL; - cmd.driver = ccard->myid; - cmd.arg = chan->No; - cmd.command = ISDN_STAT_DHUP; - ccard->interface.statcallb(&cmd); - eicon_idi_listen_req(ccard, chan); + chan->statectrl &= ~WAITING_FOR_HANGUP; + if (chan->statectrl & HAVE_CONN_REQ) { + eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No); + chan->statectrl &= ~HAVE_CONN_REQ; + if ((chan->tskb1) && (chan->tskb2)) { + skb_queue_tail(&chan->e.X, chan->tskb1); + skb_queue_tail(&ccard->sndq, chan->tskb2); + eicon_schedule_tx(ccard); + } + chan->tskb1 = NULL; + chan->tskb2 = NULL; + } else { + chan->fsm_state = EICON_STATE_NULL; + cmd.driver = ccard->myid; + cmd.arg = chan->No; + cmd.command = ISDN_STAT_DHUP; + ccard->interface.statcallb(&cmd); + eicon_idi_listen_req(ccard, chan); + } } break; case INDICATE_IND: @@ -2450,8 +2541,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case ISDN_PROTO_L2_MODEM: /* do nothing, wait for connect */ break; - default: + case ISDN_PROTO_L2_TRANS: idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + break; + default: + /* On most incoming calls we use automatic connect */ + /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ } } else idi_hangup(ccard, chan); @@ -2495,8 +2590,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) if (chan->No == ccard->nchannels) { /* Management Indication */ - idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); - chan->fsm_state = 1; + if (ind->Ind == 0x04) { /* Trace_Ind */ + eicon_parse_trace(ccard, ind->RBuffer.P, ind->RBuffer.length); + } else { + idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); + chan->fsm_state = 1; + } } else switch(ind->Ind) { @@ -2530,6 +2629,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; case IDI_N_CONNECT: @@ -2546,6 +2646,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BCONN; cmd.arg = chan->No; + strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; case IDI_N_DISC: @@ -2576,6 +2677,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.arg = chan->No; ccard->interface.statcallb(&cmd); chan->fsm_state = EICON_STATE_NULL; + chan->statectrl |= WAITING_FOR_HANGUP; } #ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0; @@ -2631,7 +2733,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) isdn_ctrl cmd; if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { - /* I dont know why this happens, just ignoring this RC */ + /* I dont know why this happens, should not ! */ + /* just ignoring this RC */ eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id); return 1; @@ -2640,16 +2743,16 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) /* Management Interface */ if (chan->No == ccard->nchannels) { /* Managementinterface: changing state */ - if (chan->e.Req == 0x04) + if (chan->e.Req != 0x02) chan->fsm_state = 1; } /* Remove an Id */ if (chan->e.Req == REMOVE) { if (ack->Reference != chan->e.ref) { + /* This should not happen anymore */ eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); - return 0; } save_flags(flags); cli(); @@ -2807,11 +2910,14 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) dCh, ack->Rc, ack->RcId, ack->RcCh); break; default: - eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", - dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); + if (dCh != ccard->nchannels) + eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", + dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); } if (dCh == ccard->nchannels) { /* Management */ chan->fsm_state = 2; + eicon_log(ccard, 8, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n", + dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req); } else if (dCh >= 0) { /* any other channel */ /* card reports error: we hangup */ @@ -3011,38 +3117,36 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) chan = &(card->bch[card->nchannels]); - if (chan->e.D3Id) - return -EBUSY; - chan->e.D3Id = 1; - while((skb2 = skb_dequeue(&chan->e.X))) - dev_kfree_skb(skb2); - chan->e.busy = 0; + if (!(chan->e.D3Id)) { + chan->e.D3Id = 1; + while((skb2 = skb_dequeue(&chan->e.X))) + dev_kfree_skb(skb2); + chan->e.busy = 0; - if ((ret = eicon_idi_manage_assign(card))) { - chan->e.D3Id = 0; - return(ret); - } + if ((ret = eicon_idi_manage_assign(card))) { + chan->e.D3Id = 0; + return(ret); + } - timeout = jiffies + 50; - while (timeout > jiffies) { - if (chan->e.B2Id) break; - SLEEP(10); - } - if (!chan->e.B2Id) { - chan->e.D3Id = 0; - return -EIO; + timeout = jiffies + 50; + while (timeout > jiffies) { + if (chan->e.B2Id) break; + SLEEP(10); + } + if (!chan->e.B2Id) { + chan->e.D3Id = 0; + return -EIO; + } } chan->fsm_state = 0; if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) { eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n"); - chan->e.D3Id = 0; return -ENOMEM; } if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) { kfree(manbuf); - chan->e.D3Id = 0; return -EFAULT; } @@ -3056,7 +3160,6 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) if (skb2) dev_kfree_skb(skb2); kfree(manbuf); - chan->e.D3Id = 0; return -ENOMEM; } @@ -3093,25 +3196,14 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) SLEEP(10); } if ((!chan->fsm_state) || (chan->fsm_state == 2)) { - eicon_idi_manage_remove(card); kfree(manbuf); - chan->e.D3Id = 0; return -EIO; } - - if ((ret = eicon_idi_manage_remove(card))) { - kfree(manbuf); - chan->e.D3Id = 0; - return(ret); - } - if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) { kfree(manbuf); - chan->e.D3Id = 0; return -EFAULT; } kfree(manbuf); - chan->e.D3Id = 0; return(0); } diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h index e09c1954d479..2fe6167a4347 100644 --- a/drivers/isdn/eicon/eicon_idi.h +++ b/drivers/isdn/eicon/eicon_idi.h @@ -1,10 +1,10 @@ -/* $Id: eicon_idi.h,v 1.7 1999/08/22 20:26:46 calle Exp $ +/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $ * - * ISDN lowlevel-module for the Eicon.Diehl active cards. + * ISDN lowlevel-module for the Eicon active cards. * IDI-Interface * - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.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 @@ -21,6 +21,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.h,v $ + * Revision 1.9 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * Revision 1.8 1999/11/25 11:43:27 armin + * Fixed statectrl and connect message. + * X.75 fix and HDLC/transparent with autoconnect. + * Minor cleanup. + * * Revision 1.7 1999/08/22 20:26:46 calle * backported changes from kernel 2.3.14: * - several #include "config.h" gone, others come. @@ -170,6 +179,10 @@ /*------------------------------------------------------------------*/ +/* defines for statectrl */ +#define WAITING_FOR_HANGUP 0x01 +#define HAVE_CONN_REQ 0x02 + typedef struct { char cpn[32]; char oad[32]; diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c index 779f241e0a9c..4f4180ed6eff 100644 --- a/drivers/isdn/eicon/eicon_io.c +++ b/drivers/isdn/eicon/eicon_io.c @@ -1,12 +1,12 @@ -/* $Id: eicon_io.c,v 1.8 1999/10/08 22:09:34 armin Exp $ +/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $ * - * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. * - * Copyright 1999 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1999,2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology Diehl GmbH & Co. oHG for + * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * * This program is free software; you can redistribute it and/or modify @@ -24,6 +24,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_io.c,v $ + * Revision 1.10 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * Revision 1.9 1999/11/18 20:55:25 armin + * Ready_Int fix of ISA cards. + * * Revision 1.8 1999/10/08 22:09:34 armin * Some fixes of cards interface handling. * Bugfix of NULL pointer occurence. @@ -470,7 +477,7 @@ eicon_io_transmit(eicon_card *ccard) { save_flags(flags); cli(); if (scom) { - if (ram_inb(ccard, &com->Req)) { + if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) { if (!ccard->ReadyInt) { tmp = ram_inb(ccard, &com->ReadyInt) + 1; ram_outb(ccard, &com->ReadyInt, tmp); @@ -566,7 +573,8 @@ eicon_io_transmit(eicon_card *ccard) { chan->e.busy = 1; eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", reqbuf->Req, - ram_inb(ccard, &ReqOut->ReqId), + (scom) ? ram_inb(ccard, &com->ReqId) : + ram_inb(ccard, &ReqOut->ReqId), reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); } @@ -754,6 +762,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { if (ccard->ReadyInt) { ccard->ReadyInt--; ram_outb(ccard, &com->Rc, 0); + eicon_schedule_tx(ccard); } } else { skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index a89d18b12128..86e6c0ef7e05 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,11 +1,11 @@ -/* $Id: eicon_isa.c,v 1.9 1999/09/08 20:17:31 armin Exp $ +/* $Id: eicon_isa.c,v 1.13 2000/01/23 21:21:23 armin Exp $ * - * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. * - * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.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 @@ -22,8 +22,21 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.c,v $ + * Revision 1.13 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * Revision 1.12 1999/11/27 12:56:19 armin + * Forgot some iomem changes for last ioremap compat. + * + * Revision 1.11 1999/11/25 11:33:09 armin + * Microchannel fix from Erik Weber (exrz73@ibm.net). + * + * Revision 1.10 1999/11/18 21:14:30 armin + * New ISA memory mapped IO + * * Revision 1.9 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. + * Added microchannel patch from Erik Weber (exrz73@ibm.net). * * Revision 1.8 1999/09/06 07:29:35 fritz * Changed my mail-address. @@ -70,7 +83,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.9 $"; +char *eicon_isa_revision = "$Revision: 1.13 $"; #undef EICON_MCA_DEBUG @@ -87,8 +100,10 @@ static int eicon_isa_valid_irq[] = { static void eicon_isa_release_shmem(eicon_isa_card *card) { - if (card->mvalid) - release_shmem((unsigned long)card->shmem, card->ramsize); + if (card->mvalid) { + iounmap(card->shmem); + release_mem_region(card->physmem, card->ramsize); + } card->mvalid = 0; } @@ -117,7 +132,7 @@ eicon_isa_printpar(eicon_isa_card *card) { case EICON_CTYPE_S2M: printk(KERN_INFO "Eicon %s at 0x%lx, irq %d.\n", eicon_ctype_name[card->type], - (unsigned long)card->shmem, + card->physmem, card->irq); } } @@ -126,6 +141,7 @@ int eicon_isa_find_card(int Mem, int Irq, char * Id) { int primary = 1; + unsigned long amem; if (!strlen(Id)) return -1; @@ -138,24 +154,27 @@ eicon_isa_find_card(int Mem, int Irq, char * Id) Mem, Id); return -1; } - if (check_shmem(Mem, RAMSIZE)) { + if (check_mem_region(Mem, RAMSIZE)) { printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem); return -1; } - writew(0x55aa, Mem + 0x402); - if (readw(Mem + 0x402) != 0x55aa) primary = 0; - writew(0, Mem + 0x402); - if (readw(Mem + 0x402) != 0) primary = 0; + amem = (unsigned long) ioremap(Mem, RAMSIZE); + writew(0x55aa, amem + 0x402); + if (readw(amem + 0x402) != 0x55aa) primary = 0; + writew(0, amem + 0x402); + if (readw(amem + 0x402) != 0) primary = 0; printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id); if (primary) { printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem); - writeb(0, Mem + 0x3ffe); + writeb(0, amem + 0x3ffe); + iounmap((unsigned char *)amem); return EICON_CTYPE_ISAPRI; } else { printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem); - writeb(0, Mem + 0x400); + writeb(0, amem + 0x400); + iounmap((unsigned char *)amem); return EICON_CTYPE_ISABRI; } return -1; @@ -187,57 +206,65 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { return -EFAULT; } + if (card->type == EICON_CTYPE_ISAPRI) + card->ramsize = RAMSIZE_P; + else + card->ramsize = RAMSIZE; + + if (check_mem_region(card->physmem, card->ramsize)) { + printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n", + card->physmem); + kfree(code); + return -EBUSY; + } + request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN"); + card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize); +#ifdef EICON_MCA_DEBUG + printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize); +#endif + card->mvalid = 1; + switch(card->type) { case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: case EICON_CTYPE_QUADRO: case EICON_CTYPE_ISABRI: - card->ramsize = RAMSIZE; card->intack = (__u8 *)card->shmem + INTACK; card->startcpu = (__u8 *)card->shmem + STARTCPU; card->stopcpu = (__u8 *)card->shmem + STOPCPU; break; case EICON_CTYPE_S2M: case EICON_CTYPE_ISAPRI: - card->ramsize = RAMSIZE_P; card->intack = (__u8 *)card->shmem + INTACK_P; card->startcpu = (__u8 *)card->shmem + STARTCPU_P; card->stopcpu = (__u8 *)card->shmem + STOPCPU_P; break; default: printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type); + eicon_isa_release_shmem(card); + kfree(code); return -EINVAL; } - /* Register shmem */ - if (check_shmem((unsigned long)card->shmem, card->ramsize)) { - printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n", - (unsigned long)card->shmem); - kfree(code); - return -EBUSY; - } - request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN"); -#ifdef EICON_MCA_DEBUG - printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize); -#endif - card->mvalid = 1; - /* clear any pending irq's */ readb(card->intack); #ifdef CONFIG_MCA - if (card->type == EICON_CTYPE_SCOM) { - outb_p(0,card->io+1); - } - else { - printk(KERN_WARNING "eicon_isa_boot: Card type yet not supported.\n"); - return -EINVAL; - }; + if (MCA_bus) { + if (card->type == EICON_CTYPE_SCOM) { + outb_p(0,card->io+1); + } + else { + printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.\n"); + eicon_isa_release_shmem(card); + return -EINVAL; + }; #ifdef EICON_MCA_DEBUG printk(KERN_INFO "eicon_isa_boot: card->io = %x.\n", card->io); printk(KERN_INFO "eicon_isa_boot: card->irq = %d.\n", (int)card->irq); #endif + } #else /* set reset-line active */ writeb(0, card->stopcpu); @@ -269,7 +296,9 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { /* Start CPU */ writeb(cbuf.boot_opt, &boot->ctrl); #ifdef CONFIG_MCA - outb_p(0, card->io); + if (MCA_bus) { + outb_p(0, card->io); + } #else writeb(0, card->startcpu); #endif /* CONFIG_MCA */ @@ -320,7 +349,7 @@ eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { } printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) { - tmp = eicon_addcard(card->type, (unsigned long)card->shmem, card->irq, + tmp = eicon_addcard(card->type, card->physmem, card->irq, ((eicon_card *)card->card)->regname); printk(KERN_INFO "Eicon: %d adapters added\n", tmp); } diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h index b0d0b0eb9e1c..b53adfcbf66a 100644 --- a/drivers/isdn/eicon/eicon_isa.h +++ b/drivers/isdn/eicon/eicon_isa.h @@ -1,10 +1,10 @@ -/* $Id: eicon_isa.h,v 1.6 1999/11/15 19:37:04 keil Exp $ +/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $ * - * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * ISDN low-level module for Eicon active ISDN-Cards. * - * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.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 @@ -21,6 +21,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.h,v $ + * Revision 1.8 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * Revision 1.7 1999/11/18 21:14:30 armin + * New ISA memory mapped IO + * * Revision 1.6 1999/11/15 19:37:04 keil * need config.h * @@ -116,6 +123,7 @@ typedef union { typedef struct { int ramsize; int irq; /* IRQ */ + unsigned long physmem; /* physical memory address */ #ifdef CONFIG_MCA int io; /* IO-port for MCA brand */ #endif /* CONFIG_MCA */ diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index 8797e6aed3f2..688d74de3f54 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,12 +1,12 @@ -/* $Id: eicon_mod.c,v 1.19 1999/11/12 13:21:44 armin Exp $ +/* $Id: eicon_mod.c,v 1.24 2000/01/23 21:21:23 armin Exp $ * - * ISDN lowlevel-module for Eicon.Diehl active cards. + * ISDN lowlevel-module for Eicon active cards. * - * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology Diehl GmbH & Co. oHG for + * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * * Deutsche Telekom AG for S2M support. @@ -31,6 +31,23 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.24 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * + * 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. + * + * Revision 1.21 1999/11/25 11:35:10 armin + * Microchannel fix from Erik Weber (exrz73@ibm.net). + * Minor cleanup. + * + * Revision 1.20 1999/11/18 21:14:30 armin + * New ISA memory mapped IO + * * Revision 1.19 1999/11/12 13:21:44 armin * Bugfix of undefined reference with CONFIG_MCA * @@ -46,7 +63,7 @@ * Improved debug and log via readstat() * * Revision 1.15 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. + * Added microchannel patch from Erik Weber (exrz73@ibm.net). * * Revision 1.14 1999/09/06 07:29:35 fritz * Changed my mail-address. @@ -123,7 +140,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.19 $"; +static char *eicon_revision = "$Revision: 1.24 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -144,7 +161,7 @@ static int irq = -1; #endif static char *id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -MODULE_DESCRIPTION( "Driver for Eicon.Diehl active ISDN cards"); +MODULE_DESCRIPTION( "Driver for Eicon active ISDN cards"); MODULE_AUTHOR( "Armin Schindler"); MODULE_SUPPORTED_DEVICE( "ISDN subsystem"); MODULE_PARM_DESC(id, "ID-String of first card"); @@ -659,7 +676,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; @@ -839,8 +856,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) } /* jiftime() copied from HiSax */ -inline int -jiftime(char *s, long mark) +static inline int jiftime(char *s, long mark) { s += 8; @@ -1000,19 +1016,28 @@ eicon_alloccard(int Type, int membase, int irq, char *id) case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: - if (membase == -1) - membase = EICON_ISA_MEMBASE; - if (irq == -1) - irq = EICON_ISA_IRQ; - card->bus = EICON_BUS_MCA; - card->hwif.isa.card = (void *)card; - card->hwif.isa.shmem = (eicon_isa_shmem *)membase; - card->hwif.isa.master = 1; - - card->hwif.isa.irq = irq; - card->hwif.isa.type = Type; - card->nchannels = 2; - card->interface.channels = 1; + if (MCA_bus) { + if (membase == -1) + membase = EICON_ISA_MEMBASE; + if (irq == -1) + irq = EICON_ISA_IRQ; + card->bus = EICON_BUS_MCA; + card->hwif.isa.card = (void *)card; + card->hwif.isa.shmem = (eicon_isa_shmem *)membase; + card->hwif.isa.physmem = (unsigned long)membase; + card->hwif.isa.master = 1; + + card->hwif.isa.irq = irq; + card->hwif.isa.type = Type; + card->nchannels = 2; + card->interface.channels = 1; + } else { + printk(KERN_WARNING + "eicon (%s): no MCA bus detected.\n", + card->interface.id); + kfree(card); + return; + } break; #endif /* CONFIG_MCA */ case EICON_CTYPE_QUADRO: @@ -1023,6 +1048,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->bus = EICON_BUS_ISA; card->hwif.isa.card = (void *)card; card->hwif.isa.shmem = (eicon_isa_shmem *)(membase + (i+1) * EICON_ISA_QOFFSET); + card->hwif.isa.physmem = (unsigned long)(membase + (i+1) * EICON_ISA_QOFFSET); card->hwif.isa.master = 0; strcpy(card->interface.id, id); if (id[strlen(id) - 1] == 'a') { @@ -1067,7 +1093,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; @@ -1091,7 +1117,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; @@ -1116,6 +1142,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->bus = EICON_BUS_ISA; card->hwif.isa.card = (void *)card; card->hwif.isa.shmem = (eicon_isa_shmem *)membase; + card->hwif.isa.physmem = (unsigned long)membase; card->hwif.isa.master = 1; card->hwif.isa.irq = irq; card->hwif.isa.type = Type; @@ -1130,6 +1157,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->bus = EICON_BUS_ISA; card->hwif.isa.card = (void *)card; card->hwif.isa.shmem = (eicon_isa_shmem *)membase; + card->hwif.isa.physmem = (unsigned long)membase; card->hwif.isa.master = 1; card->hwif.isa.irq = irq; card->hwif.isa.type = Type; @@ -1151,14 +1179,15 @@ eicon_alloccard(int Type, int membase, int irq, char *id) } for (j=0; j< (card->nchannels + 1); j++) { memset((char *)&card->bch[j], 0, sizeof(eicon_chan)); - card->bch[j].plci = 0x8000; - card->bch[j].ncci = 0x8000; + card->bch[j].statectrl = 0; card->bch[j].l2prot = ISDN_PROTO_L2_X75I; card->bch[j].l3prot = ISDN_PROTO_L3_TRANS; card->bch[j].e.D3Id = 0; card->bch[j].e.B2Id = 0; card->bch[j].e.Req = 0; card->bch[j].No = j; + card->bch[j].tskb1 = NULL; + card->bch[j].tskb2 = NULL; skb_queue_head_init(&card->bch[j].e.X); skb_queue_head_init(&card->bch[j].e.R); } diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c index 5c96302cb80e..47196f953a01 100644 --- a/drivers/isdn/eicon/eicon_pci.c +++ b/drivers/isdn/eicon/eicon_pci.c @@ -1,12 +1,12 @@ -/* $Id: eicon_pci.c,v 1.10 1999/08/22 20:26:49 calle Exp $ +/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $ * - * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. * - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology Diehl GmbH & Co. oHG for + * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * * Deutsche Telekom AG for S2M support. @@ -26,6 +26,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_pci.c,v $ + * Revision 1.11 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * * Revision 1.10 1999/08/22 20:26:49 calle * backported changes from kernel 2.3.14: * - several #include "config.h" gone, others come. @@ -77,7 +81,7 @@ #include "eicon_pci.h" -char *eicon_pci_revision = "$Revision: 1.10 $"; +char *eicon_pci_revision = "$Revision: 1.11 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h index a23faade2ba8..384cc422c536 100644 --- a/drivers/isdn/eicon/eicon_pci.h +++ b/drivers/isdn/eicon/eicon_pci.h @@ -1,9 +1,9 @@ -/* $Id: eicon_pci.h,v 1.3 1999/03/29 11:19:51 armin Exp $ +/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $ * - * ISDN low-level module for Eicon.Diehl active ISDN-Cards (PCI part). + * ISDN low-level module for Eicon active ISDN-Cards (PCI part). * - * Copyright 1998,99 by Armin Schindler (mac@melware.de) - * Copyright 1999 Cytronics & Melware (info@melware.de) + * Copyright 1998-2000 by Armin Schindler (mac@melware.de) + * Copyright 1999,2000 Cytronics & Melware (info@melware.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 @@ -20,6 +20,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_pci.h,v $ + * Revision 1.4 2000/01/23 21:21:23 armin + * Added new trace capability and some updates. + * DIVA Server BRI now supports data for ISDNLOG. + * * Revision 1.3 1999/03/29 11:19:51 armin * I/O stuff now in seperate file (eicon_io.c) * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. 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/arcofi.c b/drivers/isdn/hisax/arcofi.c index e8abc9de2d0a..5b3f3aadb90d 100644 --- a/drivers/isdn/hisax/arcofi.c +++ b/drivers/isdn/hisax/arcofi.c @@ -1,12 +1,19 @@ -/* $Id: arcofi.c,v 1.8 1999/08/25 16:50:51 keil Exp $ +/* $Id: arcofi.c,v 1.10 1999/12/23 15:09:32 keil Exp $ * arcofi.c Ansteuerung ARCOFI 2165 * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * * $Log: arcofi.c,v $ + * Revision 1.10 1999/12/23 15:09:32 keil + * change email + * + * Revision 1.9 1999/12/19 13:09:41 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.8 1999/08/25 16:50:51 keil * Fix bugs which cause 2.3.14 hangs (waitqueue init) * @@ -83,7 +90,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) { if (event == ARCOFI_TIMEOUT) { cs->dc.isac.arcofi_state = ARCOFI_NOP; test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags); - wake_up_interruptible(&cs->dc.isac.arcofi_wait); + wake_up(&cs->dc.isac.arcofi_wait); return(1); } switch (cs->dc.isac.arcofi_state) { @@ -109,7 +116,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) { del_timer(&cs->dc.isac.arcofitimer); } cs->dc.isac.arcofi_state = ARCOFI_NOP; - wake_up_interruptible(&cs->dc.isac.arcofi_wait); + wake_up(&cs->dc.isac.arcofi_wait); } } } @@ -126,7 +133,7 @@ arcofi_fsm(struct IsdnCardState *cs, int event, void *data) { del_timer(&cs->dc.isac.arcofitimer); } cs->dc.isac.arcofi_state = ARCOFI_NOP; - wake_up_interruptible(&cs->dc.isac.arcofi_wait); + wake_up(&cs->dc.isac.arcofi_wait); } } break; diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h index 86617d6a1b63..7d1c445e5a45 100644 --- a/drivers/isdn/hisax/arcofi.h +++ b/drivers/isdn/hisax/arcofi.h @@ -1,12 +1,15 @@ -/* $Id: arcofi.h,v 1.4 1999/07/01 08:11:18 keil Exp $ +/* $Id: arcofi.h,v 1.5 1999/12/23 15:09:32 keil Exp $ * arcofi.h Ansteuerung ARCOFI 2165 * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * * $Log: arcofi.h,v $ + * Revision 1.5 1999/12/23 15:09:32 keil + * change email + * * Revision 1.4 1999/07/01 08:11:18 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index 10657ad63afe..98c9736b6447 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -1,4 +1,4 @@ -/* $Id: asuscom.c,v 1.8 1999/09/04 06:20:05 keil Exp $ +/* $Id: asuscom.c,v 1.9 1999/12/19 13:09:41 keil Exp $ * asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards * @@ -8,6 +8,10 @@ * * * $Log: asuscom.c,v $ + * Revision 1.9 1999/12/19 13:09:41 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.8 1999/09/04 06:20:05 keil * Changes from kernel set_current_state() * @@ -42,7 +46,7 @@ extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.8 $"; +const char *Asuscom_revision = "$Revision: 1.9 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -291,13 +295,13 @@ reset_asuscom(struct IsdnCardState *cs) byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->subtyp == ASUS_IPAC) writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0); else byteout(cs->hw.asus.adr, 0); /* Reset Off */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->subtyp == ASUS_IPAC) { writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0); diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index f343bfb5ae24..319e0b264f51 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.12 1999/09/04 06:20:05 keil Exp $ +/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $ * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -7,6 +7,13 @@ * * * $Log: avm_pci.c,v $ + * Revision 1.14 1999/12/19 13:09:41 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * + * Revision 1.13 1999/12/03 12:10:14 keil + * Bugfix: Wrong channel use on hangup of channel 2 + * * Revision 1.12 1999/09/04 06:20:05 keil * Changes from kernel set_current_state() * @@ -56,7 +63,7 @@ #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.12 $"; +static const char *avm_pci_rev = "$Revision: 1.14 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -269,18 +276,26 @@ modehdlc(struct BCState *bcs, int mode, int bc) int hdlc = bcs->channel; if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hdlc %c mode %d ichan %d", - 'A' + hdlc, mode, bc); - bcs->mode = mode; - bcs->channel = bc; + debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d", + 'A' + hdlc, bcs->mode, mode, hdlc, bc); bcs->hw.hdlc.ctrl.ctrl = 0; switch (mode) { + case (-1): /* used for init */ + bcs->mode = 1; + bcs->channel = bc; + bc = 0; case (L1_MODE_NULL): + if (bcs->mode == L1_MODE_NULL) + return; bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; write_ctrl(bcs, 5); + bcs->mode = L1_MODE_NULL; + bcs->channel = bc; break; case (L1_MODE_TRANS): + bcs->mode = mode; + bcs->channel = bc; bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; write_ctrl(bcs, 5); @@ -290,6 +305,8 @@ modehdlc(struct BCState *bcs, int mode, int bc) hdlc_sched_event(bcs, B_XMTBUFREADY); break; case (L1_MODE_HDLC): + bcs->mode = mode; + bcs->channel = bc; bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG; write_ctrl(bcs, 5); @@ -695,8 +712,8 @@ inithdlc(struct IsdnCardState *cs)) cs->bcs[1].BC_SetStack = setstack_hdlc; cs->bcs[0].BC_Close = close_hdlcstate; cs->bcs[1].BC_Close = close_hdlcstate; - modehdlc(cs->bcs, 0, 0); - modehdlc(cs->bcs + 1, 0, 0); + modehdlc(cs->bcs, -1, 0); + modehdlc(cs->bcs + 1, -1, 1); } static void @@ -734,11 +751,11 @@ reset_avmpcipnp(struct IsdnCardState *cs) save_flags(flags); sti(); outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3)); } diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index cb999972cc2a..ce02a1bc679c 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.8 1999/09/04 06:20:05 keil Exp $ +/* $Id: bkm_a4t.c,v 1.9 1999/12/19 13:09:41 keil Exp $ * bkm_a4t.c low level stuff for T-Berkom A4T * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -7,6 +7,10 @@ * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: bkm_a4t.c,v $ + * Revision 1.9 1999/12/19 13:09:41 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.8 1999/09/04 06:20:05 keil * Changes from kernel set_current_state() * @@ -48,7 +52,7 @@ extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.8 $"; +const char *bkm_a4t_revision = "$Revision: 1.9 $"; static inline u_char @@ -231,11 +235,11 @@ reset_bkm(struct IsdnCardState *cs) sti(); /* Issue the I20 soft reset */ pI20_Regs->i20SysControl = 0xFF; /* all in */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); /* Remove the soft reset */ pI20_Regs->i20SysControl = sysRESET | 0xFF; - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); /* Set our configuration */ pI20_Regs->i20SysControl = sysRESET | sysCFG; @@ -246,14 +250,14 @@ reset_bkm(struct IsdnCardState *cs) g_A4T_ISAC_RES | g_A4T_JADE_BOOTR | g_A4T_ISAR_BOOTR; - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); /* Remove RESET state from ISDN */ pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | g_A4T_JADE_RES | g_A4T_ISAR_RES); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); restore_flags(flags); } diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index fda6c213c0fb..8ec2e9a08e69 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.8 1999/09/04 06:20:05 keil Exp $ +/* $Id: bkm_a8.c,v 1.9 1999/12/19 13:09:41 keil Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -7,6 +7,10 @@ * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: bkm_a8.c,v $ + * Revision 1.9 1999/12/19 13:09:41 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.8 1999/09/04 06:20:05 keil * Changes from kernel set_current_state() * @@ -49,7 +53,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.8 $"; +const char sct_quadro_revision[] = "$Revision: 1.9 $"; /* To survive the startup phase */ typedef struct { @@ -298,13 +302,13 @@ reset_bkm(struct IsdnCardState *cs) save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); /* Remove the soft reset */ wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10 * HZ) / 1000); restore_flags(flags); } diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index e4c26d9debd2..4a01218c32de 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 2.39 1999/10/14 20:25:28 keil Exp $ +/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,10 @@ * Fritz Elfert * * $Log: callc.c,v $ + * Revision 2.40 1999/12/19 12:59:56 keil + * fix leased line handling + * and cosmetics + * * Revision 2.39 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -163,7 +167,7 @@ #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module)) #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.39 $"; +const char *lli_revision = "$Revision: 2.40 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -199,8 +203,7 @@ static int chancount = 0; /* * Find card with given driverId */ -static inline struct IsdnCardState -* +static inline struct IsdnCardState * hisax_findcard(int driverid) { int i; @@ -239,39 +242,39 @@ link_debug(struct Channel *chanp, int direction, char *fmt, ...) } enum { - ST_NULL, /* 0 inactive */ - ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */ - ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */ - ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */ - ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */ - ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ - ST_ACTIVE, /* 6 active, b channel prot. established */ - ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */ - ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */ - ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */ - ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */ - ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */ - ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */ + ST_NULL, /* 0 inactive */ + ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */ + ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */ + ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */ + ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */ + ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ + ST_ACTIVE, /* 6 active, b channel prot. established */ + ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */ + ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */ + ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */ + ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */ + ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */ + ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */ }; #define STATE_COUNT (ST_IN_PROCEED_SEND + 1) - static char *strState[] = - { - "ST_NULL", - "ST_OUT_DIAL", - "ST_IN_WAIT_LL", - "ST_IN_ALERT_SENT", - "ST_IN_WAIT_CONN_ACK", - "ST_WAIT_BCONN", - "ST_ACTIVE", +static char *strState[] = +{ + "ST_NULL", + "ST_OUT_DIAL", + "ST_IN_WAIT_LL", + "ST_IN_ALERT_SENT", + "ST_IN_WAIT_CONN_ACK", + "ST_WAIT_BCONN", + "ST_ACTIVE", "ST_WAIT_BRELEASE", "ST_WAIT_BREL_DISC", "ST_WAIT_DCOMMAND", "ST_WAIT_DRELEASE", "ST_WAIT_D_REL_CNF", - "ST_IN_PROCEED_SEND", + "ST_IN_PROCEED_SEND", }; enum { @@ -333,19 +336,19 @@ static char *strEvent[] = static inline void HL_LL(struct Channel *chanp, int command) { - isdn_ctrl ic; + isdn_ctrl ic; - ic.driver = chanp->cs->myid; - ic.command = command; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); + ic.driver = chanp->cs->myid; + ic.command = command; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); } static inline void lli_deliver_cause(struct Channel *chanp) { - isdn_ctrl ic; - + isdn_ctrl ic; + if (chanp->proc->para.cause == NO_CAUSE) return; ic.driver = chanp->cs->myid; @@ -363,42 +366,42 @@ lli_deliver_cause(struct Channel *chanp) static inline void lli_close(struct FsmInst *fi) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_NULL); - chanp->Flags = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); + FsmChangeState(fi, ST_NULL); + chanp->Flags = 0; + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } - static void +static void lli_leased_in(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + int ret; - isdn_ctrl ic; - int ret; - - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_IN_WAIT_LL); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_ICALL_LEASED"); - ic.driver = chanp->cs->myid; + if (!chanp->leased) + return; + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); + FsmChangeState(fi, ST_IN_WAIT_LL); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_ICALL_LEASED"); + ic.driver = chanp->cs->myid; ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); - ic.arg = chanp->chan; - ic.parm.setup.si1 = 7; - ic.parm.setup.si2 = 0; - ic.parm.setup.plan = 0; - ic.parm.setup.screen = 0; - sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); - sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid); - ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 1, "statcallb ret=%d", ret); - - if (!ret) { - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_NULL); - } + ic.arg = chanp->chan; + ic.parm.setup.si1 = 7; + ic.parm.setup.si2 = 0; + ic.parm.setup.plan = 0; + ic.parm.setup.screen = 0; + sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); + sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid); + ret = chanp->cs->iif.statcallb(&ic); + if (chanp->debug & 1) + link_debug(chanp, 1, "statcallb ret=%d", ret); + if (!ret) { + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); + FsmChangeState(fi, ST_NULL); + } } @@ -408,14 +411,14 @@ lli_leased_in(struct FsmInst *fi, int event, void *arg) static void lli_init_bchan_out(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_BCONN); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DCONN"); - HL_LL(chanp, ISDN_STAT_DCONN); - init_b_st(chanp, 0); - chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_WAIT_BCONN); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DCONN"); + HL_LL(chanp, ISDN_STAT_DCONN); + init_b_st(chanp, 0); + chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); } static void @@ -427,14 +430,13 @@ lli_prep_dialout(struct FsmInst *fi, int event, void *arg) FsmDelTimer(&chanp->dial_timer, 73); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; - - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - if (chanp->leased) { - lli_init_bchan_out(fi, event, arg); - } else { - FsmChangeState(fi, ST_OUT_DIAL); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp); - } + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); + if (chanp->leased) { + lli_init_bchan_out(fi, event, arg); + } else { + FsmChangeState(fi, ST_OUT_DIAL); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp); + } } static void @@ -442,18 +444,17 @@ lli_resume(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - FsmDelTimer(&chanp->drel_timer, 60); - FsmDelTimer(&chanp->dial_timer, 73); - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = 0; - - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - if (chanp->leased) { - lli_init_bchan_out(fi, event, arg); - } else { - FsmChangeState(fi, ST_OUT_DIAL); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp); - } + FsmDelTimer(&chanp->drel_timer, 60); + FsmDelTimer(&chanp->dial_timer, 73); + chanp->l2_active_protocol = chanp->l2_protocol; + chanp->incoming = 0; + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); + if (chanp->leased) { + lli_init_bchan_out(fi, event, arg); + } else { + FsmChangeState(fi, ST_OUT_DIAL); + chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp); + } } static void @@ -521,15 +522,15 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_IN_ALERT_SENT); chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); break; - case 5: /* direct redirect */ - case 4: /* Proceeding desired */ + case 5: /* direct redirect */ + case 4: /* Proceeding desired */ FsmDelTimer(&chanp->drel_timer, 61); FsmChangeState(fi, ST_IN_PROCEED_SEND); - chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); - if (ret == 5) - { chanp->setup = ic.parm.setup; - chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); - } + chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); + if (ret == 5) { + chanp->setup = ic.parm.setup; + chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); + } break; case 2: /* Rejecting Call */ break; @@ -590,17 +591,17 @@ lli_init_bchan_in(struct FsmInst *fi, int event, void *arg) static void lli_setup_rsp(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_init_bchan_in(fi, event, arg); - } else { - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); + struct Channel *chanp = fi->userdata; + + if (chanp->leased) { + lli_init_bchan_in(fi, event, arg); + } else { + FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); #ifdef WANT_ALERT - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); #endif - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); - } + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); + } } /* Call suspend */ @@ -615,52 +616,85 @@ lli_suspend(struct FsmInst *fi, int event, void *arg) /* Call clearing */ +static void +lli_leased_hup(struct FsmInst *fi, struct Channel *chanp) +{ + isdn_ctrl ic; + + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_CAUSE; + ic.arg = chanp->chan; + sprintf(ic.parm.num, "L0010"); + chanp->cs->iif.statcallb(&ic); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + HL_LL(chanp, ISDN_STAT_DHUP); + lli_close(fi); +} + static void lli_disconnect_req(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_WAIT_DRELEASE); - chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); + if (chanp->leased) { + lli_leased_hup(fi, chanp); + } else { + FsmChangeState(fi, ST_WAIT_DRELEASE); + chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, + chanp->proc); + } } static void lli_disconnect_reject(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_WAIT_DRELEASE); - chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); + if (chanp->leased) { + lli_leased_hup(fi, chanp); + } else { + FsmChangeState(fi, ST_WAIT_DRELEASE); + chanp->proc->para.cause = 0x15; /* Call Rejected */ + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, + chanp->proc); + } } static void lli_dhup_close(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - lli_deliver_cause(chanp); - HL_LL(chanp, ISDN_STAT_DHUP); - - lli_close(fi); + if (chanp->leased) { + lli_leased_hup(fi, chanp); + } else { + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp); + HL_LL(chanp, ISDN_STAT_DHUP); + lli_close(fi); + } } static void lli_reject_req(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; + if (chanp->leased) { + lli_leased_hup(fi, chanp); + return; + } #ifndef ALERT_REJECT - chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); - lli_dhup_close(fi, event, arg); + chanp->proc->para.cause = 0x15; /* Call Rejected */ + chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); + lli_dhup_close(fi, event, arg); #else - FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); - FsmChangeState(fi, ST_IN_ALERT_SENT); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); + FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); + FsmChangeState(fi, ST_IN_ALERT_SENT); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); #endif } @@ -678,54 +712,45 @@ static void lli_start_disc(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - isdn_ctrl ic; if (chanp->leased) { - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L0010"); - chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); + lli_leased_hup(fi, chanp); } else { - lli_disconnect_req(fi, event, arg); + lli_disconnect_req(fi, event, arg); } } static void lli_rel_b_disc(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_start_disc(fi, event, arg); + struct Channel *chanp = fi->userdata; + + release_b_st(chanp); + lli_start_disc(fi, event, arg); } static void lli_bhup_disc(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); + struct Channel *chanp = fi->userdata; - lli_rel_b_disc(fi, event, arg); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + lli_rel_b_disc(fi, event, arg); } static void lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_WAIT_DCOMMAND); - chanp->data_open = 0; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - release_b_st(chanp); + FsmChangeState(fi, ST_WAIT_DCOMMAND); + chanp->data_open = 0; + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + release_b_st(chanp); } static void @@ -742,63 +767,65 @@ lli_release_bchan(struct FsmInst *fi, int event, void *arg) static void lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - release_b_st(chanp); - lli_dhup_close(fi, event, arg); + release_b_st(chanp); + lli_dhup_close(fi, event, arg); } static void lli_bhup_dhup(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - - lli_rel_b_dhup(fi, event, arg); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + lli_rel_b_dhup(fi, event, arg); } static void lli_abort(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - chanp->data_open = 0; - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); - - lli_bhup_dhup(fi, event, arg); + chanp->data_open = 0; + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + lli_bhup_dhup(fi, event, arg); } static void lli_release_req(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_D_REL_CNF); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc); + struct Channel *chanp = fi->userdata; + + if (chanp->leased) { + lli_leased_hup(fi, chanp); + } else { + FsmChangeState(fi, ST_WAIT_D_REL_CNF); + chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, + chanp->proc); + } } static void lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_release_req(fi, event, arg); + struct Channel *chanp = fi->userdata; + + release_b_st(chanp); + lli_release_req(fi, event, arg); } static void lli_bhup_release_req(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); + struct Channel *chanp = fi->userdata; - lli_rel_b_release_req(fi, event, arg); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + lli_rel_b_release_req(fi, event, arg); } @@ -825,7 +852,7 @@ lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg) if (chanp->debug & 1) link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); + HL_LL(chanp, ISDN_STAT_DHUP); } static void @@ -836,67 +863,65 @@ lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg) if (chanp->debug & 1) link_debug(chanp, 0, "STAT_DHUP"); HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); + lli_close(fi); } static void lli_error(struct FsmInst *fi, int event, void *arg) { - FsmChangeState(fi, ST_WAIT_DRELEASE); + FsmChangeState(fi, ST_WAIT_DRELEASE); } static void lli_failure_l(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; - FsmChangeState(fi, ST_NULL); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f); - chanp->cs->iif.statcallb(&ic); - HL_LL(chanp, ISDN_STAT_DHUP); - chanp->Flags = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); + FsmChangeState(fi, ST_NULL); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_CAUSE; + ic.arg = chanp->chan; + sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f); + chanp->cs->iif.statcallb(&ic); + HL_LL(chanp, ISDN_STAT_DHUP); + chanp->Flags = 0; + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } static void lli_rel_b_fail(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - release_b_st(chanp); - lli_failure_l(fi, event, arg); + release_b_st(chanp); + lli_failure_l(fi, event, arg); } static void lli_bhup_fail(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - - lli_rel_b_fail(fi, event, arg); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + lli_rel_b_fail(fi, event, arg); } static void lli_failure_a(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - chanp->data_open = 0; - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); - - lli_bhup_fail(fi, event, arg); + chanp->data_open = 0; + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + lli_bhup_fail(fi, event, arg); } - /* *INDENT-OFF* */ - static struct FsmNode fnlist[] HISAX_INITDATA = - { +/* *INDENT-OFF* */ +static struct FsmNode fnlist[] HISAX_INITDATA = +{ {ST_NULL, EV_DIAL, lli_prep_dialout}, {ST_NULL, EV_RESUME, lli_resume}, {ST_NULL, EV_SETUP_IND, lli_deliver_call}, @@ -959,10 +984,9 @@ lli_failure_a(struct FsmInst *fi, int event, void *arg) {ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close}, {ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready}, }; - /* *INDENT-ON* */ - +/* *INDENT-ON* */ - #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) +#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) HISAX_INITFUNC(void CallcNew(void)) @@ -985,9 +1009,9 @@ release_b_st(struct Channel *chanp) { struct PStack *st = chanp->b_st; - if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) { - chanp->bcs->BC_Close(chanp->bcs); - switch (chanp->l2_active_protocol) { + if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) { + chanp->bcs->BC_Close(chanp->bcs); + switch (chanp->l2_active_protocol) { case (ISDN_PROTO_L2_X75I): releasestack_isdnl2(st); break; @@ -995,10 +1019,10 @@ release_b_st(struct Channel *chanp) case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): case (ISDN_PROTO_L2_FAX): - releasestack_transl2(st); - break; - } - } + releasestack_transl2(st); + break; + } + } } struct Channel @@ -1013,10 +1037,10 @@ struct Channel else i=0; - if (!bch) - { i = 2; /* virtual channel */ - chanp += 2; - } + if (!bch) { + i = 2; /* virtual channel */ + chanp += 2; + } while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) { if (chanp->fi.state == ST_NULL) @@ -1025,17 +1049,17 @@ struct Channel i++; } - if (bch) /* number of channels is limited */ - { i = 2; /* virtual channel */ - chanp = st->lli.userdata; - chanp += i; - while (i < (2 + MAX_WAITING_CALLS)) { - if (chanp->fi.state == ST_NULL) - return (chanp); - chanp++; - i++; - } - } + if (bch) /* number of channels is limited */ { + i = 2; /* virtual channel */ + chanp = st->lli.userdata; + chanp += i; + while (i < (2 + MAX_WAITING_CALLS)) { + if (chanp->fi.state == ST_NULL) + return (chanp); + chanp++; + i++; + } + } return (NULL); } @@ -1053,19 +1077,19 @@ static void dchan_l3l4(struct PStack *st, int pr, void *arg) { struct l3_process *pc = arg; - struct IsdnCardState *cs = st->l1.hardware; + struct IsdnCardState *cs = st->l1.hardware; struct Channel *chanp; - if(!pc) - return; - - if (pr == (CC_SETUP | INDICATION)) { - if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) { - pc->para.cause = 0x11; /* User busy */ - pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc); - } else { - chanp->proc = pc; - pc->chan = chanp; + if(!pc) + return; + + if (pr == (CC_SETUP | INDICATION)) { + if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) { + pc->para.cause = 0x11; /* User busy */ + pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc); + } else { + chanp->proc = pc; + pc->chan = chanp; FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); } return; @@ -1121,8 +1145,8 @@ dchan_l3l4(struct PStack *st, int pr, void *arg) break; case (CC_REDIR | INDICATION): stat_redir_result(cs, chanp->chan, pc->redir_result); - break; - default: + break; + default: if (chanp->debug & 0x800) { HiSax_putstatus(chanp->cs, "Ch", "%d L3->L4 unknown primitiv %#x", @@ -1147,7 +1171,7 @@ init_PStack(struct PStack **stp) { (*stp)->l2.l2l1 = dummy_pstack; (*stp)->l2.l2l3 = dummy_pstack; (*stp)->l3.l3l2 = dummy_pstack; - (*stp)->l3.l3ml3 = dummy_pstack; + (*stp)->l3.l3ml3 = dummy_pstack; (*stp)->l3.l3l4 = dummy_pstack; (*stp)->lli.l4l3 = dummy_pstack; (*stp)->ma.layer = dummy_pstack; @@ -1230,8 +1254,8 @@ init_chan(int chan, struct IsdnCardState *csta) } int -CallcNewChan(struct IsdnCardState *csta) -{ int i; +CallcNewChan(struct IsdnCardState *csta) { + int i; chancount += 2; init_chan(0, csta); @@ -1240,8 +1264,7 @@ CallcNewChan(struct IsdnCardState *csta) for (i = 0; i < MAX_WAITING_CALLS; i++) init_chan(i+2,csta); - printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n"); - + printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n"); if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) { printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); csta->channel->d_st->lli.l4l3(csta->channel->d_st, @@ -1272,13 +1295,13 @@ CallcFreeChan(struct IsdnCardState *csta) for (i = 0; i < 2; i++) { FsmDelTimer(&csta->channel[i].drel_timer, 74); FsmDelTimer(&csta->channel[i].dial_timer, 75); - if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) - release_d_st(csta->channel + i); - if (csta->channel[i].b_st) { - release_b_st(csta->channel + i); - kfree(csta->channel[i].b_st); - csta->channel[i].b_st = NULL; - } else + if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) + release_d_st(csta->channel + i); + if (csta->channel[i].b_st) { + release_b_st(csta->channel + i); + kfree(csta->channel[i].b_st); + csta->channel[i].b_st = NULL; + } else printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i); if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { release_d_st(csta->channel + i); @@ -1311,7 +1334,7 @@ lldata_handler(struct PStack *st, int pr, void *arg) break; default: printk(KERN_WARNING "lldata_handler unknown primitive %#x\n", - pr); + pr); break; } } @@ -1341,7 +1364,7 @@ lltrans_handler(struct PStack *st, int pr, void *arg) break; default: printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n", - pr); + pr); break; } } @@ -1444,7 +1467,7 @@ leased_l4l3(struct PStack *st, int pr, void *arg) break; default: printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n", - pr); + pr); break; } } @@ -1598,7 +1621,7 @@ HiSax_command(isdn_ctrl * ic) if (!csta) { printk(KERN_ERR "HiSax: if_command %d called with invalid driverId %d!\n", - ic->command, ic->driver); + ic->command, ic->driver); return -ENODEV; } switch (ic->command) { @@ -1771,11 +1794,18 @@ HiSax_command(isdn_ctrl * ic) num = *(unsigned int *) ic->parm.num; chanp = csta->channel + (num & 1); num = num >>1; - test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); - chanp->d_st->l2.tei = num; - HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num); - printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n", - num); + if (num == 127) { + test_and_clear_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); + chanp->d_st->l2.tei = -1; + HiSax_putstatus(csta, "set card ", "in VAR TEI mode"); + printk(KERN_DEBUG "HiSax: set card in VAR TEI mode\n"); + } else { + test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); + chanp->d_st->l2.tei = num; + HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num); + printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n", + num); + } chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); break; @@ -1811,7 +1841,7 @@ HiSax_command(isdn_ctrl * ic) if (csta->auxcmd) return(csta->auxcmd(csta, ic)); printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", - (int) ic->arg); + (int) ic->arg); return (-EINVAL); } break; @@ -1839,11 +1869,11 @@ HiSax_command(isdn_ctrl * ic) break; /* protocol specific io commands */ - case (ISDN_CMD_PROT_IO): + case (ISDN_CMD_PROT_IO): for (st = csta->stlist; st; st = st->next) if (st->protocol == (ic->arg & 0xFF)) return(st->lli.l4l3_proto(st, ic)); - return(-EINVAL); + return(-EINVAL); break; default: if (csta->auxcmd) @@ -1865,7 +1895,7 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb) if (!csta) { printk(KERN_ERR - "HiSax: if_sendbuf called with invalid driverId!\n"); + "HiSax: if_sendbuf called with invalid driverId!\n"); return -ENODEV; } chanp = csta->channel + chan; diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index a75810f026ac..8d389c6237ab 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,10 +1,21 @@ -/* $Id: config.c,v 2.40 1999/10/30 13:09:45 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 * @@ -202,6 +213,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 * @@ -217,6 +229,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); @@ -352,6 +365,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 @@ -529,9 +549,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)); @@ -687,6 +707,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 @@ -994,7 +1018,7 @@ HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs)) while (cnt) { cs->cardmsg(cs, CARD_INIT, NULL); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); /* Timeout 10ms */ schedule_timeout((10*HZ)/1000); restore_flags(flags); @@ -1208,6 +1232,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); @@ -1515,6 +1544,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/diva.c b/drivers/isdn/hisax/diva.c index f1161e63de6a..5dc86894235e 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.17 1999/09/04 06:20:06 keil Exp $ +/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $ * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * @@ -12,6 +12,10 @@ * * * $Log: diva.c,v $ + * Revision 1.18 1999/12/19 13:09:41 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.17 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -80,7 +84,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.17 $"; +const char *Diva_revision = "$Revision: 1.18 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -750,30 +754,30 @@ reset_diva(struct IsdnCardState *cs) sti(); if (cs->subtyp == DIVA_IPAC_ISA) { writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); } else if (cs->subtyp == DIVA_IPAC_PCI) { unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + PITA_MISC_REG); *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); *ireg = PITA_PARA_MPX_MODE; - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0); } else { /* DIVA 2.0 */ cs->hw.diva.ctrl_reg = 0; /* Reset On */ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->subtyp == DIVA_ISA) cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 4dbe40c38462..1e425ccc5806 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -1,4 +1,4 @@ -/* $Id: elsa.c,v 2.19 1999/09/04 06:20:06 keil Exp $ +/* $Id: elsa.c,v 2.20 1999/12/19 13:09:42 keil Exp $ * elsa.c low level stuff for Elsa isdn cards * @@ -14,6 +14,10 @@ * for ELSA PCMCIA support * * $Log: elsa.c,v $ + * Revision 2.20 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 2.19 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -99,7 +103,7 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.19 $"; +const char *Elsa_revision = "$Revision: 2.20 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", @@ -578,10 +582,10 @@ reset_elsa(struct IsdnCardState *cs) save_flags(flags); sti(); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ restore_flags(flags); @@ -785,7 +789,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) cs->hw.elsa.status |= ELSA_TIMER_AKTIV; byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); byteout(cs->hw.elsa.timer, 0); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((110*HZ)/1000); restore_flags(flags); cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c index aa0ff4adbd14..665fa2c74a1a 100644 --- a/drivers/isdn/hisax/fsm.c +++ b/drivers/isdn/hisax/fsm.c @@ -1,12 +1,15 @@ -/* $Id: fsm.c,v 1.10 1998/11/15 23:54:39 keil Exp $ +/* $Id: fsm.c,v 1.11 1999/12/23 15:09:32 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: fsm.c,v $ + * Revision 1.11 1999/12/23 15:09:32 keil + * change email + * * Revision 1.10 1998/11/15 23:54:39 keil * changes from 2.0 * diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index bb388c5c28c7..2b22cdfea09a 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1,11 +1,14 @@ -/* $Id: hfc_2bds0.c,v 1.10 1999/10/14 20:25:28 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hfc_2bds0.c,v $ + * Revision 1.11 1999/12/23 15:09:32 keil + * change email + * * Revision 1.10 1999/10/14 20:25:28 keil * add a statistic for error monitoring * diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h index d11e8b50363e..32f703662ae7 100644 --- a/drivers/isdn/hisax/hfc_2bds0.h +++ b/drivers/isdn/hisax/hfc_2bds0.h @@ -1,11 +1,14 @@ -/* $Id: hfc_2bds0.h,v 1.2 1998/02/02 13:26:15 keil Exp $ +/* $Id: hfc_2bds0.h,v 1.3 1999/12/23 15:09:32 keil Exp $ * specific defines for CCD's HFC 2BDS0 * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hfc_2bds0.h,v $ + * Revision 1.3 1999/12/23 15:09:32 keil + * change email + * * Revision 1.2 1998/02/02 13:26:15 keil * New * diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index 6620b90ecee3..f3edefa3e4e4 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.10 1999/10/14 20:25:28 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $ * specific routines for CCD's HFC 2BS0 * @@ -6,6 +6,13 @@ * * * $Log: hfc_2bs0.c,v $ + * Revision 1.12 1999/12/19 14:17:12 keil + * fix compiler warning + * + * Revision 1.11 1999/11/21 12:41:18 werner + * + * Implemented full audio support + * * Revision 1.10 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -210,7 +217,7 @@ hfc_empty_fifo(struct BCState *bcs, int count) WaitForBusy(cs); return (NULL); } - if (count < 4) { + if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfc_empty_fifo: incoming packet too small"); cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); @@ -225,47 +232,55 @@ hfc_empty_fifo(struct BCState *bcs, int count) #endif return (NULL); } - if (!(skb = dev_alloc_skb(count - 3))) + if (bcs->mode == L1_MODE_TRANS) + count -= 1; + else + count -= 3; + if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HFC: receive out of memory\n"); else { - ptr = skb_put(skb, count - 3); + ptr = skb_put(skb, count); idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); while ((idx < count - 3) && WaitNoBusy(cs)) { *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } - if (idx != count - 3) { + if (idx != count) { debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); dev_kfree_skb(skb); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); + if (bcs->mode != L1_MODE_TRANS) { + WaitNoBusy(cs); + stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | + HFC_CHANNEL(bcs->channel)); + WaitForBusy(cs); + } return (NULL); } - WaitNoBusy(cs); - chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8); - WaitNoBusy(cs); - chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", - bcs->channel, chksum, stat); - if (stat) { - debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); - skb = NULL; + if (bcs->mode != L1_MODE_TRANS) { + WaitNoBusy(cs); + chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8); + WaitNoBusy(cs); + chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); + WaitNoBusy(cs); + stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", + bcs->channel, chksum, stat); + if (stat) { + debugl1(cs, "FIFO CRC error"); + dev_kfree_skb(skb); + skb = NULL; #ifdef ERROR_STATISTIC - bcs->err_crc++; + bcs->err_crc++; #endif + } + WaitNoBusy(cs); + stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | + HFC_CHANNEL(bcs->channel)); + WaitForBusy(cs); } - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); } return (skb); } @@ -277,6 +292,7 @@ hfc_fill_fifo(struct BCState *bcs) long flags; int idx, fcnt; int count; + int z1, z2; u_char cip; if (!bcs->tx_skb) @@ -288,29 +304,39 @@ hfc_fill_fifo(struct BCState *bcs) cli(); cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel); if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); - WaitForBusy(cs); + cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); + WaitForBusy(cs); } WaitNoBusy(cs); - bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", - bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, - bcs->hw.hfc.send[bcs->hw.hfc.f1]); - fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; - if (fcnt < 0) - fcnt += 32; - if (fcnt > 30) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo more as 30 frames"); - restore_flags(flags); - return; - } - count = GetFreeFifoBytes(bcs); + if (bcs->mode != L1_MODE_TRANS) { + bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); + cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel); + WaitNoBusy(cs); + bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); + bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", + bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, + bcs->hw.hfc.send[bcs->hw.hfc.f1]); + fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; + if (fcnt < 0) + fcnt += 32; + if (fcnt > 30) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo more as 30 frames"); + restore_flags(flags); + return; + } + count = GetFreeFifoBytes(bcs); + } + else { + WaitForBusy(cs); + z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); + z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); + count = z1 - z2; + if (count < 0) + count += cs->hw.hfc.fifosize; + } /* L1_MODE_TRANS */ if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)", bcs->channel, bcs->tx_skb->len, @@ -335,9 +361,11 @@ hfc_fill_fifo(struct BCState *bcs) count = -1; dev_kfree_skb(bcs->tx_skb); bcs->tx_skb = NULL; - WaitForBusy(cs); - WaitNoBusy(cs); - cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); + if (bcs->mode != L1_MODE_TRANS) { + WaitForBusy(cs); + WaitNoBusy(cs); + cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); + } if (bcs->st->lli.l1writewakeup && (count >= 0)) bcs->st->lli.l1writewakeup(bcs->st, count); test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); @@ -366,32 +394,39 @@ main_irq_hfc(struct BCState *bcs) WaitForBusy(cs); } WaitNoBusy(cs); - f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d f1(%d) f2(%d)", - bcs->channel, f1, f2); + receive = 0; + if (bcs->mode == L1_MODE_HDLC) { + f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); + cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); + WaitNoBusy(cs); + f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); + if (f1 != f2) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d f1(%d) f2(%d)", + bcs->channel, f1, f2); + receive = 1; + } + } + if (receive || (bcs->mode == L1_MODE_TRANS)) { WaitForBusy(cs); z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); rcnt = z1 - z2; if (rcnt < 0) rcnt += cs->hw.hfc.fifosize; - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, z1, z2, rcnt); -/* sti(); */ - if ((skb = hfc_empty_fifo(bcs, rcnt))) { - skb_queue_tail(&bcs->rqueue, skb); - hfc_sched_event(bcs, B_RCVBUFREADY); + if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) { + rcnt++; + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", + bcs->channel, z1, z2, rcnt); + /* sti(); */ + if ((skb = hfc_empty_fifo(bcs, rcnt))) { + skb_queue_tail(&bcs->rqueue, skb); + hfc_sched_event(bcs, B_RCVBUFREADY); + } } receive = 1; - } else - receive = 0; + } restore_flags(flags); udelay(1); cli(); @@ -432,12 +467,19 @@ mode_hfc(struct BCState *bcs, int mode, int bc) switch (mode) { case (L1_MODE_NULL): - if (bc) + if (bc) { + cs->hw.hfc.ctmt &= ~1; cs->hw.hfc.isac_spcr &= ~0x03; - else + } + else { + cs->hw.hfc.ctmt &= ~2; cs->hw.hfc.isac_spcr &= ~0x0c; + } break; case (L1_MODE_TRANS): + cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */ + cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); + hfc_clear_fifo(bcs); /* complete fifo clear */ if (bc) { cs->hw.hfc.ctmt |= 1; cs->hw.hfc.isac_spcr &= ~0x03; @@ -462,7 +504,7 @@ mode_hfc(struct BCState *bcs, int mode, int bc) } cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr); - if (mode) + if (mode == L1_MODE_HDLC) hfc_clear_fifo(bcs); } diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h index cce8e4a35076..981ae7cb3d68 100644 --- a/drivers/isdn/hisax/hfc_2bs0.h +++ b/drivers/isdn/hisax/hfc_2bs0.h @@ -1,11 +1,14 @@ -/* $Id: hfc_2bs0.h,v 1.1 1997/09/11 17:31:34 keil Exp $ +/* $Id: hfc_2bs0.h,v 1.2 1999/12/23 15:09:32 keil Exp $ * specific defines for CCD's HFC 2BS0 * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hfc_2bs0.h,v $ + * Revision 1.2 1999/12/23 15:09:32 keil + * change email + * * Revision 1.1 1997/09/11 17:31:34 keil * Common part for HFC 2BS0 based cards * diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 518c1670aec7..76f353861c19 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.23 1999/11/07 17:01:55 keil Exp $ +/* $Id: hfc_pci.c,v 1.26 2000/02/09 20:22:55 werner Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -23,6 +23,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.c,v $ + * Revision 1.26 2000/02/09 20:22:55 werner + * + * Updated PCI-ID table + * + * Revision 1.25 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * + * Revision 1.24 1999/11/17 23:59:55 werner + * + * removed unneeded data + * * Revision 1.23 1999/11/07 17:01:55 keil * fix for 2.3 pci structs * @@ -114,7 +126,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.23 $"; +static const char *hfcpci_revision = "$Revision: 1.26 $"; /* table entry in the PCI devices list */ typedef struct { @@ -143,26 +155,12 @@ static const PCI_ENTRY id_list[] = {0x1051, 0x0100, "Motorola MC145575", "MC145575"}, {0x1397, 0xB100, "Seyeon", "B100"}, {0x15B0, 0x2BD0, "Zoltrix", "2BD0"}, + {0x114f, 0x71, "Digi intl.","Digicom"}, {0, 0, NULL, NULL}, }; #if CONFIG_PCI -/*****************************/ -/* release D- and B-channels */ -/*****************************/ -void -releasehfcpci(struct IsdnCardState *cs) -{ - if (cs->bcs[0].hw.hfc.send) { - kfree(cs->bcs[0].hw.hfc.send); - cs->bcs[0].hw.hfc.send = NULL; - } - if (cs->bcs[1].hw.hfc.send) { - kfree(cs->bcs[1].hw.hfc.send); - cs->bcs[1].hw.hfc.send = NULL; - } -} /******************************************/ /* free hardware resources used by driver */ @@ -179,13 +177,12 @@ release_io_hfcpci(struct IsdnCardState *cs) restore_flags(flags); Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ #if CONFIG_PCI pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ #endif /* CONFIG_PCI */ - releasehfcpci(cs); del_timer(&cs->hw.hfcpci.timer); kfree(cs->hw.hfcpci.share_start); cs->hw.hfcpci.share_start = NULL; @@ -211,10 +208,10 @@ reset_hfcpci(struct IsdnCardState *cs) pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */ Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ if (Read_hfc(cs, HFCPCI_STATUS) & 2) printk(KERN_WARNING "HFC-PCI init bit busy\n"); @@ -1647,24 +1644,6 @@ hfcpci_bh(struct IsdnCardState *cs) } -/*************************************/ -/* Alloc memory send data for queues */ -/*************************************/ -__initfunc(unsigned int - *init_send_hfcpci(int cnt)) -{ - int i, *send; - - if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hfcpci.send\n"); - return (NULL); - } - for (i = 0; i < cnt; i++) - send[i] = 0x1fff; - return (send); -} - /********************************/ /* called for card init message */ /********************************/ @@ -1676,10 +1655,6 @@ __initfunc(void cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); cs->tqueue.routine = (void *) (void *) hfcpci_bh; - if (!cs->bcs[0].hw.hfc.send) - cs->bcs[0].hw.hfc.send = init_send_hfcpci(32); - if (!cs->bcs[1].hw.hfc.send) - cs->bcs[1].hw.hfc.send = init_send_hfcpci(32); cs->BC_Send_Data = &hfcpci_send_data; cs->bcs[0].BC_SetStack = setstack_2b; cs->bcs[1].BC_SetStack = setstack_2b; @@ -1712,7 +1687,7 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) inithfcpci(cs); save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ /* now switch timer interrupt off */ cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; @@ -1746,8 +1721,6 @@ __initfunc(int printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); #if CONFIG_PCI cs->hw.hfcpci.int_s1 = 0; - cs->bcs[0].hw.hfc.send = NULL; - cs->bcs[1].hw.hfc.send = NULL; cs->dc.hfcpci.ph_state = 0; cs->hw.hfcpci.fifo = 255; if (cs->typ == ISDN_CTYPE_HFC_PCI) { diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c new file mode 100644 index 000000000000..ee14af806992 --- /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(); + set_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(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ + Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ + set_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(); + set_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/hfcscard.c b/drivers/isdn/hisax/hfcscard.c index 8654857fdef6..7015f4bb57e0 100644 --- a/drivers/isdn/hisax/hfcscard.c +++ b/drivers/isdn/hisax/hfcscard.c @@ -1,4 +1,4 @@ -/* $Id: hfcscard.c,v 1.5 1999/09/04 06:20:06 keil Exp $ +/* $Id: hfcscard.c,v 1.6 1999/12/19 13:09:42 keil Exp $ * hfcscard.c low level stuff for hfcs based cards (Teles3c, ACER P10) * @@ -6,6 +6,10 @@ * * * $Log: hfcscard.c,v $ + * Revision 1.6 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.5 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -30,7 +34,7 @@ extern const char *CardType[]; -static const char *hfcs_revision = "$Revision: 1.5 $"; +static const char *hfcs_revision = "$Revision: 1.6 $"; static void hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs) @@ -85,13 +89,13 @@ reset_hfcs(struct IsdnCardState *cs) cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); cs->hw.hfcD.cirm = 0; if (cs->typ == ISDN_CTYPE_TELES3C) cs->hw.hfcD.cirm |= HFCD_MEM8K; cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); if (cs->typ == ISDN_CTYPE_TELES3C) cs->hw.hfcD.cirm |= HFCD_INTB; @@ -138,7 +142,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) init2bds0(cs); save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((80*HZ)/1000); cs->hw.hfcD.ctmt |= HFCD_TIM800; cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 0c67d5c4a213..6f5b5615c5f7 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/hscx.h b/drivers/isdn/hisax/hscx.h index 08801bc736ca..00b566a44193 100644 --- a/drivers/isdn/hisax/hscx.h +++ b/drivers/isdn/hisax/hscx.h @@ -1,11 +1,14 @@ -/* $Id: hscx.h,v 1.4 1998/04/15 16:45:34 keil Exp $ +/* $Id: hscx.h,v 1.5 1999/12/23 15:09:32 keil Exp $ * hscx.h HSCX specific defines * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hscx.h,v $ + * Revision 1.5 1999/12/23 15:09:32 keil + * change email + * * Revision 1.4 1998/04/15 16:45:34 keil * new init code * diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h index 82c5fa8f89a3..34a85dd6b857 100644 --- a/drivers/isdn/hisax/ipac.h +++ b/drivers/isdn/hisax/ipac.h @@ -1,11 +1,14 @@ -/* $Id: ipac.h,v 1.3 1998/04/15 16:48:09 keil Exp $ +/* $Id: ipac.h,v 1.4 1999/12/23 15:09:32 keil Exp $ * ipac.h IPAC specific defines * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: ipac.h,v $ + * Revision 1.4 1999/12/23 15:09:32 keil + * change email + * * Revision 1.3 1998/04/15 16:48:09 keil * IPAC_ATX added * diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h index bed887d4fbcb..a8a46e13508c 100644 --- a/drivers/isdn/hisax/isac.h +++ b/drivers/isdn/hisax/isac.h @@ -1,11 +1,14 @@ -/* $Id: isac.h,v 1.5 1998/05/25 12:58:03 keil Exp $ +/* $Id: isac.h,v 1.6 1999/12/23 15:09:32 keil Exp $ * isac.h ISAC specific defines * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: isac.h,v $ + * Revision 1.6 1999/12/23 15:09:32 keil + * change email + * * Revision 1.5 1998/05/25 12:58:03 keil * HiSax golden code from certification, Don't use !!! * No leased lines, no X75, but many changes. diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 417f2157dbde..bfff8670754c 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.7 1999/10/14 20:25:29 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,12 @@ * * * $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 + * * Revision 1.7 1999/10/14 20:25:29 keil * add a statistic for error monitoring * @@ -42,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 @@ -442,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) { @@ -512,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); @@ -544,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); } @@ -603,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; @@ -613,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); } @@ -639,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"}; @@ -700,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); @@ -769,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 @@ -788,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; @@ -815,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; @@ -831,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; @@ -866,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; @@ -876,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; @@ -896,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; @@ -911,18 +1286,16 @@ 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; } - if (!sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar pump status req dp%d failed", - bcs->hw.isar.dpath); - } + udelay(1000); + sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); + udelay(1000); } static void @@ -933,44 +1306,30 @@ 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; } - if (!sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar buf stat req dp%d failed", - bcs->hw.isar.dpath); - } + udelay(1000); + sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); + udelay(1000); } static void @@ -995,15 +1354,10 @@ setup_iom2(struct BCState *bcs) { cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV; break; } - if (!sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg)) { - if (cs->debug) - debugl1(cs, "isar iom2 dp%d failed", bcs->hw.isar.dpath); - } - if (!sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL)) { - if (cs->debug) - debugl1(cs, "isar IOM2 cfg req dp%d failed", - bcs->hw.isar.dpath); - } + sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); + udelay(1000); + sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); + udelay(1000); } int @@ -1041,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; @@ -1066,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) { @@ -1076,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; @@ -1147,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; @@ -1185,6 +1638,7 @@ close_isarstate(struct BCState *bcs) debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY"); } } + del_timer(&bcs->hw.isar.ftimer); } int @@ -1206,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); } @@ -1226,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/isurf.c b/drivers/isdn/hisax/isurf.c index 4ee5831fed52..18a7cfc58b57 100644 --- a/drivers/isdn/hisax/isurf.c +++ b/drivers/isdn/hisax/isurf.c @@ -1,10 +1,14 @@ -/* $Id: isurf.c,v 1.7 1999/11/14 23:37:03 keil Exp $ +/* $Id: isurf.c,v 1.8 1999/12/19 13:09:42 keil Exp $ * isurf.c low level stuff for Siemens I-Surf/I-Talk cards * * Author Karsten Keil (keil@isdn4linux.de) * * $Log: isurf.c,v $ + * Revision 1.8 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.7 1999/11/14 23:37:03 keil * new ISA memory mapped IO * @@ -40,7 +44,7 @@ extern const char *CardType[]; -static const char *ISurf_revision = "$Revision: 1.7 $"; +static const char *ISurf_revision = "$Revision: 1.8 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -162,10 +166,10 @@ reset_isurf(struct IsdnCardState *cs, u_char chips) byteout(cs->hw.isurf.reset, chips); /* Reset On */ save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } 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 035ee54ca32d..9fa10e326dd9 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.20 1999/10/11 22:16:27 keil Exp $ +/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,16 @@ * 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 + * * Revision 2.20 1999/10/11 22:16:27 keil * Suspend/Resume is possible without explicit ID too * @@ -91,9 +101,10 @@ #include "isdnl3.h" #include "l3dss1.h" #include +#include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.20 $"; +const char *dss1_revision = "$Revision: 2.22 $"; #define EXT_BEARER_CAPS 1 @@ -668,34 +679,36 @@ l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) } static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, + IE_USER_USER, -1}; static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_CONNECT_PN, - IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, -1}; + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, + IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_USER_USER, -1}; -static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; +static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLED_PN, -1}; static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; -static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, IE_USER_USER, -1}; +static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, + IE_SIGNAL, IE_USER_USER, -1}; /* a RELEASE_COMPLETE with errors don't require special actions -static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_USER_USER, -1}; +static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; */ static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_DISPLAY, -1}; 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_CALLING_PN, - IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_LLC, IE_HLC, - IE_USER_USER, -1}; + IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, + 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, -1}; + IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | IE_MANDATORY, IE_DISPLAY, -1}; static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; @@ -1272,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; @@ -1283,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 */ @@ -1452,12 +1470,25 @@ 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 { - *p++ = 0x7c; - *p++ = 0x02; - *p++ = 0x88; - *p++ = 0x90; + switch (pc->para.setup.si1) { + case 1: /* Telephony */ + *p++ = 0x7c; /* BC-IE-code */ + *p++ = 0x3; /* Length */ + *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + *p++ = 0xa3; /* A-Law Audio */ + break; + case 5: /* Datatransmission 64k, BTX */ + case 7: /* Datatransmission 64k */ + default: + *p++ = 0x7c; /* BC-IE-code */ + *p++ = 0x2; /* Length */ + *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ + *p++ = 0x90; /* Circuit-Mode 64kbps */ + break; + } #endif } #endif @@ -2738,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); } @@ -2747,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/netjet.c b/drivers/isdn/hisax/netjet.c index 3b502f7dbe4e..3855625bd694 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.16 1999/10/14 20:25:29 keil Exp $ +/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $ * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * @@ -7,6 +7,10 @@ * Thanks to Traverse Technologie Australia for documents and informations * * $Log: netjet.c,v $ + * Revision 1.17 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.16 1999/10/14 20:25:29 keil * add a statistic for error monitoring * @@ -81,7 +85,7 @@ extern const char *CardType[]; -const char *NETjet_revision = "$Revision: 1.16 $"; +const char *NETjet_revision = "$Revision: 1.17 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -1054,11 +1058,11 @@ reset_netjet(struct IsdnCardState *cs) sti(); cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ restore_flags(flags); cs->hw.njet.auxd = 0; diff --git a/drivers/isdn/hisax/rawhdlc.c b/drivers/isdn/hisax/rawhdlc.c index 17ac5c60200c..5a8b0591e178 100644 --- a/drivers/isdn/hisax/rawhdlc.c +++ b/drivers/isdn/hisax/rawhdlc.c @@ -1,8 +1,8 @@ -/* $Id: rawhdlc.c,v 1.3 1998/06/17 19:51:21 he Exp $ +/* $Id: rawhdlc.c,v 1.4 1999/12/23 15:09:32 keil Exp $ * rawhdlc.c support routines for cards that don't support HDLC * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * Brent Baccala * * diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c index 955a9a4de400..b642d759c54c 100644 --- a/drivers/isdn/hisax/saphir.c +++ b/drivers/isdn/hisax/saphir.c @@ -1,4 +1,4 @@ -/* $Id: saphir.c,v 1.4 1999/09/04 06:20:06 keil Exp $ +/* $Id: saphir.c,v 1.5 1999/12/19 13:09:42 keil Exp $ * saphir.c low level stuff for HST Saphir 1 * @@ -8,6 +8,10 @@ * * * $Log: saphir.c,v $ + * Revision 1.5 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.4 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -29,7 +33,7 @@ #include "isdnl1.h" extern const char *CardType[]; -static char *saphir_rev = "$Revision: 1.4 $"; +static char *saphir_rev = "$Revision: 1.5 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -237,10 +241,10 @@ saphir_reset(struct IsdnCardState *cs) save_flags(flags); sti(); byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ restore_flags(flags); byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index b93895ea19bc..dd1c53d044be 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.18 1999/11/13 21:25:03 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,13 @@ * 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 + * * Revision 1.18 1999/11/13 21:25:03 keil * Support for Speedfax+ PCI * @@ -110,7 +117,7 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.18 $"; +const char *Sedlbauer_revision = "$Revision: 1.20 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", @@ -490,10 +497,10 @@ reset_sedlbauer(struct IsdnCardState *cs) writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20); save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0); writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff); @@ -506,20 +513,20 @@ reset_sedlbauer(struct IsdnCardState *cs) byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); save_flags(flags); sti(); - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_UNINTERRUPTIBLE; schedule_timeout((20*HZ)/1000); byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_UNINTERRUPTIBLE; schedule_timeout((20*HZ)/1000); restore_flags(flags); } else { byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } @@ -659,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); @@ -675,7 +680,7 @@ setup_sedlbauer(struct IsdnCard *card)) byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on); save_flags(flags); sti(); - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_UNINTERRUPTIBLE; schedule_timeout((10*HZ)/1000); byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off); restore_flags(flags); diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c index 91a6a6ae18da..03ecedb931f5 100644 --- a/drivers/isdn/hisax/sportster.c +++ b/drivers/isdn/hisax/sportster.c @@ -1,12 +1,19 @@ -/* $Id: sportster.c,v 1.10 1999/09/04 06:20:06 keil Exp $ +/* $Id: sportster.c,v 1.12 1999/12/23 15:09:32 keil Exp $ * sportster.c low level stuff for USR Sportster internal TA * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation * * $Log: sportster.c,v $ + * Revision 1.12 1999/12/23 15:09:32 keil + * change email + * + * Revision 1.11 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.10 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -46,7 +53,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *sportster_revision = "$Revision: 1.10 $"; +const char *sportster_revision = "$Revision: 1.12 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -180,11 +187,11 @@ reset_sportster(struct IsdnCardState *cs) byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c index c34dc5613b2b..bbf59316d6ce 100644 --- a/drivers/isdn/hisax/teleint.c +++ b/drivers/isdn/hisax/teleint.c @@ -1,4 +1,4 @@ -/* $Id: teleint.c,v 1.11 1999/09/04 06:20:06 keil Exp $ +/* $Id: teleint.c,v 1.12 1999/12/19 13:09:42 keil Exp $ * teleint.c low level stuff for TeleInt isdn cards * @@ -6,6 +6,10 @@ * * * $Log: teleint.c,v $ + * Revision 1.12 1999/12/19 13:09:42 keil + * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for + * signal proof delays + * * Revision 1.11 1999/09/04 06:20:06 keil * Changes from kernel set_current_state() * @@ -51,7 +55,7 @@ extern const char *CardType[]; -const char *TeleInt_revision = "$Revision: 1.11 $"; +const char *TeleInt_revision = "$Revision: 1.12 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -260,11 +264,11 @@ reset_TeleInt(struct IsdnCardState *cs) byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */ save_flags(flags); sti(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((30*HZ)/1000); cs->hw.hfc.cirm &= ~HFC_RESET; byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((10*HZ)/1000); restore_flags(flags); } diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c index 8e8017bbb5af..c3a4a05ebbdf 100644 --- a/drivers/isdn/hisax/teles0.c +++ b/drivers/isdn/hisax/teles0.c @@ -1,15 +1,18 @@ -/* $Id: teles0.c,v 2.10 1999/11/14 23:37:03 keil Exp $ +/* $Id: teles0.c,v 2.11 1999/12/23 15:09:32 keil Exp $ * teles0.c low level stuff for Teles Memory IO isdn cards * based on the teles driver from Jan den Ouden * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Jan den Ouden * Fritz Elfert * Beat Doebeli * * $Log: teles0.c,v $ + * Revision 2.11 1999/12/23 15:09:32 keil + * change email + * * Revision 2.10 1999/11/14 23:37:03 keil * new ISA memory mapped IO * @@ -61,7 +64,7 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.10 $"; +const char *teles0_revision = "$Revision: 2.11 $"; #define TELES_IOMEM_SIZE 0x400 #define byteout(addr,val) outb(val,addr) diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index 0db245abcfc8..171aeb07d72f 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -1,16 +1,22 @@ -/* $Id: teles3.c,v 2.13 1999/08/30 12:01:28 keil Exp $ +/* $Id: teles3.c,v 2.15 2000/02/03 16:40:10 keil Exp $ * teles3.c low level stuff for Teles 16.3 & PNP isdn cards * * based on the teles driver from Jan den Ouden * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Jan den Ouden * Fritz Elfert * Beat Doebeli * * $Log: teles3.c,v $ + * Revision 2.15 2000/02/03 16:40:10 keil + * Fix teles pcmcia + * + * Revision 2.14 1999/12/23 15:09:32 keil + * change email + * * Revision 2.13 1999/08/30 12:01:28 keil * HW version v1.3 support * @@ -88,7 +94,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.13 $"; +const char *teles3_revision = "$Revision: 2.15 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -225,7 +231,7 @@ void release_io_teles3(struct IsdnCardState *cs) { if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - release_region(cs->hw.teles3.hscx[0], 97); + release_region(cs->hw.teles3.hscx[1], 96); } else { if (cs->hw.teles3.cfg_reg) { if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { @@ -367,15 +373,15 @@ setup_teles3(struct IsdnCard *card)) cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - if (check_region((cs->hw.teles3.hscx[0]), 97)) { + if (check_region((cs->hw.teles3.hscx[1]), 96 )) { printk(KERN_WARNING "HiSax: %s ports %x-%x already in use\n", CardType[cs->typ], - cs->hw.teles3.hscx[0], - cs->hw.teles3.hscx[0] + 96); + cs->hw.teles3.hscx[1], + cs->hw.teles3.hscx[1] + 96); return (0); } else - request_region(cs->hw.teles3.hscx[0], 97, "HiSax Teles PCMCIA"); + request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA"); } else { if (cs->hw.teles3.cfg_reg) { if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index 3486b470ad83..e90510b35a4d 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -1,12 +1,15 @@ -/* $Id: telespci.c,v 2.10 1999/11/15 14:20:05 keil Exp $ +/* $Id: telespci.c,v 2.11 1999/12/23 15:09:32 keil Exp $ * telespci.c low level stuff for Teles PCI isdn cards * * Author Ton van Rosmalen - * Karsten Keil (keil@temic-ech.spacenet.de) + * Karsten Keil (keil@isdn4linux.de) * * * $Log: telespci.c,v $ + * Revision 2.11 1999/12/23 15:09:32 keil + * change email + * * Revision 2.10 1999/11/15 14:20:05 keil * 64Bit compatibility * @@ -47,7 +50,7 @@ #include extern const char *CardType[]; -const char *telespci_revision = "$Revision: 2.10 $"; +const char *telespci_revision = "$Revision: 2.11 $"; #define ZORAN_PO_RQ_PEN 0x02000000 #define ZORAN_PO_WR 0x00800000 diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile new file mode 100644 index 000000000000..626a6deaae6e --- /dev/null +++ b/drivers/isdn/hysdn/Makefile @@ -0,0 +1,24 @@ +SUB_DIRS := +MOD_SUB_DIRS := +ALL_SUB_DIRS := + +L_OBJS := +LX_OBJS := +M_OBJS := +MX_OBJS := +O_OBJS := +OX_OBJS := +L_TARGET := +O_TARGET := + +ifeq ($(CONFIG_PROC_FS),y) + ifeq ($(CONFIG_HYSDN),y) + M_OBJS += hysdn.o + O_TARGET += hysdn.o + O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o + OX_OBJS += hysdn_init.o + endif +endif + +include $(TOPDIR)/Rules.make + diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c new file mode 100644 index 000000000000..31f91531be61 --- /dev/null +++ b/drivers/isdn/hysdn/boardergo.c @@ -0,0 +1,468 @@ +/* $Id: boardergo.c,v 1.1 2000/02/10 19:45:18 werner Exp $ + + * Linux driver for HYSDN cards, specific routines for ergo type boards. + * + * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same + * DPRAM interface and layout with only minor differences all related + * stuff is done here, not in separate modules. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: boardergo.c,v $ + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" +#include "boardergo.h" + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +/***************************************************/ +/* The cards interrupt handler. Called from system */ +/***************************************************/ +static void +ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + hysdn_card *card = dev_id; /* parameter from irq */ + tErgDpram *dpr; + ulong flags; + uchar volatile b; + + if (!card) + return; /* error -> spurious interrupt */ + if (!card->irq_enabled) + return; /* other device interrupting or irq switched off */ + + save_flags(flags); + cli(); /* no further irqs allowed */ + + if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) { + restore_flags(flags); /* restore old state */ + return; /* no interrupt requested by E1 */ + } + /* clear any pending ints on the board */ + dpr = card->dpram; + b = dpr->ToPcInt; /* clear for ergo */ + b |= dpr->ToPcIntMetro; /* same for metro */ + b |= dpr->ToHyInt; /* and for champ */ + + /* start kernel task immediately after leaving all interrupts */ + if (!card->hw_lock) { + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + restore_flags(flags); +} /* ergo_interrupt */ + +/******************************************************************************/ +/* ergo_irq_bh is the function called by the immediate kernel task list after */ +/* being activated with queue_task and no interrupts active. This task is the */ +/* only one handling data transfer from or to the card after booting. The task */ +/* may be queued from everywhere (interrupts included). */ +/******************************************************************************/ +static void +ergo_irq_bh(hysdn_card * card) +{ + tErgDpram *dpr; + int again; + ulong flags; + + if (card->state != CARD_STATE_RUN) + return; /* invalid call */ + + dpr = card->dpram; /* point to DPRAM */ + + save_flags(flags); + cli(); + if (card->hw_lock) { + restore_flags(flags); /* hardware currently unavailable */ + return; + } + card->hw_lock = 1; /* we now lock the hardware */ + + do { + sti(); /* reenable other ints */ + again = 0; /* assume loop not to be repeated */ + + if (!dpr->ToHyFlag) { + /* we are able to send a buffer */ + + if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel, + ERG_TO_HY_BUF_SIZE)) { + dpr->ToHyFlag = 1; /* enable tx */ + again = 1; /* restart loop */ + } + } /* we are able to send a buffer */ + if (dpr->ToPcFlag) { + /* a message has arrived for us, handle it */ + + if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) { + dpr->ToPcFlag = 0; /* we worked the data */ + again = 1; /* restart loop */ + } + } /* a message has arrived for us */ + cli(); /* no further ints */ + if (again) { + dpr->ToHyInt = 1; + dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ + } else + card->hw_lock = 0; /* free hardware again */ + } while (again); /* until nothing more to do */ + + restore_flags(flags); +} /* ergo_irq_bh */ + + +/*********************************************************/ +/* stop the card (hardware reset) and disable interrupts */ +/*********************************************************/ +static void +ergo_stopcard(hysdn_card * card) +{ + ulong flags; + uchar val; + + hysdn_net_release(card); /* first release the net device if existing */ + save_flags(flags); + cli(); + val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ + val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */ + byteout(card->iobase + PCI9050_INTR_REG, val); + card->irq_enabled = 0; + byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */ + card->state = CARD_STATE_UNUSED; + card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */ + + restore_flags(flags); +} /* ergo_stopcard */ + +/**************************************************************************/ +/* enable or disable the cards error log. The event is queued if possible */ +/**************************************************************************/ +static void +ergo_set_errlog_state(hysdn_card * card, int on) +{ + ulong flags; + + if (card->state != CARD_STATE_RUN) { + card->err_log_state = ERRLOG_STATE_OFF; /* must be off */ + return; + } + save_flags(flags); + cli(); + + if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) || + ((card->err_log_state == ERRLOG_STATE_ON) && on)) { + restore_flags(flags); + return; /* nothing to do */ + } + if (on) + card->err_log_state = ERRLOG_STATE_START; /* request start */ + else + card->err_log_state = ERRLOG_STATE_STOP; /* request stop */ + + restore_flags(flags); + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} /* ergo_set_errlog_state */ + +/******************************************/ +/* test the cards RAM and return 0 if ok. */ +/******************************************/ +static const char TestText[36] = "This Message is filler, why read it"; + +static int +ergo_testram(hysdn_card * card) +{ + tErgDpram *dpr = card->dpram; + + memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */ + dpr->ToHyInt = 1; /* E1 INTR state forced */ + + memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText)); + if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText))) + return (-1); + + memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText)); + if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, + sizeof(TestText))) + return (-1); + + return (0); +} /* ergo_testram */ + +/*****************************************************************************/ +/* this function is intended to write stage 1 boot image to the cards buffer */ +/* this is done in two steps. First the 1024 hi-words are written (offs=0), */ +/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */ +/* PCI-write-buffers flushed and the card is taken out of reset. */ +/* The function then waits for a reaction of the E1 processor or a timeout. */ +/* Negative return values are interpreted as errors. */ +/*****************************************************************************/ +static int +ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs) +{ + uchar *dst; + tErgDpram *dpram; + int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */ + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs); + + dst = card->dpram; /* pointer to start of DPRAM */ + dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */ + while (cnt--) { + *dst++ = *(buf + 1); /* high byte */ + *dst++ = *buf; /* low byte */ + dst += 2; /* point to next longword */ + buf += 2; /* buffer only filled with words */ + } + + /* if low words (offs = 2) have been written, clear the rest of the DPRAM, */ + /* flush the PCI-write-buffer and take the E1 out of reset */ + if (offs) { + memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */ + dpram = card->dpram; /* get pointer to dpram structure */ + dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */ + while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */ + + byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */ + /* the interrupts are still masked */ + + sti(); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + + if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) { + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write bootldr no answer"); + return (-ERR_BOOTIMG_FAIL); + } + } /* start_boot_img */ + return (0); /* successfull */ +} /* ergo_writebootimg */ + +/********************************************************************************/ +/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */ +/* using the boot spool mechanism. If everything works fine 0 is returned. In */ +/* case of errors a negative error value is returned. */ +/********************************************************************************/ +static int +ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len) +{ + tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram; + uchar *dst; + uchar buflen; + int nr_write; + uchar tmp_rdptr; + uchar wr_mirror; + int i; + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write boot seq len=%d ", len); + + dst = sp->Data; /* point to data in spool structure */ + buflen = sp->Len; /* maximum len of spooled data */ + wr_mirror = sp->WrPtr; /* only once read */ + sti(); + + /* try until all bytes written or error */ + i = 0x1000; /* timeout value */ + while (len) { + + /* first determine the number of bytes that may be buffered */ + do { + tmp_rdptr = sp->RdPtr; /* first read the pointer */ + i--; /* decrement timeout */ + } while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */ + + if (!i) { + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: write boot seq timeout"); + return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */ + } + if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0) + nr_write += buflen; /* now we got number of free bytes - 1 in buffer */ + + if (!nr_write) + continue; /* no free bytes in buffer */ + + if (nr_write > len) + nr_write = len; /* limit if last few bytes */ + i = 0x1000; /* reset timeout value */ + + /* now we know how much bytes we may put in the puffer */ + len -= nr_write; /* we savely could adjust len before output */ + while (nr_write--) { + *(dst + wr_mirror) = *buf++; /* output one byte */ + if (++wr_mirror >= buflen) + wr_mirror = 0; + sp->WrPtr = wr_mirror; /* announce the next byte to E1 */ + } /* while (nr_write) */ + + } /* while (len) */ + + return (0); +} /* ergo_writebootseq */ + +/***********************************************************************************/ +/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */ +/* boot process. If the process has been successfull 0 is returned otherwise a */ +/* negative error code is returned. */ +/***********************************************************************************/ +static int +ergo_waitpofready(struct HYSDN_CARD *card) +{ + tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */ + int timecnt = 10000 / 50; /* timeout is 10 secs max. */ + ulong flags; + int msg_size; + int i; + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: waiting for pof ready"); + + while (timecnt--) { + /* wait until timeout */ + + if (dpr->ToPcFlag) { + /* data has arrived */ + + if ((dpr->ToPcChannel != CHAN_SYSTEM) || + (dpr->ToPcSize < MIN_RDY_MSG_SIZE) || + (dpr->ToPcSize > MAX_RDY_MSG_SIZE) || + ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC)) + break; /* an error occured */ + + /* Check for additional data delivered during SysReady */ + msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE; + if (msg_size > 0) + if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size)) + break; + + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "ERGO: pof boot success"); + + save_flags(flags); + cli(); + + card->state = CARD_STATE_RUN; /* now card is running */ + /* enable the cards interrupt */ + byteout(card->iobase + PCI9050_INTR_REG, + bytein(card->iobase + PCI9050_INTR_REG) | + (PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1)); + card->irq_enabled = 1; /* we are ready to receive interrupts */ + + dpr->ToPcFlag = 0; /* reset data indicator */ + dpr->ToHyInt = 1; + dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ + + restore_flags(flags); + if ((i = hysdn_net_create(card))) { + ergo_stopcard(card); + card->state = CARD_STATE_BOOTERR; + return (i); + } + return (0); /* success */ + } /* data has arrived */ + sti(); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((50 * HZ) / 1000); /* Timeout 50ms */ + } /* wait until timeout */ + + if (card->debug_flags & LOG_POF_CARD) + hysdn_addlog(card, "ERGO: pof boot ready timeout"); + return (-ERR_POF_TIMEOUT); +} /* ergo_waitpofready */ + + + +/************************************************************************************/ +/* release the cards hardware. Before releasing do a interrupt disable and hardware */ +/* reset. Also unmap dpram. */ +/* Use only during module release. */ +/************************************************************************************/ +static void +ergo_releasehardware(hysdn_card * card) +{ + ergo_stopcard(card); /* first stop the card if not already done */ + free_irq(card->irq, card); /* release interrupt */ + release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */ + release_region(card->iobase + PCI9050_USER_IO, 1); + vfree(card->dpram); + card->dpram = NULL; /* release shared mem */ +} /* ergo_releasehardware */ + + +/*********************************************************************************/ +/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */ +/* value is returned. */ +/* Use only during module init. */ +/*********************************************************************************/ +int +ergo_inithardware(hysdn_card * card) +{ + if (check_region(card->iobase + PCI9050_INTR_REG, 1) || + check_region(card->iobase + PCI9050_USER_IO, 1)) + return (-1); /* ports already in use */ + + card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1; + if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE))) + return (-1); + + request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN"); + request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN"); + ergo_stopcard(card); /* disable interrupts */ + if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) { + ergo_releasehardware(card); /* return the aquired hardware */ + return (-1); + } + /* success, now setup the function pointers */ + card->stopcard = ergo_stopcard; + card->releasehardware = ergo_releasehardware; + card->testram = ergo_testram; + card->writebootimg = ergo_writebootimg; + card->writebootseq = ergo_writebootseq; + card->waitpofready = ergo_waitpofready; + card->set_errlog_state = ergo_set_errlog_state; + card->irq_queue.next = 0; + card->irq_queue.sync = 0; + card->irq_queue.data = card; /* init task queue for interrupt */ + card->irq_queue.routine = (void *) (void *) ergo_irq_bh; + + return (0); +} /* ergo_inithardware */ diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/isdn/hysdn/boardergo.h new file mode 100644 index 000000000000..0e2c3f678784 --- /dev/null +++ b/drivers/isdn/hysdn/boardergo.h @@ -0,0 +1,117 @@ +/* $Id: boardergo.h,v 1.1 2000/02/10 19:44:30 werner Exp $ + + * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..). + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: boardergo.h,v $ + * Revision 1.1 2000/02/10 19:44:30 werner + * + * Initial release + * + * + */ + + +/************************************************/ +/* defines for the dual port memory of the card */ +/************************************************/ +#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */ +#define BOOT_IMG_SIZE 4096 +#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE) + +#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */ +#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */ + +/* following DPRAM layout copied from OS2-driver boarderg.h */ +typedef struct ErgDpram_tag { +/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE]; +/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE]; + + /*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART]; + /* size 0x1B0 */ + + /*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64]; + /* size 64 bytes */ + /*1DB0 ulong ulErrType; */ + /*1DB4 ulong ulErrSubtype; */ + /*1DB8 ulong ucTextSize; */ + /*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */ + /*1DF0 */ + +/*1DF0 */ word volatile ToHyChannel; +/*1DF2 */ word volatile ToHySize; + /*1DF4 */ uchar volatile ToHyFlag; + /* !=0: msg for Hy waiting */ + /*1DF5 */ uchar volatile ToPcFlag; + /* !=0: msg for PC waiting */ +/*1DF6 */ word volatile ToPcChannel; +/*1DF8 */ word volatile ToPcSize; + /*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA]; + /* 6 bytes */ + +/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00]; +/*1F00 */ ulong TrapTable[62]; + /*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8]; + /* low part of reset vetor */ +/*1FFB */ uchar ToPcIntMetro; + /* notes: + * - metro has 32-bit boot ram - accessing + * ToPcInt and ToHyInt would be the same; + * so we moved ToPcInt to 1FFB. + * Because on the PC side both vars are + * readonly (reseting on int from E1 to PC), + * we can read both vars on both cards + * without destroying anything. + * - 1FFB is the high byte of the reset vector, + * so E1 side should NOT change this byte + * when writing! + */ +/*1FFC */ uchar volatile ToHyNoDpramErrLog; + /* note: ToHyNoDpramErrLog is used to inform + * boot loader, not to use DPRAM based + * ErrLog; when DOS driver is rewritten + * this becomes obsolete + */ +/*1FFD */ uchar bRes1FFD; + /*1FFE */ uchar ToPcInt; + /* E1_intclear; on CHAMP2: E1_intset */ + /*1FFF */ uchar ToHyInt; + /* E1_intset; on CHAMP2: E1_intclear */ +} tErgDpram; + +/**********************************************/ +/* PCI9050 controller local register offsets: */ +/* copied from boarderg.c */ +/**********************************************/ +#define PCI9050_INTR_REG 0x4C /* Interrupt register */ +#define PCI9050_USER_IO 0x51 /* User I/O register */ + + /* bitmask for PCI9050_INTR_REG: */ +#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */ +#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */ +#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */ +#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */ + + /* bitmask for PCI9050_USER_IO: */ +#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */ +#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */ +#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */ + +#define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */ +#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */ diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c new file mode 100644 index 000000000000..e62418089bf2 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_boot.c @@ -0,0 +1,421 @@ +/* $Id: hysdn_boot.c,v 1.1 2000/02/10 19:45:18 werner Exp $ + + * Linux driver for HYSDN cards, specific routines for booting and pof handling. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_boot.c,v $ + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" +#include "hysdn_pof.h" + +/********************************/ +/* defines for pof read handler */ +/********************************/ +#define POF_READ_FILE_HEAD 0 +#define POF_READ_TAG_HEAD 1 +#define POF_READ_TAG_DATA 2 + +/************************************************************/ +/* definition of boot specific data area. This data is only */ +/* needed during boot and so allocated dynamically. */ +/************************************************************/ +struct boot_data { + word Cryptor; /* for use with Decrypt function */ + word Nrecs; /* records remaining in file */ + uchar pof_state; /* actual state of read handler */ + uchar is_crypted; /* card data is crypted */ + int BufSize; /* actual number of bytes bufferd */ + int last_error; /* last occured error */ + word pof_recid; /* actual pof recid */ + ulong pof_reclen; /* total length of pof record data */ + ulong pof_recoffset; /* actual offset inside pof record */ + union { + uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */ + tPofRecHdr PofRecHdr; /* header for actual record/chunk */ + tPofFileHdr PofFileHdr; /* header from POF file */ + tPofTimeStamp PofTime; /* time information */ + } buf; +}; + +/*****************************************************/ +/* start decryption of sucessive POF file chuncks. */ +/* */ +/* to be called at start of POF file reading, */ +/* before starting any decryption on any POF record. */ +/*****************************************************/ +void +StartDecryption(struct boot_data *boot) +{ + boot->Cryptor = CRYPT_STARTTERM; +} /* StartDecryption */ + + +/***************************************************************/ +/* decrypt complete BootBuf */ +/* NOTE: decryption must be applied to all or none boot tags - */ +/* to HI and LO boot loader and (all) seq tags, because */ +/* global Cryptor is started for whole POF. */ +/***************************************************************/ +void +DecryptBuf(struct boot_data *boot, int cnt) +{ + uchar *bufp = boot->buf.BootBuf; + + while (cnt--) { + boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0); + *bufp++ ^= (uchar) boot->Cryptor; + } +} /* DecryptBuf */ + +/********************************************************************************/ +/* pof_handle_data executes the required actions dependant on the active record */ +/* id. If successfull 0 is returned, a negative value shows an error. */ +/********************************************************************************/ +static int +pof_handle_data(hysdn_card * card, int datlen) +{ + struct boot_data *boot = card->boot; /* pointer to boot specific data */ + long l; + uchar *imgp; + int img_len; + + /* handle the different record types */ + switch (boot->pof_recid) { + + case TAG_TIMESTMP: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText); + break; + + case TAG_CBOOTDTA: + DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ + case TAG_BOOTDTA: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", + (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA", + datlen, boot->pof_recoffset); + + if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) { + boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */ + return (boot->last_error); + } + imgp = boot->buf.BootBuf; /* start of buffer */ + img_len = datlen; /* maximum length to transfer */ + + l = POF_BOOT_LOADER_OFF_IN_PAGE - + (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1)); + if (l > 0) { + /* buffer needs to be truncated */ + imgp += l; /* advance pointer */ + img_len -= l; /* adjust len */ + } + /* at this point no special handling for data wrapping over buffer */ + /* is necessary, because the boot image always will be adjusted to */ + /* match a page boundary inside the buffer. */ + /* The buffer for the boot image on the card is filled in 2 cycles */ + /* first the 1024 hi-words are put in the buffer, then the low 1024 */ + /* word are handled in the same way with different offset. */ + + if (img_len > 0) { + /* data available for copy */ + if ((boot->last_error = + card->writebootimg(card, imgp, + (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0) + return (boot->last_error); + } + break; /* end of case boot image hi/lo */ + + case TAG_CABSDATA: + DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ + case TAG_ABSDATA: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", + (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA", + datlen, boot->pof_recoffset); + + if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0)) + return (boot->last_error); /* error writing data */ + + if (boot->pof_recoffset + datlen >= boot->pof_reclen) + return (card->waitpofready(card)); /* data completely spooled, wait for ready */ + + break; /* end of case boot seq data */ + + default: + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid, + datlen, boot->pof_recoffset); + + break; /* simply skip record */ + } /* switch boot->pof_recid */ + + return (0); +} /* pof_handle_data */ + + +/******************************************************************************/ +/* pof_write_buffer is called when the buffer has been filled with the needed */ +/* number of data bytes. The number delivered is additionally supplied for */ +/* verification. The functions handles the data and returns the needed number */ +/* of bytes for the next action. If the returned value is 0 or less an error */ +/* occured and booting must be aborted. */ +/******************************************************************************/ +int +pof_write_buffer(hysdn_card * card, int datlen) +{ + struct boot_data *boot = card->boot; /* pointer to boot specific data */ + + if (!boot) + return (-EFAULT); /* invalid call */ + if (boot->last_error < 0) + return (boot->last_error); /* repeated error */ + + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: got %d bytes ", datlen); + + switch (boot->pof_state) { + case POF_READ_FILE_HEAD: + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: checking file header"); + + if (datlen != sizeof(tPofFileHdr)) { + boot->last_error = -EPOF_INTERNAL; + break; + } + if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) { + boot->last_error = -EPOF_BAD_MAGIC; + break; + } + /* Setup the new state and vars */ + boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */ + boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ + boot->last_error = sizeof(tPofRecHdr); /* new length */ + break; + + case POF_READ_TAG_HEAD: + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: checking tag header"); + + if (datlen != sizeof(tPofRecHdr)) { + boot->last_error = -EPOF_INTERNAL; + break; + } + boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */ + boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */ + boot->pof_recoffset = 0; /* no starting offset */ + + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ", + boot->pof_recid, boot->pof_reclen); + + boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */ + if (boot->pof_reclen < BOOT_BUF_SIZE) + boot->last_error = boot->pof_reclen; /* limit size */ + else + boot->last_error = BOOT_BUF_SIZE; /* maximum */ + + if (!boot->last_error) { /* no data inside record */ + boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ + boot->last_error = sizeof(tPofRecHdr); /* new length */ + } + break; + + case POF_READ_TAG_DATA: + if (card->debug_flags & LOG_POF_WRITE) + hysdn_addlog(card, "POF write: getting tag data"); + + if (datlen != boot->last_error) { + boot->last_error = -EPOF_INTERNAL; + break; + } + if ((boot->last_error = pof_handle_data(card, datlen)) < 0) + return (boot->last_error); /* an error occured */ + + boot->pof_recoffset += datlen; + if (boot->pof_recoffset >= boot->pof_reclen) { + boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ + boot->last_error = sizeof(tPofRecHdr); /* new length */ + } else { + if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE) + boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */ + else + boot->last_error = BOOT_BUF_SIZE; /* maximum */ + } + break; + + default: + boot->last_error = -EPOF_INTERNAL; /* unknown state */ + break; + } /* switch (boot->pof_state) */ + + return (boot->last_error); +} /* pof_write_buffer */ + + +/*******************************************************************************/ +/* pof_write_open is called when an open for boot on the cardlog device occurs. */ +/* The function returns the needed number of bytes for the next operation. If */ +/* the returned number is less or equal 0 an error specified by this code */ +/* occurred. Additionally the pointer to the buffer data area is set on success */ +/*******************************************************************************/ +int +pof_write_open(hysdn_card * card, uchar ** bufp) +{ + struct boot_data *boot; /* pointer to boot specific data */ + + if (card->boot) { + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF open: already opened for boot"); + return (-ERR_ALREADY_BOOT); /* boot already active */ + } + /* error no mem available */ + if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) { + if (card->debug_flags & LOG_MEM_ERR) + hysdn_addlog(card, "POF open: unable to allocate mem"); + return (-EFAULT); + } + card->boot = boot; + card->state = CARD_STATE_BOOTING; + memset(boot, 0, sizeof(struct boot_data)); + + card->stopcard(card); /* first stop the card */ + if (card->testram(card)) { + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF open: DPRAM test failure"); + boot->last_error = -ERR_BOARD_DPRAM; + card->state = CARD_STATE_BOOTERR; /* show boot error */ + return (boot->last_error); + } + boot->BufSize = 0; /* Buffer is empty */ + boot->pof_state = POF_READ_FILE_HEAD; /* read file header */ + StartDecryption(boot); /* if POF File should be encrypted */ + + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF open: success"); + + *bufp = boot->buf.BootBuf; /* point to buffer */ + return (sizeof(tPofFileHdr)); +} /* pof_write_open */ + +/********************************************************************************/ +/* pof_write_close is called when an close of boot on the cardlog device occurs. */ +/* The return value must be 0 if everything has happened as desired. */ +/********************************************************************************/ +int +pof_write_close(hysdn_card * card) +{ + struct boot_data *boot = card->boot; /* pointer to boot specific data */ + + if (!boot) + return (-EFAULT); /* invalid call */ + + card->boot = NULL; /* no boot active */ + kfree(boot); + + if (card->state == CARD_STATE_RUN) + card->set_errlog_state(card, 1); /* activate error log */ + + if (card->debug_flags & LOG_POF_OPEN) + hysdn_addlog(card, "POF close: success"); + + return (0); +} /* pof_write_close */ + +/*********************************************************************************/ +/* EvalSysrTokData checks additional records delivered with the Sysready Message */ +/* when POF has been booted. A return value of 0 is used if no error occured. */ +/*********************************************************************************/ +int +EvalSysrTokData(hysdn_card * card, uchar * cp, int len) +{ + u_char *p; + u_char crc; + + if (card->debug_flags & LOG_POF_RECORD) + hysdn_addlog(card, "SysReady Token data length %d", len); + + if (len < 2) { + hysdn_addlog(card, "SysReady Token Data to short"); + return (1); + } + for (p = cp, crc = 0; p < (cp + len - 2); p++) + if ((crc & 0x80)) + crc = (((u_char) (crc << 1)) + 1) + *p; + else + crc = ((u_char) (crc << 1)) + *p; + crc = ~crc; + if (crc != *(cp + len - 1)) { + hysdn_addlog(card, "SysReady Token Data invalid CRC"); + return (1); + } + len--; /* dont check CRC byte */ + while (len > 0) { + + if (*cp == SYSR_TOK_END) + return (0); /* End of Token stream */ + + if (len < (*(cp + 1) + 2)) { + hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1)); + return (1); + } + switch (*cp) { + case SYSR_TOK_B_CHAN: /* 1 */ + if (*(cp + 1) != 1) + return (1); /* length invalid */ + card->bchans = *(cp + 2); + break; + + case SYSR_TOK_FAX_CHAN: /* 2 */ + if (*(cp + 1) != 1) + return (1); /* length invalid */ + card->faxchans = *(cp + 2); + break; + + case SYSR_TOK_MAC_ADDR: /* 3 */ + if (*(cp + 1) != 6) + return (1); /* length invalid */ + memcpy(card->mac_addr, cp + 2, 6); + break; + + default: + hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1)); + break; + } + len -= (*(cp + 1) + 2); /* adjust len */ + cp += (*(cp + 1) + 2); /* and pointer */ + } + + hysdn_addlog(card, "no end token found"); + return (1); +} /* EvalSysrTokData */ diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h new file mode 100644 index 000000000000..cac76cb26dc6 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -0,0 +1,229 @@ +/* $Id: hysdn_defs.h,v 1.1 2000/02/10 19:44:30 werner Exp $ + + * Linux driver for HYSDN cards, global definitions and exported vars and functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_defs.h,v $ + * Revision 1.1 2000/02/10 19:44:30 werner + * + * Initial release + * + * + */ + +#include +#include +#include +#include + +/****************************/ +/* storage type definitions */ +/****************************/ +#define uchar unsigned char +#define uint unsigned int +#define ulong unsigned long +#define word unsigned short + +#include "ince1pc.h" + +/************************************************/ +/* constants and bits for debugging/log outputs */ +/************************************************/ +#define LOG_MAX_LINELEN 120 +#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */ +#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */ +#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */ +#define LOG_POF_RECORD 0x00000020 /* log pof record parser */ +#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */ +#define LOG_POF_CARD 0x00000080 /* log pof related card functions */ +#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */ +#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */ +#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */ +#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */ +#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */ +#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */ +#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */ + +#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */ + +/**********************************/ +/* proc filesystem name constants */ +/**********************************/ +#define PROC_SUBDIR_NAME "hysdn" +#define PROC_CONF_BASENAME "cardconf" +#define PROC_LOG_BASENAME "cardlog" + +/************************/ +/* PCI constant defines */ +/************************/ +#define PCI_VENDOR_ID_HYPERCOPE 0x1365 +#define PCI_DEVICE_ID_PLX 0x9050 /* all DPRAM cards use the same id */ + +/*****************************/ +/* sub ids determining cards */ +/*****************************/ +#define PCI_SUB_ID_OLD_ERGO 0x0104 +#define PCI_SUB_ID_ERGO 0x0106 +#define PCI_SUB_ID_METRO 0x0107 +#define PCI_SUB_ID_CHAMP2 0x0108 +#define PCI_SUB_ID_PLEXUS 0x0109 + +/***********************************/ +/* PCI 32 bit parms for IO and MEM */ +/***********************************/ +#define PCI_REG_PLX_MEM_BASE 0 +#define PCI_REG_PLX_IO_BASE 1 +#define PCI_REG_MEMORY_BASE 3 + +/**************/ +/* card types */ +/**************/ +#define BD_NONE 0U +#define BD_PERFORMANCE 1U +#define BD_VALUE 2U +#define BD_PCCARD 3U +#define BD_ERGO 4U +#define BD_METRO 5U +#define BD_CHAMP2 6U +#define BD_PLEXUS 7U + +/******************************************************/ +/* defined states for cards shown by reading cardconf */ +/******************************************************/ +#define CARD_STATE_UNUSED 0 /* never been used or booted */ +#define CARD_STATE_BOOTING 1 /* booting is in progress */ +#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */ +#define CARD_STATE_RUN 3 /* card is active */ + +/*******************************/ +/* defines for error_log_state */ +/*******************************/ +#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */ +#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */ +#define ERRLOG_STATE_START 2 /* start error logging */ +#define ERRLOG_STATE_STOP 3 /* stop error logging */ + +/*******************************/ +/* data structure for one card */ +/*******************************/ +typedef struct HYSDN_CARD { + + /* general variables for the cards */ + int myid; /* own driver card id */ + uchar bus; /* pci bus the card is connected to */ + uchar devfn; /* slot+function bit encoded */ + word subsysid; /* PCI subsystem id */ + uchar brdtype; /* type of card */ + uint bchans; /* number of available B-channels */ + uint faxchans; /* number of available fax-channels */ + uchar mac_addr[6]; /* MAC Address read from card */ + uint irq; /* interrupt number */ + uint iobase; /* IO-port base address */ + ulong plxbase; /* PLX memory base */ + ulong membase; /* DPRAM memory base */ + ulong memend; /* DPRAM memory end */ + void *dpram; /* mapped dpram */ + int state; /* actual state of card -> CARD_STATE_** */ + struct HYSDN_CARD *next; /* pointer to next card */ + + /* data areas for the /proc file system */ + void *proclog; /* pointer to proclog filesystem specific data */ + void *procconf; /* pointer to procconf filesystem specific data */ + + /* debugging and logging */ + uchar err_log_state; /* actual error log state of the card */ + ulong debug_flags; /* tells what should be debugged and where */ + void (*set_errlog_state) (struct HYSDN_CARD *, int); + + /* interrupt handler + interrupt synchronisation */ + struct tq_struct irq_queue; /* interrupt task queue */ + uchar volatile irq_enabled; /* interrupt enabled if != 0 */ + uchar volatile hw_lock; /* hardware is currently locked -> no access */ + + /* boot process */ + void *boot; /* pointer to boot private data */ + int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong); + int (*writebootseq) (struct HYSDN_CARD *, uchar *, int); + int (*waitpofready) (struct HYSDN_CARD *); + int (*testram) (struct HYSDN_CARD *); + + /* scheduler for data transfer (only async parts) */ + uchar async_data[256]; /* async data to be sent (normally for config) */ + word volatile async_len; /* length of data to sent */ + word volatile async_channel; /* channel number for async transfer */ + int volatile async_busy; /* flag != 0 sending in progress */ + int volatile net_tx_busy; /* a network packet tx is in progress */ + + /* network interface */ + void *netif; /* pointer to network structure */ + + /* init and deinit stopcard for booting, too */ + void (*stopcard) (struct HYSDN_CARD *); + void (*releasehardware) (struct HYSDN_CARD *); +} hysdn_card; + + +/*****************/ +/* exported vars */ +/*****************/ +extern int cardmax; /* number of found cards */ +extern hysdn_card *card_root; /* pointer to first card */ + + + +/*************************/ +/* im/exported functions */ +/*************************/ +extern int printk(const char *fmt,...); +extern char *hysdn_getrev(const char *); + +/* hysdn_procconf.c */ +extern int hysdn_procconf_init(void); /* init proc config filesys */ +extern void hysdn_procconf_release(void); /* deinit proc config filesys */ + +/* hysdn_proclog.c */ +extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */ +extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */ +extern void put_log_buffer(hysdn_card *, char *); /* output log data */ +extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */ +extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */ + +/* boardergo.c */ +extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */ + +/* hysdn_boot.c */ +extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */ +extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */ +extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */ +extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */ + +/* hysdn_sched.c */ +extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *, + word); +extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word); +extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */ + +/* hysdn_net.c */ +extern char *hysdn_net_revision; +extern int hysdn_net_create(hysdn_card *); /* create a new net device */ +extern int hysdn_net_release(hysdn_card *); /* delete the device */ +extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */ +extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */ +extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */ +extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */ diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c new file mode 100644 index 000000000000..eb3fed4d33a1 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -0,0 +1,243 @@ +/* $Id: hysdn_init.c,v 1.1 2000/02/10 19:45:18 werner Exp $ + + * Linux driver for HYSDN cards, init functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_init.c,v $ + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +static char *hysdn_init_revision = "$Revision: 1.1 $"; +int cardmax; /* number of found cards */ +hysdn_card *card_root = NULL; /* pointer to first card */ + +/**********************************************/ +/* table assigning PCI-sub ids to board types */ +/* the last entry contains all 0 */ +/**********************************************/ +static struct { + word subid; /* PCI sub id */ + uchar cardtyp; /* card type assigned */ +} pci_subid_map[] = { + + { + PCI_SUB_ID_METRO, BD_METRO + }, + { + PCI_SUB_ID_CHAMP2, BD_CHAMP2 + }, + { + PCI_SUB_ID_ERGO, BD_ERGO + }, + { + PCI_SUB_ID_OLD_ERGO, BD_ERGO + }, + { + 0, 0 + } /* terminating entry */ +}; + +/*********************************************************************/ +/* search_cards searches for available cards in the pci config data. */ +/* If a card is found, the card structure is allocated and the cards */ +/* ressources are reserved. cardmax is incremented. */ +/*********************************************************************/ +static void +search_cards(void) +{ + struct pci_dev *akt_pcidev = NULL; + hysdn_card *card, *card_last; + uchar irq; + int i; + + card_root = NULL; + card_last = NULL; + while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_PLX, + akt_pcidev)) != NULL) { + + if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) { + printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); + return; + } + memset(card, 0, sizeof(hysdn_card)); + card->myid = cardmax; /* set own id */ + card->bus = akt_pcidev->bus->number; + card->devfn = akt_pcidev->devfn; /* slot + function */ + pcibios_read_config_word(card->bus, card->devfn, PCI_SUBSYSTEM_ID, &card->subsysid); + pcibios_read_config_byte(card->bus, card->devfn, PCI_INTERRUPT_LINE, &irq); + card->irq = irq; + card->iobase = akt_pcidev->resource[ PCI_REG_PLX_IO_BASE].start & PCI_BASE_ADDRESS_IO_MASK; + card->plxbase = akt_pcidev->resource[ PCI_REG_PLX_MEM_BASE].start; + card->membase = akt_pcidev->resource[ PCI_REG_MEMORY_BASE].start; + card->brdtype = BD_NONE; /* unknown */ + card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ + card->faxchans = 0; /* default no fax channels */ + card->bchans = 2; /* and 2 b-channels */ + for (i = 0; pci_subid_map[i].subid; i++) + if (pci_subid_map[i].subid == card->subsysid) { + card->brdtype = pci_subid_map[i].cardtyp; + break; + } + if (card->brdtype != BD_NONE) { + if (ergo_inithardware(card)) { + printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); + kfree(card); + continue; + } + } else { + printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid); + kfree(card); /* release mem */ + continue; + } + cardmax++; + card->next = NULL; /*end of chain */ + if (card_last) + card_last->next = card; /* pointer to next card */ + else + card_root = card; + card_last = card; /* new chain end */ + } /* device found */ +} /* search_cards */ + +/************************************************************************************/ +/* free_resources frees the acquired PCI resources and returns the allocated memory */ +/************************************************************************************/ +static void +free_resources(void) +{ + hysdn_card *card; + + while (card_root) { + card = card_root; + if (card->releasehardware) + card->releasehardware(card); /* free all hardware resources */ + card_root = card_root->next; /* remove card from chain */ + kfree(card); /* return mem */ + + } /* while card_root */ +} /* free_resources */ + +/**************************************************************************/ +/* stop_cards disables (hardware resets) all cards and disables interrupt */ +/**************************************************************************/ +static void +stop_cards(void) +{ + hysdn_card *card; + + card = card_root; /* first in chain */ + while (card) { + if (card->stopcard) + card->stopcard(card); + card = card->next; /* remove card from chain */ + } /* while card */ +} /* stop_cards */ + + +/****************************************************************************/ +/* The module startup and shutdown code. Only compiled when used as module. */ +/* Using the driver as module is always advisable, because the booting */ +/* image becomes smaller and the driver code is only loaded when needed. */ +/* Additionally newer versions may be activated without rebooting. */ +/****************************************************************************/ +#ifdef CONFIG_MODULES + +/******************************************************/ +/* extract revision number from string for log output */ +/******************************************************/ +char * +hysdn_getrev(const char *revision) +{ + char *rev; + char *p; + + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; +} + + +/****************************************************************************/ +/* init_module is called once when the module is loaded to do all necessary */ +/* things like autodetect... */ +/* If the return value of this function is 0 the init has been successfull */ +/* and the module is added to the list in /proc/modules, otherwise an error */ +/* is assumed and the module will not be kept in memory. */ +/****************************************************************************/ +int +init_module(void) +{ + char tmp[50]; + + strcpy(tmp, hysdn_init_revision); + printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp)); + strcpy(tmp, hysdn_net_revision); + printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp)); + if (!pci_present()) { + printk(KERN_ERR "HYSDN: no PCI bus present, module not loaded\n"); + return (-1); + } + search_cards(); + printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); + + if (hysdn_procconf_init()) { + free_resources(); /* proc file_sys not created */ + return (-1); + } + return (0); /* no error */ +} /* init_module */ + + +/***********************************************************************/ +/* cleanup_module is called when the module is released by the kernel. */ +/* The routine is only called if init_module has been successfull and */ +/* the module counter has a value of 0. Otherwise this function will */ +/* not be called. This function must release all resources still allo- */ +/* cated as after the return from this function the module code will */ +/* be removed from memory. */ +/***********************************************************************/ +void +cleanup_module(void) +{ + + stop_cards(); + hysdn_procconf_release(); + free_resources(); + printk(KERN_NOTICE "HYSDN: module unloaded\n"); +} /* cleanup_module */ + +#endif /* CONFIG_MODULES */ diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c new file mode 100644 index 000000000000..3546ea818f37 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -0,0 +1,379 @@ +/* $Id: hysdn_net.c,v 1.3 2000/02/14 19:24:12 werner Exp $ + + * Linux driver for HYSDN cards, net (ethernet type) handling routines. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.de) + * + * This net module has been inspired by the skeleton driver from + * Donald Becker (becker@CESDIS.gsfc.nasa.gov) + * + * 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: hysdn_net.c,v $ + * Revision 1.3 2000/02/14 19:24:12 werner + * + * Removed superflous file + * + * Revision 1.2 2000/02/13 17:32:19 werner + * + * Added support for new network layer of 2.3.43 and 44 kernels and tested driver. + * + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +/* store the actual version for log reporting */ +char *hysdn_net_revision = "$Revision: 1.3 $"; + +#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ + +/****************************************************************************/ +/* structure containing the complete network data. The structure is aligned */ +/* in a way that both, the device and statistics are kept inside it. */ +/* for proper access, the device structure MUST be the first var/struct */ +/* inside the definition. */ +/****************************************************************************/ +struct net_local { + struct net_device netdev; /* the network device */ + struct net_device_stats stats; + /* additional vars may be added here */ + char dev_name[9]; /* our own device name */ + + /* Tx control lock. This protects the transmit buffer ring + * state along with the "tx full" state of the driver. This + * means all netif_queue flow control actions are protected + * by this lock as well. + */ + spinlock_t lock; + struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */ + int in_idx, out_idx; /* indexes to buffer ring */ + int sk_count; /* number of buffers currently in ring */ + + int is_open; /* flag controlling module locking */ +}; /* net_local */ + + +/*****************************************************/ +/* Get the current statistics for this card. */ +/* This may be called with the card open or closed ! */ +/*****************************************************/ +static struct net_device_stats * +net_get_stats(struct net_device *dev) +{ + return (&((struct net_local *) dev)->stats); +} /* net_device_stats */ + +/*********************************************************************/ +/* Open/initialize the board. This is called (in the current kernel) */ +/* sometime after booting when the 'ifconfig' program is run. */ +/* This routine should set everything up anew at each open, even */ +/* registers that "should" only need to be set once at boot, so that */ +/* there is non-reboot way to recover if something goes wrong. */ +/*********************************************************************/ +static int +net_open(struct net_device *dev) +{ + struct in_device *in_dev; + hysdn_card *card = dev->priv; + int i; + + if (!((struct net_local *) dev)->is_open) + MOD_INC_USE_COUNT; /* increment only if interface is actually down */ + ((struct net_local *) dev)->is_open = 1; /* device actually open */ + + netif_start_queue(dev); /* start tx-queueing */ + + /* Fill in the MAC-level header (if not already set) */ + if (!card->mac_addr[0]) { + for (i = 0; i < ETH_ALEN - sizeof(ulong); i++) + dev->dev_addr[i] = 0xfc; + if ((in_dev = dev->ip_ptr) != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa != NULL) + memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong)); + } + } else + memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN); + + return (0); +} /* net_open */ + +/*******************************************/ +/* flush the currently occupied tx-buffers */ +/* must only be called when device closed */ +/*******************************************/ +static void +flush_tx_buffers(struct net_local *nl) +{ + + while (nl->sk_count) { + dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */ + if (nl->out_idx >= MAX_SKB_BUFFERS) + nl->out_idx = 0; /* wrap around */ + nl->sk_count--; + } +} /* flush_tx_buffers */ + + +/*********************************************************************/ +/* close/decativate the device. The device is not removed, but only */ +/* deactivated. */ +/*********************************************************************/ +static int +net_close(struct net_device *dev) +{ + + netif_stop_queue(dev); /* disable queueing */ + + if (((struct net_local *) dev)->is_open) + MOD_DEC_USE_COUNT; /* adjust module counter */ + ((struct net_local *) dev)->is_open = 0; + flush_tx_buffers((struct net_local *) dev); + + return (0); /* success */ +} /* net_close */ + +/************************************/ +/* send a packet on this interface. */ +/* new style for kernel >= 2.3.33 */ +/************************************/ +static int +net_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local *) dev; + + spin_lock_irq(&lp->lock); + + lp->skbs[lp->in_idx++] = skb; /* add to buffer list */ + if (lp->in_idx >= MAX_SKB_BUFFERS) + lp->in_idx = 0; /* wrap around */ + lp->sk_count++; /* adjust counter */ + dev->trans_start = jiffies; + + /* If we just used up the very last entry in the + * TX ring on this device, tell the queueing + * layer to send no more. + */ + if (lp->sk_count >= MAX_SKB_BUFFERS) + netif_stop_queue(dev); + + /* When the TX completion hw interrupt arrives, this + * is when the transmit statistics are updated. + */ + + spin_unlock_irq(&lp->lock); + + if (lp->sk_count <= 3) { + queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + return (0); /* success */ +} /* net_send_packet */ + + + +/***********************************************************************/ +/* acknowlegde a packet send. The network layer will be informed about */ +/* completion */ +/***********************************************************************/ +void +hysdn_tx_netack(hysdn_card * card) +{ + struct net_local *lp = card->netif; + + if (!lp) + return; /* non existing device */ + + + if (!lp->sk_count) + return; /* error condition */ + + lp->stats.tx_packets++; + lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len; + + dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */ + if (lp->out_idx >= MAX_SKB_BUFFERS) + lp->out_idx = 0; /* wrap around */ + + if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */ + netif_start_queue((struct net_device *) lp); +} /* hysdn_tx_netack */ + +/*****************************************************/ +/* we got a packet from the network, go and queue it */ +/*****************************************************/ +void +hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len) +{ + struct net_local *lp = card->netif; + struct sk_buff *skb; + + if (!lp) + return; /* non existing device */ + + lp->stats.rx_bytes += len; + + skb = dev_alloc_skb(len); + if (skb == NULL) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", + lp->netdev.name); + lp->stats.rx_dropped++; + return; + } + skb->dev = &lp->netdev; + + /* copy the data */ + memcpy(skb_put(skb, len), buf, len); + + /* determine the used protocol */ + skb->protocol = eth_type_trans(skb, &lp->netdev); + + netif_rx(skb); + lp->stats.rx_packets++; /* adjust packet count */ + +} /* hysdn_rx_netpkt */ + +/*****************************************************/ +/* return the pointer to a network packet to be send */ +/*****************************************************/ +struct sk_buff * +hysdn_tx_netget(hysdn_card * card) +{ + struct net_local *lp = card->netif; + + if (!lp) + return (NULL); /* non existing device */ + + if (!lp->sk_count) + return (NULL); /* nothing available */ + + return (lp->skbs[lp->out_idx]); /* next packet to send */ +} /* hysdn_tx_netget */ + + +/*******************************************/ +/* init function called by register device */ +/*******************************************/ +static int +net_init(struct net_device *dev) +{ + /* setup the function table */ + dev->open = net_open; + dev->stop = net_close; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + return (0); /* success */ +} /* net_init */ + +/*****************************************************************************/ +/* hysdn_net_create creates a new net device for the given card. If a device */ +/* already exists, it will be deleted and created a new one. The return value */ +/* 0 announces success, else a negative error code will be returned. */ +/*****************************************************************************/ +int +hysdn_net_create(hysdn_card * card) +{ + struct net_device *dev; + int i; + + hysdn_net_release(card); /* release an existing net device */ + if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); + if (card->debug_flags & LOG_NET_INIT) + return (-ENOMEM); + } + memset(dev, 0, sizeof(struct net_local)); /* clean the structure */ + + spin_lock_init(&((struct net_local *) dev)->lock); + + /* initialise necessary or informing fields */ + dev->base_addr = card->iobase; /* IO address */ + dev->irq = card->irq; /* irq */ + dev->init = net_init; /* the init function of the device */ + dev->name = ((struct net_local *) dev)->dev_name; /* device name */ + if ((i = register_netdev(dev))) { + printk(KERN_WARNING "HYSDN: unable to create network device\n"); + kfree(dev); + return (i); + } + dev->priv = card; /* remember pointer to own data structure */ + card->netif = dev; /* setup the local pointer */ + + if (card->debug_flags & LOG_NET_INIT) + hysdn_addlog(card, "network device created"); + return (0); /* and return success */ +} /* hysdn_net_create */ + +/***************************************************************************/ +/* hysdn_net_release deletes the net device for the given card. The return */ +/* value 0 announces success, else a negative error code will be returned. */ +/***************************************************************************/ +int +hysdn_net_release(hysdn_card * card) +{ + struct net_device *dev = card->netif; + + if (!dev) + return (0); /* non existing */ + + card->netif = NULL; /* clear out pointer */ + dev->stop(dev); /* close the device */ + + flush_tx_buffers((struct net_local *) dev); /* empty buffers */ + + unregister_netdev(dev); /* release the device */ + kfree(dev); /* release the memory allocated */ + if (card->debug_flags & LOG_NET_INIT) + hysdn_addlog(card, "network device deleted"); + + return (0); /* always successfull */ +} /* hysdn_net_release */ + +/*****************************************************************************/ +/* hysdn_net_getname returns a pointer to the name of the network interface. */ +/* if the interface is not existing, a "-" is returned. */ +/*****************************************************************************/ +char * +hysdn_net_getname(hysdn_card * card) +{ + struct net_device *dev = card->netif; + + if (!dev) + return ("-"); /* non existing */ + + return (dev->name); +} /* hysdn_net_getname */ diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h new file mode 100644 index 000000000000..619c07897850 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_pof.h @@ -0,0 +1,95 @@ +/* $Id: hysdn_pof.h,v 1.1 2000/02/10 19:44:30 werner Exp $ + + * Linux driver for HYSDN cards, definitions used for handling pof-files. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_pof.h,v $ + * Revision 1.1 2000/02/10 19:44:30 werner + * + * Initial release + * + * + */ + +/************************/ +/* POF specific defines */ +/************************/ +#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */ +#define CRYPT_FEEDTERM 0x8142 +#define CRYPT_STARTTERM 0x81a5 + /* max. timeout time in seconds + * from end of booting to POF is ready + */ +#define POF_READY_TIME_OUT_SEC 10 + +/**********************************/ +/* defines for 1.stage boot image */ +/**********************************/ + +/* the POF file record containing the boot loader image + * has 2 pages a 16KB: + * 1. page contains the high 16-bit part of the 32-bit E1 words + * 2. page contains the low 16-bit part of the 32-bit E1 words + * + * In each 16KB page we assume the start of the boot loader code + * in the highest 2KB part (at offset 0x3800); + * the rest (0x0000..0x37FF) is assumed to contain 0 bytes. + */ + +#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */ +#define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE) + +#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */ + + /* offset in boot page, where loader code may start */ + /* =0x3800= 14336U */ +#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE) + + +/*--------------------------------------POF file record structs------------*/ +typedef struct PofFileHdr_tag { /* Pof file header */ +/*00 */ ulong Magic __attribute__((packed)); +/*04 */ ulong N_PofRecs __attribute__((packed)); +/*08 */ +} tPofFileHdr; + +typedef struct PofRecHdr_tag { /* Pof record header */ +/*00 */ word PofRecId __attribute__((packed)); +/*02 */ ulong PofRecDataLen __attribute__((packed)); +/*06 */ +} tPofRecHdr; + +typedef struct PofTimeStamp_tag { +/*00 */ ulong UnixTime __attribute__((packed)); + /*04 */ uchar DateTimeText[0x28] __attribute__((packed)); + /* =40 */ +/*2C */ +} tPofTimeStamp; + + /* tPofFileHdr.Magic value: */ +#define TAGFILEMAGIC 0x464F501AUL + /* tPofRecHdr.PofRecId values: */ +#define TAG_ABSDATA 0x1000 /* abs. data */ +#define TAG_BOOTDTA 0x1001 /* boot data */ +#define TAG_COMMENT 0x0020 +#define TAG_SYSCALL 0x0021 +#define TAG_FLOWCTRL 0x0022 +#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */ +#define TAG_CABSDATA 0x1100 /* crypted abs. data */ +#define TAG_CBOOTDTA 0x1101 /* crypted boot data */ diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c new file mode 100644 index 000000000000..c26ef7fedcba --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -0,0 +1,486 @@ +/* $Id: hysdn_procconf.c,v 1.2 2000/02/14 19:23:03 werner Exp $ + + * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_procconf.c,v $ + * Revision 1.2 2000/02/14 19:23:03 werner + * + * Changed handling of proc filesystem tables to a more portable version + * + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +static char *hysdn_procconf_revision = "$Revision: 1.2 $"; + +#define INFO_OUT_LEN 80 /* length of info line including lf */ + +/********************************************************/ +/* defines and data structure for conf write operations */ +/********************************************************/ +#define CONF_STATE_DETECT 0 /* waiting for detect */ +#define CONF_STATE_CONF 1 /* writing config data */ +#define CONF_STATE_POF 2 /* writing pof data */ +#define CONF_LINE_LEN 80 /* 80 chars max */ + +struct conf_writedata { + hysdn_card *card; /* card the device is connected to */ + int buf_size; /* actual number of bytes in the buffer */ + int needed_size; /* needed size when reading pof */ + int state; /* actual interface states from above constants */ + uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */ + word channel; /* active channel number */ + uchar *pof_buffer; /* buffer when writing pof */ +}; + +/***********************************************************************/ +/* process_line parses one config line and transfers it to the card if */ +/* necessary. */ +/* if the return value is negative an error occured. */ +/***********************************************************************/ +static int +process_line(struct conf_writedata *cnf) +{ + uchar *cp = cnf->conf_line; + int i; + + if (cnf->card->debug_flags & LOG_CNF_LINE) + hysdn_addlog(cnf->card, "conf line: %s", cp); + + if (*cp == '-') { /* option */ + cp++; /* point to option char */ + + if (*cp++ != 'c') + return (0); /* option unknown or used */ + i = 0; /* start value for channel */ + while ((*cp <= '9') && (*cp >= '0')) + i = i * 10 + *cp++ - '0'; /* get decimal number */ + if (i > 65535) { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "conf channel invalid %d", i); + return (-ERR_INV_CHAN); /* invalid channel */ + } + cnf->channel = i & 0xFFFF; /* set new channel number */ + return (0); /* success */ + } /* option */ + if (*cp == '*') { /* line to send */ + if (cnf->card->debug_flags & LOG_CNF_DATA) + hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp); + return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1, + cnf->channel)); /* send the line without * */ + } /* line to send */ + return (0); +} /* process_line */ + +/*************************/ +/* dummy file operations */ +/*************************/ +static loff_t +hysdn_dummy_lseek(struct file *file, loff_t offset, int orig) +{ + return -ESPIPE; +} /* hysdn_dummy_lseek */ + +/***********************************/ +/* conf file operations and tables */ +/***********************************/ + +/****************************************************/ +/* write conf file -> boot or send cfg line to card */ +/****************************************************/ +static ssize_t +hysdn_conf_write(struct file *file, const char *buf, size_t count, loff_t * off) +{ + struct conf_writedata *cnf; + int i; + uchar ch, *cp; + + if (&file->f_pos != off) /* fs error check */ + return (-ESPIPE); + if (!count) + return (0); /* nothing to handle */ + + if (!(cnf = file->private_data)) + return (-EFAULT); /* should never happen */ + + if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */ + if (copy_from_user(&ch, buf, 1)) /* get first char for detect */ + return (-EFAULT); + + if (ch == 0x1A) { + /* we detected a pof file */ + if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0) + return (cnf->needed_size); /* an error occured -> exit */ + cnf->buf_size = 0; /* buffer is empty */ + cnf->state = CONF_STATE_POF; /* new state */ + } else { + /* conf data has been detected */ + cnf->buf_size = 0; /* buffer is empty */ + cnf->state = CONF_STATE_CONF; /* requested conf data write */ + if (cnf->card->state != CARD_STATE_RUN) + return (-ERR_NOT_BOOTED); + cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */ + cnf->channel = 4098; /* default channel for output */ + } + } /* state was auto detect */ + if (cnf->state == CONF_STATE_POF) { /* pof write active */ + i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */ + if (i <= 0) + return (-EINVAL); /* size error handling pof */ + + if (i < count) + count = i; /* limit requested number of bytes */ + if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count)) + return (-EFAULT); /* error while copying */ + cnf->buf_size += count; + + if (cnf->needed_size == cnf->buf_size) { + cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */ + if (cnf->needed_size <= 0) { + cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */ + return (cnf->needed_size); /* an error occured */ + } + cnf->buf_size = 0; /* buffer is empty again */ + } + } + /* pof write active */ + else { /* conf write active */ + + if (cnf->card->state != CARD_STATE_RUN) { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "cnf write denied -> not booted"); + return (-ERR_NOT_BOOTED); + } + i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */ + if (i > 0) { + /* copy remaining bytes into buffer */ + + if (count > i) + count = i; /* limit transfer */ + if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count)) + return (-EFAULT); /* error while copying */ + + i = count; /* number of chars in buffer */ + cp = cnf->conf_line + cnf->buf_size; + while (i) { + /* search for end of line */ + if ((*cp < ' ') && (*cp != 9)) + break; /* end of line found */ + cp++; + i--; + } /* search for end of line */ + + if (i) { + /* delimiter found */ + *cp++ = 0; /* string termination */ + count -= (i - 1); /* subtract remaining bytes from count */ + while ((i) && (*cp < ' ') && (*cp != 9)) { + i--; /* discard next char */ + count++; /* mark as read */ + cp++; /* next char */ + } + cnf->buf_size = 0; /* buffer is empty after transfer */ + if ((i = process_line(cnf)) < 0) /* handle the line */ + count = i; /* return the error */ + } + /* delimiter found */ + else { + cnf->buf_size += count; /* add chars to string */ + if (cnf->buf_size >= CONF_LINE_LEN - 1) { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count); + return (-ERR_CONF_LONG); + } + } /* not delimited */ + + } + /* copy remaining bytes into buffer */ + else { + if (cnf->card->debug_flags & LOG_CNF_MISC) + hysdn_addlog(cnf->card, "cnf line too long"); + return (-ERR_CONF_LONG); + } + } /* conf write active */ + + return (count); +} /* hysdn_conf_write */ + +/*******************************************/ +/* read conf file -> output card info data */ +/*******************************************/ +static ssize_t +hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off) +{ + char *cp; + int i; + + if (off != &file->f_pos) /* fs error check */ + return -ESPIPE; + + if (file->f_mode & FMODE_READ) { + if (!(cp = file->private_data)) + return (-EFAULT); /* should never happen */ + i = strlen(cp); /* get total string length */ + if (*off < i) { + /* still bytes to transfer */ + cp += *off; /* point to desired data offset */ + i -= *off; /* remaining length */ + if (i > count) + i = count; /* limit length to transfer */ + if (copy_to_user(buf, cp, i)) + return (-EFAULT); /* copy error */ + *off += i; /* adjust offset */ + } else + return (0); + } else + return (-EPERM); /* no permission to read */ + + return (i); +} /* hysdn_conf_read */ + +/******************/ +/* open conf file */ +/******************/ +static int +hysdn_conf_open(struct inode *ino, struct file *filep) +{ + hysdn_card *card; + struct proc_dir_entry *pd; + struct conf_writedata *cnf; + char *cp, *tmp; + + MOD_INC_USE_COUNT; /* lock module */ + + /* now search the addressed card */ + card = card_root; + while (card) { + pd = card->procconf; + if (pd->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (!card) { + MOD_DEC_USE_COUNT; /* unlock module */ + return (-ENODEV); /* device is unknown/invalid */ + } + if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) + hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x", + filep->f_uid, filep->f_gid, filep->f_mode); + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write boot file or conf line */ + + if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) { + MOD_DEC_USE_COUNT; + return (-EFAULT); + } + cnf->card = card; + cnf->buf_size = 0; /* nothing buffered */ + cnf->state = CONF_STATE_DETECT; /* start auto detect */ + filep->private_data = cnf; + + } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + /* read access -> output card info data */ + + if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) { + MOD_DEC_USE_COUNT; + return (-EFAULT); /* out of memory */ + } + filep->private_data = tmp; /* start of string */ + + /* first output a headline */ + sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device"); + cp = tmp; /* start of string */ + while (*cp) + cp++; + while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) + *cp++ = ' '; + *cp++ = '\n'; + + /* and now the data */ + sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s", + card->myid, + card->bus, + PCI_SLOT(card->devfn), + card->brdtype, + card->irq, + card->iobase, + card->membase, + card->bchans, + card->faxchans, + card->state, + hysdn_net_getname(card)); + while (*cp) + cp++; + while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) + *cp++ = ' '; + *cp++ = '\n'; + *cp = 0; /* end of string */ + } else { /* simultaneous read/write access forbidden ! */ + MOD_DEC_USE_COUNT; /* unlock module */ + return (-EPERM); /* no permission this time */ + } + return (0); +} /* hysdn_conf_open */ + +/***************************/ +/* close a config file. */ +/***************************/ +static int +hysdn_conf_close(struct inode *ino, struct file *filep) +{ + hysdn_card *card; + struct conf_writedata *cnf; + int retval = 0; + struct proc_dir_entry *pd; + + /* search the addressed card */ + card = card_root; + while (card) { + pd = card->procconf; + if (pd->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (!card) { + return (-ENODEV); /* device is unknown/invalid */ + } + if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) + hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x", + filep->f_uid, filep->f_gid, filep->f_mode); + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write boot file or conf line */ + if (filep->private_data) { + cnf = filep->private_data; + + if (cnf->state == CONF_STATE_POF) + retval = pof_write_close(cnf->card); /* close the pof write */ + kfree(filep->private_data); /* free allocated memory for buffer */ + + } /* handle write private data */ + } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + /* read access -> output card info data */ + + if (filep->private_data) + kfree(filep->private_data); /* release memory */ + } + MOD_DEC_USE_COUNT; /* reduce usage count */ + return (retval); +} /* hysdn_conf_close */ + +/******************************************************/ +/* table for conf filesystem functions defined above. */ +/******************************************************/ +static struct file_operations conf_fops = +{ + hysdn_dummy_lseek, + hysdn_conf_read, + hysdn_conf_write, + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + hysdn_conf_open, + NULL, /* flush */ + hysdn_conf_close, + NULL /* fsync */ +}; + +static struct inode_operations conf_inode_operations; + +/*****************************/ +/* hysdn subdir in /proc/net */ +/*****************************/ +struct proc_dir_entry *hysdn_proc_entry = NULL; + +/*******************************************************************************/ +/* hysdn_procconf_init is called when the module is loaded and after the cards */ +/* have been detected. The needed proc dir and card config files are created. */ +/* The log init is called at last. */ +/*******************************************************************************/ +int +hysdn_procconf_init(void) +{ + hysdn_card *card; + uchar conf_name[20]; + + hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net); + if (!hysdn_proc_entry) { + printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); + return (-1); + } + card = card_root; /* point to first card */ + while (card) { + + sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); + if ((card->procconf = (void *) create_proc_entry(conf_name, + S_IFREG | S_IRUGO | S_IWUSR, + hysdn_proc_entry)) != NULL) { + memset(&conf_inode_operations, 0, sizeof(struct inode_operations)); + conf_inode_operations.default_file_ops = &conf_fops; + + ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations; + hysdn_proclog_init(card); /* init the log file entry */ + } + card = card->next; /* next entry */ + } + + printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision)); + return (0); +} /* hysdn_procconf_init */ + +/*************************************************************************************/ +/* hysdn_procconf_release is called when the module is unloaded and before the cards */ +/* resources are released. The module counter is assumed to be 0 ! */ +/*************************************************************************************/ +void +hysdn_procconf_release(void) +{ + hysdn_card *card; + uchar conf_name[20]; + + card = card_root; /* start with first card */ + while (card) { + + sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); + if (card->procconf) + remove_proc_entry(conf_name, hysdn_proc_entry); + + hysdn_proclog_release(card); /* init the log file entry */ + + card = card->next; /* point to next card */ + } + + remove_proc_entry(PROC_SUBDIR_NAME, proc_net); +} /* hysdn_procfs_release */ diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c new file mode 100644 index 000000000000..3400067ff6f3 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_procfs.c @@ -0,0 +1,503 @@ +/* $Id: hysdn_procfs.c,v 1.1 2000/02/10 19:45:18 werner Exp $ + + * Linux driver for HYSDN cards, /proc/net filesystem log functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_procfs.c,v $ + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +static char *hysdn_procfs_revision = "$Revision: 1.1 $"; + +#define INFO_OUT_LEN 80 /* length of info line including lf */ + +/*************************************************/ +/* structure keeping ascii log for device output */ +/*************************************************/ +struct log_data { + struct log_data *next; + ulong usage_cnt; /* number of files still to work */ + void *proc_ctrl; /* pointer to own control procdata structure */ + char log_start[2]; /* log string start (final len aligned by size) */ +}; + +/**********************************************/ +/* structure holding proc entrys for one card */ +/**********************************************/ +struct procdata { + struct proc_dir_entry *log; /* log entry */ + char log_name[15]; /* log filename */ + struct log_data *log_head, *log_tail; /* head and tail for queue */ + int if_used; /* open count for interface */ + wait_queue_head_t rd_queue; +}; + +/********************************************/ +/* put an log buffer into the log queue. */ +/* This buffer will be kept until all files */ +/* opened for read got the contents. */ +/* Flushes buffers not longer in use. */ +/********************************************/ +void +put_log_buffer(hysdn_card * card, char *cp) +{ + struct log_data *ib; + struct procdata *pd = card->procfs; + int flags; + + if (!pd) + return; + if (!cp) + return; + if (!*cp) + return; + if (pd->if_used <= 0) + return; /* no open file for read */ + + if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC))) + return; /* no memory */ + strcpy(ib->log_start, cp); /* set output string */ + ib->next = NULL; + ib->proc_ctrl = pd; /* point to own control structure */ + save_flags(flags); + cli(); + ib->usage_cnt = pd->if_used; + if (!pd->log_head) + pd->log_head = ib; /* new head */ + else + pd->log_tail->next = ib; /* follows existing messages */ + pd->log_tail = ib; /* new tail */ + restore_flags(flags); + + /* delete old entrys */ + while (pd->log_head->next) { + if ((pd->log_head->usage_cnt <= 0) && + (pd->log_head->next->usage_cnt <= 0)) { + ib = pd->log_head; + pd->log_head = pd->log_head->next; + kfree(ib); + } else + break; + } /* pd->log_head->next */ + wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */ +} /* put_log_buffer */ + + +/*************************/ +/* dummy file operations */ +/*************************/ +static loff_t +hysdn_dummy_lseek(struct file *file, loff_t offset, int orig) +{ + return -ESPIPE; +} /* hysdn_dummy_lseek */ + +/**********************************/ +/* log file operations and tables */ +/**********************************/ + +/****************************************/ +/* write log file -> set log level bits */ +/****************************************/ +static ssize_t +hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off) +{ + int retval; + hysdn_card *card = (hysdn_card *) file->private_data; + + if (&file->f_pos != off) /* fs error check */ + return (-ESPIPE); + + if ((retval = pof_boot_write(card, buf, count)) < 0) + retval = -EFAULT; /* an error occured */ + + return (retval); +} /* hysdn_log_write */ + +/******************/ +/* read log file */ +/******************/ +static ssize_t +hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off) +{ + struct log_data *inf; + int len; + word ino; + struct procdata *pd; + hysdn_card *card; + + if (!*((struct log_data **) file->private_data)) { + if (file->f_flags & O_NONBLOCK) + return (-EAGAIN); + + /* sorry, but we need to search the card */ + ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ + card = card_root; + while (card) { + pd = card->procfs; + if (pd->log->low_ino == ino) + break; + card = card->next; /* search next entry */ + } + if (card) + interruptible_sleep_on(&(pd->rd_queue)); + else + return (-EAGAIN); + + } + if (!(inf = *((struct log_data **) file->private_data))) + return (0); + + inf->usage_cnt--; /* new usage count */ + (struct log_data **) file->private_data = &inf->next; /* next structure */ + if ((len = strlen(inf->log_start)) <= count) { + if (copy_to_user(buf, inf->log_start, len)) + return -EFAULT; + file->f_pos += len; + return (len); + } + return (0); +} /* hysdn_log_read */ + +/******************/ +/* open log file */ +/******************/ +static int +hysdn_log_open(struct inode *ino, struct file *filep) +{ + hysdn_card *card; + struct procdata *pd; + ulong flags; + + MOD_INC_USE_COUNT; /* lock module */ + card = card_root; + while (card) { + pd = card->procfs; + if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (!card) { + MOD_DEC_USE_COUNT; /* unlock module */ + return (-ENODEV); /* device is unknown/invalid */ + } + filep->private_data = card; /* remember our own card */ + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> boot pof data */ + if (pof_boot_open(card)) { + MOD_DEC_USE_COUNT; /* unlock module */ + return (-EPERM); /* no permission this time */ + } + } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + + /* read access -> log/debug read */ + save_flags(flags); + cli(); + pd->if_used++; + if (pd->log_head) + (struct log_data **) filep->private_data = &(pd->log_tail->next); + else + (struct log_data **) filep->private_data = &(pd->log_head); + restore_flags(flags); + + } else { /* simultaneous read/write access forbidden ! */ + MOD_DEC_USE_COUNT; /* unlock module */ + return (-EPERM); /* no permission this time */ + } + return (0); +} /* hysdn_log_open */ + +/*******************************************************************************/ +/* close a cardlog file. If the file has been opened for exclusive write it is */ +/* assumed as pof data input and the pof loader is noticed about. */ +/* Otherwise file is handled as log output. In this case the interface usage */ +/* count is decremented and all buffers are noticed of closing. If this file */ +/* was the last one to be closed, all buffers are freed. */ +/*******************************************************************************/ +static int +hysdn_log_close(struct inode *ino, struct file *filep) +{ + struct log_data *inf; + struct procdata *pd; + hysdn_card *card; + int flags, retval = 0; + + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write debug completely written */ + retval = 0; /* success */ + } else { + /* read access -> log/debug read, mark one further file as closed */ + + pd = NULL; + save_flags(flags); + cli(); + inf = *((struct log_data **) filep->private_data); /* get first log entry */ + if (inf) + pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ + else { + /* no info available -> search card */ + card = card_root; + while (card) { + pd = card->procfs; + if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (card) + pd = card->procfs; /* pointer to procfs ctrl */ + } + if (pd) + pd->if_used--; /* decrement interface usage count by one */ + + while (inf) { + inf->usage_cnt--; /* decrement usage count for buffers */ + inf = inf->next; + } + restore_flags(flags); + + if (pd) + if (pd->if_used <= 0) /* delete buffers if last file closed */ + while (pd->log_head) { + inf = pd->log_head; + pd->log_head = pd->log_head->next; + kfree(inf); + } + } /* read access */ + + MOD_DEC_USE_COUNT; + return (retval); +} /* hysdn_log_close */ + +/*************************************************/ +/* select/poll routine to be able using select() */ +/*************************************************/ +static unsigned int +hysdn_log_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = 0; + word ino; + hysdn_card *card; + struct procdata *pd; + + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) + return (mask); /* no polling for write supported */ + + /* we need to search the card */ + ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ + card = card_root; + while (card) { + pd = card->procfs; + if (pd->log->low_ino == ino) + break; + card = card->next; /* search next entry */ + } + if (!card) + return (mask); /* card not found */ + + poll_wait(file, &(pd->rd_queue), wait); + + if (*((struct log_data **) file->private_data)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} /* hysdn_log_poll */ + +/**************************************************/ +/* table for log filesystem functions defined above. */ +/**************************************************/ +static struct file_operations log_fops = +{ + hysdn_dummy_lseek, + hysdn_log_read, + hysdn_log_write, + NULL, /* readdir */ + hysdn_log_poll, /* poll */ + NULL, /*hysdn_log_ioctl, *//* ioctl */ + NULL, /* mmap */ + hysdn_log_open, + NULL, /* flush */ + hysdn_log_close, + NULL /* fsync */ +}; + +struct inode_operations log_inode_operations = +{ + &log_fops, /* log proc file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/*****************************************/ +/* Output info data to the cardinfo file */ +/*****************************************/ +static int +info_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + char tmp[INFO_OUT_LEN * 11 + 2]; + int i; + char *cp; + hysdn_card *card; + + sprintf(tmp, "id bus slot type irq iobase plx-mem dp-mem boot device"); + cp = tmp; /* start of string */ + while (*cp) + cp++; + while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) + *cp++ = ' '; + *cp++ = '\n'; + + card = card_root; /* start of list */ + while (card) { + sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x 0x%08x", + card->myid, + card->bus, + PCI_SLOT(card->devfn), + card->brdtype, + card->irq, + card->iobase, + card->plxbase, + card->membase); + card = card->next; + while (*cp) + cp++; + while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) + *cp++ = ' '; + *cp++ = '\n'; + } + + i = cp - tmp; + *start = buffer; + if (offset + length > i) { + length = i - offset; + *eof = 1; + } else if (offset > i) { + length = 0; + *eof = 1; + } + cp = tmp + offset; + + if (length > 0) { + /* start_bh_atomic(); */ + memcpy(buffer, cp, length); + /* end_bh_atomic(); */ + return length; + } + return 0; +} /* info_read */ + +/*****************************/ +/* hysdn subdir in /proc/net */ +/*****************************/ +static struct proc_dir_entry *hysdn_proc_entry = NULL; +static struct proc_dir_entry *hysdn_info_entry = NULL; + +/***************************************************************************************/ +/* hysdn_procfs_init is called when the module is loaded and after the cards have been */ +/* detected. The needed proc dir and card entries are created. */ +/***************************************************************************************/ +int +hysdn_procfs_init(void) +{ + struct procdata *pd; + hysdn_card *card; + + hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net); + if (!hysdn_proc_entry) { + printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); + return (-1); + } + hysdn_info_entry = create_proc_entry("cardinfo", 0, hysdn_proc_entry); + if (hysdn_info_entry) + hysdn_info_entry->read_proc = info_read; /* read info function */ + + /* create all cardlog proc entries */ + + card = card_root; /* start with first card */ + while (card) { + if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { + memset(pd, 0, sizeof(struct procdata)); + + sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); + if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) + pd->log->ops = &log_inode_operations; /* set new operations table */ + + init_waitqueue_head(&(pd->rd_queue)); + + card->procfs = (void *) pd; /* remember procfs structure */ + } + card = card->next; /* point to next card */ + } + + printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procfs_revision)); + return (0); +} /* hysdn_procfs_init */ + +/***************************************************************************************/ +/* hysdn_procfs_release is called when the module is unloaded and before the cards */ +/* resources are released. The module counter is assumed to be 0 ! */ +/***************************************************************************************/ +void +hysdn_procfs_release(void) +{ + struct procdata *pd; + hysdn_card *card; + + card = card_root; /* start with first card */ + while (card) { + if ((pd = (struct procdata *) card->procfs) != NULL) { + if (pd->log) + remove_proc_entry(pd->log_name, hysdn_proc_entry); + kfree(pd); /* release memory */ + } + card = card->next; /* point to next card */ + } + + remove_proc_entry("cardinfo", hysdn_proc_entry); + remove_proc_entry(PROC_SUBDIR_NAME, proc_net); +} /* hysdn_procfs_release */ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c new file mode 100644 index 000000000000..88a001af88a3 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -0,0 +1,482 @@ +/* $Id: hysdn_proclog.c,v 1.2 2000/02/14 19:23:03 werner Exp $ + + * Linux driver for HYSDN cards, /proc/net filesystem log functions. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_proclog.c,v $ + * Revision 1.2 2000/02/14 19:23:03 werner + * + * Changed handling of proc filesystem tables to a more portable version + * + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +static char *hysdn_proclog_revision = "$Revision: 1.2 $"; + +/* the proc subdir for the interface is defined in the procconf module */ +extern struct proc_dir_entry *hysdn_proc_entry; + +/*************************************************/ +/* structure keeping ascii log for device output */ +/*************************************************/ +struct log_data { + struct log_data *next; + ulong usage_cnt; /* number of files still to work */ + void *proc_ctrl; /* pointer to own control procdata structure */ + char log_start[2]; /* log string start (final len aligned by size) */ +}; + +/**********************************************/ +/* structure holding proc entrys for one card */ +/**********************************************/ +struct procdata { + struct proc_dir_entry *log; /* log entry */ + char log_name[15]; /* log filename */ + struct log_data *log_head, *log_tail; /* head and tail for queue */ + int if_used; /* open count for interface */ + int volatile del_lock; /* lock for delete operations */ + uchar logtmp[LOG_MAX_LINELEN]; + wait_queue_head_t rd_queue; +}; + + +/**********************************************/ +/* log function for cards error log interface */ +/**********************************************/ +void +hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize) +{ + char buf[ERRLOG_TEXT_SIZE + 40]; + + sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText); + put_log_buffer(card, buf); /* output the string */ +} /* hysdn_card_errlog */ + +/***************************************************/ +/* Log function using format specifiers for output */ +/***************************************************/ +void +hysdn_addlog(hysdn_card * card, char *fmt,...) +{ + struct procdata *pd = card->proclog; + char *cp; + va_list args; + + if (!pd) + return; /* log structure non existent */ + + cp = pd->logtmp; + cp += sprintf(cp, "HYSDN: card %d ", card->myid); + + va_start(args, fmt); + cp += vsprintf(cp, fmt, args); + va_end(args); + *cp++ = '\n'; + *cp = 0; + + if (card->debug_flags & DEB_OUT_SYSLOG) + printk(KERN_INFO "%s", pd->logtmp); + else + put_log_buffer(card, pd->logtmp); + +} /* hysdn_addlog */ + +/********************************************/ +/* put an log buffer into the log queue. */ +/* This buffer will be kept until all files */ +/* opened for read got the contents. */ +/* Flushes buffers not longer in use. */ +/********************************************/ +void +put_log_buffer(hysdn_card * card, char *cp) +{ + struct log_data *ib; + struct procdata *pd = card->proclog; + int i, flags; + + if (!pd) + return; + if (!cp) + return; + if (!*cp) + return; + if (pd->if_used <= 0) + return; /* no open file for read */ + + if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC))) + return; /* no memory */ + strcpy(ib->log_start, cp); /* set output string */ + ib->next = NULL; + ib->proc_ctrl = pd; /* point to own control structure */ + save_flags(flags); + cli(); + ib->usage_cnt = pd->if_used; + if (!pd->log_head) + pd->log_head = ib; /* new head */ + else + pd->log_tail->next = ib; /* follows existing messages */ + pd->log_tail = ib; /* new tail */ + i = pd->del_lock++; /* get lock state */ + restore_flags(flags); + + /* delete old entrys */ + if (!i) + while (pd->log_head->next) { + if ((pd->log_head->usage_cnt <= 0) && + (pd->log_head->next->usage_cnt <= 0)) { + ib = pd->log_head; + pd->log_head = pd->log_head->next; + kfree(ib); + } else + break; + } /* pd->log_head->next */ + pd->del_lock--; /* release lock level */ + wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */ +} /* put_log_buffer */ + + +/*************************/ +/* dummy file operations */ +/*************************/ +static loff_t +hysdn_dummy_lseek(struct file *file, loff_t offset, int orig) +{ + return -ESPIPE; +} /* hysdn_dummy_lseek */ + +/******************************/ +/* file operations and tables */ +/******************************/ + +/****************************************/ +/* write log file -> set log level bits */ +/****************************************/ +static ssize_t +hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off) +{ + ulong u = 0; + int found = 0; + uchar *cp, valbuf[128]; + long base = 10; + hysdn_card *card = (hysdn_card *) file->private_data; + + if (&file->f_pos != off) /* fs error check */ + return (-ESPIPE); + + if (count > (sizeof(valbuf) - 1)) + count = sizeof(valbuf) - 1; /* limit length */ + if (copy_from_user(valbuf, buf, count)) + return (-EFAULT); /* copy failed */ + + valbuf[count] = 0; /* terminating 0 */ + cp = valbuf; + if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) { + cp += 2; /* pointer after hex modifier */ + base = 16; + } + /* scan the input for debug flags */ + while (*cp) { + if ((*cp >= '0') && (*cp <= '9')) { + found = 1; + u *= base; /* adjust to next digit */ + u += *cp++ - '0'; + continue; + } + if (base != 16) + break; /* end of number */ + + if ((*cp >= 'a') && (*cp <= 'f')) { + found = 1; + u *= base; /* adjust to next digit */ + u += *cp++ - 'a' + 10; + continue; + } + break; /* terminated */ + } + + if (found) { + card->debug_flags = u; /* remember debug flags */ + hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); + } + return (count); +} /* hysdn_log_write */ + +/******************/ +/* read log file */ +/******************/ +static ssize_t +hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off) +{ + struct log_data *inf; + int len; + word ino; + struct procdata *pd; + hysdn_card *card; + + if (!*((struct log_data **) file->private_data)) { + if (file->f_flags & O_NONBLOCK) + return (-EAGAIN); + + /* sorry, but we need to search the card */ + ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == ino) + break; + card = card->next; /* search next entry */ + } + if (card) + interruptible_sleep_on(&(pd->rd_queue)); + else + return (-EAGAIN); + + } + if (!(inf = *((struct log_data **) file->private_data))) + return (0); + + inf->usage_cnt--; /* new usage count */ + (struct log_data **) file->private_data = &inf->next; /* next structure */ + if ((len = strlen(inf->log_start)) <= count) { + if (copy_to_user(buf, inf->log_start, len)) + return -EFAULT; + file->f_pos += len; + return (len); + } + return (0); +} /* hysdn_log_read */ + +/******************/ +/* open log file */ +/******************/ +static int +hysdn_log_open(struct inode *ino, struct file *filep) +{ + hysdn_card *card; + struct procdata *pd; + ulong flags; + + MOD_INC_USE_COUNT; /* lock module */ + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (!card) { + MOD_DEC_USE_COUNT; /* unlock module */ + return (-ENODEV); /* device is unknown/invalid */ + } + filep->private_data = card; /* remember our own card */ + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write log level only */ + } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { + + /* read access -> log/debug read */ + save_flags(flags); + cli(); + pd->if_used++; + if (pd->log_head) + (struct log_data **) filep->private_data = &(pd->log_tail->next); + else + (struct log_data **) filep->private_data = &(pd->log_head); + restore_flags(flags); + } else { /* simultaneous read/write access forbidden ! */ + MOD_DEC_USE_COUNT; /* unlock module */ + return (-EPERM); /* no permission this time */ + } + return (0); +} /* hysdn_log_open */ + +/*******************************************************************************/ +/* close a cardlog file. If the file has been opened for exclusive write it is */ +/* assumed as pof data input and the pof loader is noticed about. */ +/* Otherwise file is handled as log output. In this case the interface usage */ +/* count is decremented and all buffers are noticed of closing. If this file */ +/* was the last one to be closed, all buffers are freed. */ +/*******************************************************************************/ +static int +hysdn_log_close(struct inode *ino, struct file *filep) +{ + struct log_data *inf; + struct procdata *pd; + hysdn_card *card; + int flags, retval = 0; + + + if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { + /* write only access -> write debug level written */ + retval = 0; /* success */ + } else { + /* read access -> log/debug read, mark one further file as closed */ + + pd = NULL; + save_flags(flags); + cli(); + inf = *((struct log_data **) filep->private_data); /* get first log entry */ + if (inf) + pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ + else { + /* no info available -> search card */ + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) + break; + card = card->next; /* search next entry */ + } + if (card) + pd = card->proclog; /* pointer to procfs log */ + } + if (pd) + pd->if_used--; /* decrement interface usage count by one */ + + while (inf) { + inf->usage_cnt--; /* decrement usage count for buffers */ + inf = inf->next; + } + restore_flags(flags); + + if (pd) + if (pd->if_used <= 0) /* delete buffers if last file closed */ + while (pd->log_head) { + inf = pd->log_head; + pd->log_head = pd->log_head->next; + kfree(inf); + } + } /* read access */ + + MOD_DEC_USE_COUNT; + return (retval); +} /* hysdn_log_close */ + +/*************************************************/ +/* select/poll routine to be able using select() */ +/*************************************************/ +static unsigned int +hysdn_log_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = 0; + word ino; + hysdn_card *card; + struct procdata *pd; + + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) + return (mask); /* no polling for write supported */ + + /* we need to search the card */ + ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ + card = card_root; + while (card) { + pd = card->proclog; + if (pd->log->low_ino == ino) + break; + card = card->next; /* search next entry */ + } + if (!card) + return (mask); /* card not found */ + + poll_wait(file, &(pd->rd_queue), wait); + + if (*((struct log_data **) file->private_data)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} /* hysdn_log_poll */ + +/**************************************************/ +/* table for log filesystem functions defined above. */ +/**************************************************/ +static struct file_operations log_fops = +{ + hysdn_dummy_lseek, + hysdn_log_read, + hysdn_log_write, + NULL, /* readdir */ + hysdn_log_poll, /* poll */ + NULL, + NULL, /* mmap */ + hysdn_log_open, + NULL, /* flush */ + hysdn_log_close, + NULL /* fsync */ +}; + +struct inode_operations log_inode_operations; + +/***********************************************************************************/ +/* hysdn_proclog_init is called when the module is loaded after creating the cards */ +/* conf files. */ +/***********************************************************************************/ +int +hysdn_proclog_init(hysdn_card * card) +{ + struct procdata *pd; + + /* create a cardlog proc entry */ + + if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { + memset(pd, 0, sizeof(struct procdata)); + memset(&log_inode_operations, 0, sizeof(struct inode_operations)); + log_inode_operations.default_file_ops = &log_fops; + + sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); + if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) + pd->log->ops = &log_inode_operations; /* set new operations table */ + + init_waitqueue_head(&(pd->rd_queue)); + + card->proclog = (void *) pd; /* remember procfs structure */ + } + return (0); +} /* hysdn_proclog_init */ + +/************************************************************************************/ +/* hysdn_proclog_release is called when the module is unloaded and before the cards */ +/* conf file is released */ +/* The module counter is assumed to be 0 ! */ +/************************************************************************************/ +void +hysdn_proclog_release(hysdn_card * card) +{ + struct procdata *pd; + + if ((pd = (struct procdata *) card->proclog) != NULL) { + if (pd->log) + remove_proc_entry(pd->log_name, hysdn_proc_entry); + kfree(pd); /* release memory */ + card->proclog = NULL; + } +} /* hysdn_proclog_release */ diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c new file mode 100644 index 000000000000..991272152100 --- /dev/null +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -0,0 +1,203 @@ +/* $Id: hysdn_sched.c,v 1.1 2000/02/10 19:45:18 werner Exp $ + + * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc. + * + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_sched.c,v $ + * Revision 1.1 2000/02/10 19:45:18 werner + * + * Initial release + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include + +#include "hysdn_defs.h" + +/*****************************************************************************/ +/* hysdn_sched_rx is called from the cards handler to announce new data is */ +/* available from the card. The routine has to handle the data and return */ +/* with a nonzero code if the data could be worked (or even thrown away), if */ +/* no room to buffer the data is available a zero return tells the card */ +/* to keep the data until later. */ +/*****************************************************************************/ +int +hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan) +{ + + switch (chan) { + case CHAN_NDIS_DATA: + hysdn_rx_netpkt(card, buf, len); /* give packet to network handler */ + break; + + case CHAN_ERRLOG: + hysdn_card_errlog(card, (tErrLogEntry *) buf, len); + if (card->err_log_state == ERRLOG_STATE_ON) + card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ + break; + + default: + printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); + break; + + } /* switch rx channel */ + + return (1); /* always handled */ +} /* hysdn_sched_rx */ + +/*****************************************************************************/ +/* hysdn_sched_tx is called from the cards handler to announce that there is */ +/* room in the tx-buffer to the card and data may be sent if needed. */ +/* If the routine wants to send data it must fill buf, len and chan with the */ +/* appropriate data and return a nonzero value. With a zero return no new */ +/* data to send is assumed. maxlen specifies the buffer size available for */ +/* sending. */ +/*****************************************************************************/ +int +hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen) +{ + struct sk_buff *skb; + + if (card->net_tx_busy) { + card->net_tx_busy = 0; /* reset flag */ + hysdn_tx_netack(card); /* acknowledge packet send */ + } /* a network packet has completely been transferred */ + /* first of all async requests are handled */ + if (card->async_busy) { + if (card->async_len <= maxlen) { + memcpy(buf, card->async_data, card->async_len); + *len = card->async_len; + *chan = card->async_channel; + card->async_busy = 0; /* reset request */ + return (1); + } + card->async_busy = 0; /* in case of length error */ + } /* async request */ + if ((card->err_log_state == ERRLOG_STATE_START) && + (maxlen >= ERRLOG_CMD_REQ_SIZE)) { + strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */ + *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */ + *chan = CHAN_ERRLOG; /* and channel */ + card->err_log_state = ERRLOG_STATE_ON; /* new state is on */ + return (1); /* tell that data should be send */ + } /* error log start and able to send */ + if ((card->err_log_state == ERRLOG_STATE_STOP) && + (maxlen >= ERRLOG_CMD_STOP_SIZE)) { + strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */ + *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */ + *chan = CHAN_ERRLOG; /* and channel */ + card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */ + return (1); /* tell that data should be send */ + } /* error log start and able to send */ + /* now handle network interface packets */ + if ((skb = hysdn_tx_netget(card)) != NULL) { + if (skb->len <= maxlen) { + memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */ + *len = skb->len; + *chan = CHAN_NDIS_DATA; + card->net_tx_busy = 1; /* we are busy sending network data */ + return (1); /* go and send the data */ + } else + hysdn_tx_netack(card); /* aknowledge packet -> throw away */ + } /* send a network packet if available */ + return (0); /* nothing to send */ +} /* hysdn_sched_tx */ + + +/*****************************************************************************/ +/* send one config line to the card and return 0 if successfull, otherwise a */ +/* negative error code. */ +/* The function works with timeouts perhaps not giving the greatest speed */ +/* sending the line, but this should be meaningless beacuse only some lines */ +/* are to be sent and this happens very seldom. */ +/*****************************************************************************/ +int +hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan) +{ + int cnt = 50; /* timeout intervalls */ + ulong flags; + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1); + + save_flags(flags); + cli(); + while (card->async_busy) { + sti(); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg delayed"); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + if (!--cnt) { + restore_flags(flags); + return (-ERR_ASYNC_TIME); /* timed out */ + } + cli(); + } /* wait for buffer to become free */ + + strcpy(card->async_data, line); + card->async_len = strlen(line) + 1; + card->async_channel = chan; + card->async_busy = 1; /* request transfer */ + + /* now queue the task */ + queue_task(&card->irq_queue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + sti(); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg data queued"); + + cnt++; /* short delay */ + cli(); + + while (card->async_busy) { + sti(); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg waiting for tx-ready"); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + if (!--cnt) { + restore_flags(flags); + return (-ERR_ASYNC_TIME); /* timed out */ + } + cli(); + } /* wait for buffer to become free again */ + + restore_flags(flags); + + if (card->debug_flags & LOG_SCHED_ASYN) + hysdn_addlog(card, "async tx-cfg data send"); + + return (0); /* line send correctly */ +} /* hysdn_tx_cfgline */ diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h new file mode 100644 index 000000000000..c22974d85338 --- /dev/null +++ b/drivers/isdn/hysdn/ince1pc.h @@ -0,0 +1,132 @@ +#ifndef __INCE1PC_H__ +#define __INCE1PC_H__ + +/**************************************************************************** + + FILE: ince1pc.h + + AUTHOR: M.Steinkopf + + PURPOSE: common definitions for both sides of the bus: + - conventions both spoolers must know + - channel numbers agreed upon + +*****************************************************************************/ + +/* basic scalar definitions have same meanning, + * but their declaration location depends on environment + */ + +/*--------------------------------------channel numbers---------------------*/ +#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ +#define CHAN_ERRLOG 0x0005 /* error logger */ +#define CHAN_CAPI 0x0064 /* CAPI interface */ +#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ + +/*--------------------------------------POF ready msg-----------------------*/ + /* NOTE: after booting POF sends system ready message to PC: */ +#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ +#define RDY_MAGIC_SIZE 4 /* size in bytes */ + +#define MAX_N_TOK_BYTES 255 + +#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE +#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + +#define SYSR_TOK_END 0 +#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ +#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ +#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ +#define SYSR_TOK_ESC 255 /* undefined data size yet */ + /* default values, if not corrected by token: */ +#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ +#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ + +/* syntax of new SYSR token stream: + * channel: CHAN_SYSTEM + * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE + * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) + * msg : 0 1 2 3 {4 5 6 ..} + * S Y S R MAX_N_TOK_BYTES bytes of TokenStream + * + * TokenStream := empty + * | {NonEndTokenChunk} EndToken RotlCRC + * NonEndTokenChunk:= NonEndTokenId DataLen [Data] + * NonEndTokenId := 0x01 .. 0xFE 1 BYTE + * DataLen := 0x00 .. 0xFF 1 BYTE + * Data := DataLen bytes + * EndToken := 0x00 + * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes + * s. RotlCRC algorithm + * + * RotlCRC algorithm: + * ucSum= 0 1 uchar + * for all NonEndTokenChunk bytes: + * ROTL(ucSum,1) rotate left by 1 + * ucSum += Char; add current byte with swap around + * RotlCRC= ~ucSum; invert all bits for result + * + * note: + * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! + */ + +/*--------------------------------------error logger------------------------*/ + /* note: pof needs final 0 ! */ +#define ERRLOG_CMD_REQ "ERRLOG ON" +#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ +#define ERRLOG_CMD_STOP "ERRLOG OFF" +#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ + +#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ + /* remaining text size = 55 */ +#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1) + +typedef struct ErrLogEntry_tag { + +/*00 */ ulong ulErrType; + +/*04 */ ulong ulErrSubtype; + +/*08 */ uchar ucTextSize; + + /*09 */ uchar ucText[ERRLOG_TEXT_SIZE]; + /* ASCIIZ of len ucTextSize-1 */ + +/*40 */ +} tErrLogEntry; + + +#if defined(__TURBOC__) +#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE +#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE +#endif /* */ +#endif /* */ + +/*--------------------------------------DPRAM boot spooler------------------*/ + /* this is the struture used between pc and + * hyperstone to exchange boot data + */ +#define DPRAM_SPOOLER_DATA_SIZE 0x20 +typedef struct DpramBootSpooler_tag { + +/*00 */ uchar Len; + +/*01 */ volatile uchar RdPtr; + +/*02 */ uchar WrPtr; + +/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE]; + +/*23 */ +} tDpramBootSpooler; + + +#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ +#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ + +/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ + /* at DPRAM offset 0x1C00: */ +#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ + + +#endif /* __INCE1PC_H__ */ diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 1626fa4e9d08..21cc2e67d567 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; @@ -1078,6 +1110,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: @@ -1563,6 +1596,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; @@ -1854,7 +1890,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; @@ -2024,13 +2060,17 @@ isdn_close(struct inode *ino, struct file *filep) static struct file_operations isdn_fops = { - llseek: isdn_lseek, - read: isdn_read, - write: isdn_write, - poll: isdn_poll, - ioctl: isdn_ioctl, - open: isdn_open, - release: isdn_close, + isdn_lseek, + isdn_read, + isdn_write, + NULL, /* isdn_readdir */ + isdn_poll, /* isdn_poll */ + isdn_ioctl, /* isdn_ioctl */ + NULL, /* isdn_mmap */ + isdn_open, + NULL, /* flush */ + isdn_close, + NULL /* fsync */ }; char * @@ -2056,7 +2096,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; @@ -2079,6 +2119,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) { @@ -2360,6 +2402,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; @@ -2473,6 +2528,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 3c60d7c8076a..c45dd5202b36 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, wait_queue_head_t *); -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 e1c7cb75d483..12947565f058 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.107 2000/02/13 09:52:05 kai Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,66 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.107 2000/02/13 09:52:05 kai + * increased TX_TIMEOUT to 20sec + * + * Revision 1.106 2000/02/12 19:26:55 kai + * adopted to latest 2.3 softnet changes. + * + * tested with PPP and MPPP, it works here. + * can somebody check raw-ip? + * + * also changed std2kern, stddiff for bash-1 compatibility, + * hope this doesn't break anything. + * + * Revision 1.105 2000/02/12 11:43:26 he + * SOFTNET related changes, first try. Compatible with linux 2.2.x, but + * not tested for kernels with softnet (>= 2.3.43) yet. + * + * Revision 1.104 2000/02/06 21:49:59 detabc + * add rewriting of socket's and frame's saddr for udp-ipv4 dynip-connections. + * Include checksum-recompute of ip- and udp-header's. + * + * 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. @@ -393,10 +453,6 @@ #endif -#ifndef ISDN_NEW_TBUSY -#define ISDN_NEW_TBUSY -#endif -#ifdef ISDN_NEW_TBUSY /* * Outline of new tbusy handling: * @@ -413,29 +469,60 @@ */ /* - * Tell upper layers that the network device is ready to xmit more frames. + * About SOFTNET: + * Most of the changes were pretty obvious and basically done by HE already. + * + * One problem of the isdn net device code is that is uses struct net_device + * for masters and slaves. However, only master interface are registered to + * the network layer, and therefore, it only makes sense to call netif_* + * functions on them. + * + * The old code abused the slaves dev->start to remember the corresponding + * master's interface state (ifup'ed or not). This does not work with SOFTNET + * any more, because there's now dev->start anymore. + * Instead I chose to add isdn_net_started() which gives the state of the + * master in case of slaves. + * I'm still not sure if this is how it's supposed to be done this way + * because it uses test_bit(LINK_STATE_START, &dev->state) which might be + * considered private to the network layer. However, it works for now. + * Alternative: set a flag in _open() and clear it in _close() + * + * I left some dead code around in #if 0 which I'm not absolutely sure about. + * If no problems turn up, it should be removed later + * + * --KG */ -static void __inline__ isdn_net_dev_xon(struct net_device * dev) -{ - dev->tbusy = 0; - mark_bh(NET_BH); -} -static void __inline__ isdn_net_lp_xon(isdn_net_local * lp) +/* + * Find out if the netdevice has been ifup-ed yet. + * For slaves, look at the corresponding master. + */ +static int __inline__ isdn_net_started(isdn_net_dev *n) { - lp->netdev->dev.tbusy = 0; - if(lp->master) lp->master->tbusy = 0; - mark_bh(NET_BH); + isdn_net_local *lp = n->local; + struct net_device *dev; + + if (lp->master) + dev = lp->master; + else + dev = &n->dev; + return test_bit(LINK_STATE_START, &dev->state); } /* - * Ask upper layers to temporarily cease passing us more xmit frames. + * wake up the network -> net_device queue. + * For slaves, wake the corresponding master interface. */ -static void __inline__ isdn_net_dev_xoff(struct net_device * dev) +static void __inline__ isdn_net_lp_xon(isdn_net_local * lp) { - dev->tbusy = 1; + if (lp->master) + netif_wake_queue(lp->master); + else + netif_wake_queue(&lp->netdev->dev); } -#endif + + +#define ISDN_NET_TX_TIMEOUT (20*HZ) /* Prototypes */ @@ -443,7 +530,7 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.95 $"; +char *isdn_net_revision = "$Revision: 1.107 $"; /* * Code for raw-networking over ISDN @@ -482,14 +569,9 @@ isdn_net_reset(struct net_device *dev) #endif ulong flags; + /* not sure if the cli() is needed at all --KG */ save_flags(flags); cli(); /* Avoid glitch on writes to CMD regs */ - dev->interrupt = 0; -#ifdef ISDN_NEW_TBUSY - isdn_net_dev_xon(dev); -#else - dev->tbusy = 0; -#endif #ifdef CONFIG_ISDN_X25 if( cprot && cprot -> pops && dops ) cprot -> pops -> restart ( cprot, dev, dops ); @@ -505,8 +587,12 @@ isdn_net_open(struct net_device *dev) struct net_device *p; struct in_device *in_dev; + /* moved here from isdn_net_reset, because only the master has an + interface associated which is supposed to be started. BTW: + we need to call netif_start_queue, not netif_wake_queue here */ + netif_start_queue(dev); + isdn_net_reset(dev); - dev->start = 1; /* Fill in the MAC-level header (not needed, but for compatibility... */ for (i = 0; i < ETH_ALEN - sizeof(u32); i++) dev->dev_addr[i] = 0xfc; @@ -524,7 +610,6 @@ isdn_net_open(struct net_device *dev) if ((p = (((isdn_net_local *) dev->priv)->slave))) { while (p) { isdn_net_reset(p); - p->start = 1; p = (((isdn_net_local *) p->priv)->slave); } } @@ -703,19 +788,11 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) mdev = &lp->netdev->dev; if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) { lp->sav_skb = NULL; -#ifndef ISDN_NEW_TBUSY - mark_bh(NET_BH); -#endif } else { return 1; } } -#ifdef ISDN_NEW_TBUSY isdn_net_lp_xon(lp); -#else - if (test_and_clear_bit(0, (void *) &(p->dev.tbusy))) - mark_bh(NET_BH); -#endif } return 1; case ISDN_STAT_DCONN: @@ -814,18 +891,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb))) lp->first_skb = NULL; } -#ifdef ISDN_NEW_TBUSY if(! lp->first_skb) isdn_net_lp_xon(lp); -#else - else { - /* - * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb). - * With an empty lp->first_skb, we need to do this ourselves - */ - lp->netdev->dev.tbusy = 0; - mark_bh(NET_BH); - } -#endif /* ISDN_NEW_TBUSY */ return 1; } break; @@ -1259,14 +1325,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; @@ -1280,14 +1348,8 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) * * Return: 0 on success, !0 on failure. */ -#ifndef ISDN_NEW_TBUSY -/* - * Side-effects: ndev->tbusy is cleared on success. - */ -#endif -int -isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp, - struct sk_buff *skb) +int isdn_net_send_skb + (struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb) { int ret; int len = skb->len; /* save len */ @@ -1295,17 +1357,11 @@ isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp, ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); if (ret == len) { lp->transcount += len; -#ifndef ISDN_NEW_TBUSY - clear_bit(0, (void *) &(ndev->tbusy)); -#endif return 0; } if (ret < 0) { dev_kfree_skb(skb); lp->stats.tx_errors++; -#ifndef ISDN_NEW_TBUSY - clear_bit(0, (void *) &(ndev->tbusy)); -#endif return 0; } return 1; @@ -1351,11 +1407,7 @@ isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb) if (lp->srobin == ndev) ret = isdn_net_send_skb(ndev, lp, skb); else -#ifdef ISDN_NEW_TBUSY ret = isdn_net_start_xmit(skb, lp->srobin); -#else - ret = ndev->tbusy = isdn_net_start_xmit(skb, lp->srobin); -#endif lp->srobin = (slp->slave) ? slp->slave : ndev; slp = (isdn_net_local *) (lp->srobin->priv); if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0))) @@ -1397,6 +1449,35 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) } } + +void isdn_net_tx_timeout(struct net_device * ndev) +{ + isdn_net_local *lp = (isdn_net_local *) ndev->priv; + + printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate); + if (!lp->dialstate){ + lp->stats.tx_errors++; + /* + * There is a certain probability that this currently + * works at all because if we always wake up the interface, + * then upper layer will try to send the next packet + * immediately. And then, the old clean_up logic in the + * driver will hopefully continue to work as it used to do. + * + * This is rather primitive right know, we better should + * clean internal queues here, in particular for multilink and + * ppp, and reset HL driver's channel, too. --HE + * + * actually, this may not matter at all, because ISDN hardware + * should not see transmitter hangs at all IMO + * changed KERN_DEBUG to KERN_WARNING to find out if this is + * ever called + */ + } + ndev->trans_start = jiffies; + netif_wake_queue(ndev); +} + /* * Try sending a packet. * If this interface isn't connected to a ISDN-Channel, find a free channel, @@ -1408,19 +1489,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_local *lp = (isdn_net_local *) ndev->priv; #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = lp -> netdev -> cprot; -#endif - if (ndev->tbusy) { - if (jiffies - ndev->trans_start < (2 * HZ)) - return 1; - if (!lp->dialstate) - lp->stats.tx_errors++; - ndev->trans_start = jiffies; -#ifdef ISDN_NEW_TBUSY - isdn_net_dev_xon(ndev); -#endif - } -#ifndef ISDN_NEW_TBUSY - ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */ #endif #ifdef CONFIG_ISDN_X25 /* At this point hard_start_xmit() passes control to the encapsulation @@ -1436,9 +1504,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) */ if( cprot ) { int ret = cprot -> pops -> encap_and_xmit ( cprot , skb); -#ifdef ISDN_NEW_TBUSY - if(ret) isdn_net_dev_xoff(ndev); -#endif + if(ret) netif_stop_queue(ndev); return ret; } else #endif @@ -1458,9 +1524,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); dev_kfree_skb(skb); -#ifndef ISDN_NEW_TBUSY - ndev->tbusy = 0; -#endif return 0; } if (lp->phone[1]) { @@ -1476,15 +1539,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) if(jiffies < lp->dialwait_timer) { isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); dev_kfree_skb(skb); -#ifndef ISDN_NEW_TBUSY - ndev->tbusy = 0; -#endif restore_flags(flags); return 0; } else lp->dialwait_timer = 0; } - /* Grab a free ISDN-Channel */ if (((chi = isdn_get_free_channel( @@ -1492,7 +1551,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_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,15 +1560,13 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_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, "No channel"); dev_kfree_skb(skb); -#ifndef ISDN_NEW_TBUSY - ndev->tbusy = 0; -#endif return 0; } /* Log packet, which triggered dialing */ @@ -1528,9 +1586,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) } restore_flags(flags); isdn_net_dial(); /* Initiate dialing */ -#ifdef ISDN_NEW_TBUSY - isdn_net_dev_xoff(ndev); -#endif + netif_stop_queue(ndev); return 1; /* let upper layer requeue skb packet */ } #endif @@ -1544,9 +1600,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) } lp->first_skb = skb; /* Initiate dialing */ -#ifndef ISDN_NEW_TBUSY - ndev->tbusy = 0; -#endif restore_flags(flags); isdn_net_dial(); return 0; @@ -1554,9 +1607,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_unreachable(ndev, skb, "No phone number"); dev_kfree_skb(skb); -#ifndef ISDN_NEW_TBUSY - ndev->tbusy = 0; -#endif return 0; } } else { @@ -1567,24 +1617,16 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) int ret; if (lp->first_skb) { if (isdn_net_xmit(ndev, lp, lp->first_skb)){ -#ifdef ISDN_NEW_TBUSY - isdn_net_dev_xoff(ndev); -#endif + netif_stop_queue(ndev); return 1; } lp->first_skb = NULL; } ret = (isdn_net_xmit(ndev, lp, skb)); -#ifdef ISDN_NEW_TBUSY - if(ret) isdn_net_dev_xoff(ndev); -#endif + if(ret) netif_stop_queue(ndev); return ret; } else -#ifdef ISDN_NEW_TBUSY - isdn_net_dev_xoff(ndev); -#else - ndev->tbusy = 1; -#endif + netif_stop_queue(ndev); } } return 1; @@ -1606,8 +1648,7 @@ isdn_net_close(struct net_device *dev) #ifdef CONFIG_ISDN_X25 if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); #endif - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); if ((p = (((isdn_net_local *) dev->priv)->slave))) { /* If this interface has slaves, stop them also */ while (p) { @@ -1618,8 +1659,6 @@ isdn_net_close(struct net_device *dev) cprot -> pops -> close( cprot ); #endif isdn_net_hangup(p); - p->tbusy = 1; - p->start = 0; p = (((isdn_net_local *) p->priv)->slave); } } @@ -2360,7 +2399,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) * Is the interface up? * If not, reject the call actively. */ - if (!p->dev.start) { + if (!isdn_net_started(p)) { restore_flags(flags); printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", lp->name); @@ -2389,7 +2428,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 +2450,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 +2568,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); @@ -2626,11 +2667,13 @@ isdn_net_new(char *name, struct net_device *master) p = (((isdn_net_local *) p->priv)->slave); } ((isdn_net_local *) q->priv)->slave = &(netdev->dev); - q->interrupt = 0; - q->tbusy = 0; - q->start = master->start; } else { /* Device shall be a master */ + /* + * Watchdog timer (currently) for master only. + */ + netdev->dev.tx_timeout = isdn_net_tx_timeout; + netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT; if (register_netdev(&netdev->dev) != 0) { printk(KERN_WARNING "isdn_net: Could not register net-device\n"); kfree(netdev->local); @@ -2701,7 +2744,7 @@ isdn_net_newslave(char *parm) if (n->local->master) return NULL; /* Master must not be started yet */ - if (n->dev.start) + if (isdn_net_started(n)) return NULL; return (isdn_net_new(newname, &(n->dev))); } @@ -2744,9 +2787,8 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = p -> cprot; #endif - if (p->dev.start) { - printk(KERN_WARNING - "%s: cannot change encap when if is up\n", + if (isdn_net_started(p)) { + printk(KERN_WARNING "%s: cannot change encap when if is up\n", lp->name); return -EBUSY; } @@ -2837,10 +2879,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); @@ -3181,14 +3222,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) save_flags(flags); cli(); - if (p->local->master) { - /* If it's a slave, it may be removed even if it is busy. However - * it has to be hung up first. - */ - isdn_net_hangup(&p->dev); - p->dev.start = 0; - } - if (p->dev.start) { + if (isdn_net_started(p)) { restore_flags(flags); return -EBUSY; } diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index 06c2d83addd7..2551dc344d1b 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.62 2000/02/12 19:26:55 kai Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,31 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.62 2000/02/12 19:26:55 kai + * adopted to latest 2.3 softnet changes. + * + * tested with PPP and MPPP, it works here. + * can somebody check raw-ip? + * + * also changed std2kern, stddiff for bash-1 compatibility, + * hope this doesn't break anything. + * + * 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 +331,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.62 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; @@ -699,7 +724,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) case PPPIOCGIFNAME: if(!lp) return -EINVAL; - if ((r = set_arg((void *) arg, lp->name,strlen(lp->name)))) + if ((r = set_arg((void *) arg, lp->name, strlen(lp->name)))) return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ @@ -721,8 +746,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) } if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { if (lp) { - lp->netdev->dev.tbusy = 0; - mark_bh(NET_BH); /* OK .. we are ready to send buffers */ + /* OK .. we are ready to send buffers */ + netif_wake_queue(&lp->netdev->dev); } } is->pppcfg = val; diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index 5b301adb9db8..0503c67a279b 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 { @@ -2567,7 +2591,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; @@ -2668,8 +2692,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])) @@ -2720,7 +2743,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 @@ -3247,8 +3270,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: @@ -3280,6 +3317,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]++; @@ -3565,8 +3610,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; @@ -3582,11 +3629,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; @@ -3601,11 +3662,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; @@ -3995,6 +4062,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/net/3c505.c b/drivers/net/3c505.c index b61767c5f2dd..914918853f57 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -184,23 +184,9 @@ static const int addr_list[] __initdata = {0x300, 0x280, 0x310, 0}; /* Dma Memory related stuff */ -/* Pure 2^n version of get_order */ -static inline int __get_order(unsigned long size) -{ - int order; - - size = (size - 1) >> (PAGE_SHIFT - 1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static unsigned long dma_mem_alloc(int size) { - int order = __get_order(size); + int order = get_order(size); return __get_dma_pages(GFP_KERNEL, order); } @@ -1191,7 +1177,7 @@ static int elp_close(struct net_device *dev) free_irq(dev->irq, dev); free_dma(dev->dma); - free_pages((unsigned long) adapter->dma_buffer, __get_order(DMA_BUFFER_SIZE)); + free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE)); MOD_DEC_USE_COUNT; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 9de74e1b664a..8aa9ba63570f 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -274,34 +274,45 @@ enum pci_flags_bit { #define outl writel #endif + /* How to wait for the command unit to accept a command. Typically this takes 0 ticks. */ -static inline void wait_for_cmd_done(long cmd_ioaddr) +static inline void wait_for_cmd_done (long cmd_ioaddr) { int wait = 100; - do ; - while(inb(cmd_ioaddr) && --wait >= 0); + do; + while (inb (cmd_ioaddr) && --wait >= 0); } + /* Offsets to the various registers. All accesses need not be longword aligned. */ enum speedo_offsets { SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ - SCBPointer = 4, /* General purpose pointer. */ - SCBPort = 8, /* Misc. commands and operands. */ - SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ - SCBCtrlMDI = 16, /* MDI interface control. */ - SCBEarlyRx = 20, /* Early receive byte count. */ + SCBPointer = 4, /* General purpose pointer. */ + SCBPort = 8, /* Misc. commands and operands. */ + SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ + SCBCtrlMDI = 16, /* MDI interface control. */ + SCBEarlyRx = 20, /* Early receive byte count. */ }; + + /* Commands that can be put in a command list entry. */ enum commands { - CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000, - CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000, - CmdDump = 0x60000, CmdDiagnose = 0x70000, + CmdNOp = 0, + CmdIASetup = 0x10000, + CmdConfigure = 0x20000, + CmdMulticastList = 0x30000, + CmdTx = 0x40000, + CmdTDR = 0x50000, + CmdDump = 0x60000, + CmdDiagnose = 0x70000, CmdSuspend = 0x40000000, /* Suspend after completion. */ CmdIntr = 0x20000000, /* Interrupt after completion. */ CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */ }; + + /* Do atomically if possible. */ #if defined(__i386__) || defined(__alpha__) || defined(__ia64__) #define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status) @@ -1145,9 +1156,9 @@ static void speedo_tx_timeout(struct net_device *dev) sp->stats.tx_errors++; dev->trans_start = jiffies; netif_start_queue (dev); - return; } + static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1764,6 +1775,8 @@ static void eepro100_suspend (struct pci_dev *pdev) netif_stop_queue (dev); outl(PortPartialReset, ioaddr + SCBPort); + + /* XXX call pci_set_power_state ()? */ } diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index affd0cc3ea96..7190e350f9ff 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -15,8 +15,42 @@ Information and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html + + + + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the SMC "EPIC/100", the SMC +single-chip Ethernet controllers for PCI. This chip is used on +the SMC EtherPower II boards. + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS will assign the +PCI INTA signal to a (preferably otherwise unused) system IRQ line. +Note: Kernel versions earlier than 1.3.73 do not support shared PCI +interrupt lines. + +III. Driver operation + +IIIa. Ring buffers + +IVb. References + +http://www.smsc.com/main/datasheets/83c171.pdf +http://www.smsc.com/main/datasheets/83c175.pdf +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.national.com/pf/DP/DP83840A.html + +IVc. Errata + */ + + static const char *version = "epic100.c:v1.04 8/23/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n"; @@ -56,7 +90,6 @@ static int max_interrupt_work = 10; #include #include #include -#define PCI_SUPPORT_VER2 #include #include /* Processor type for cache alignment. */ @@ -72,6 +105,9 @@ static int max_interrupt_work = 10; #define RUN_AT(x) (jiffies + (x)) +#define EPIC100_MODULE_NAME "epic100" +#define PFX EPIC100_MODULE_NAME ": " + MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); MODULE_PARM(debug, "i"); @@ -86,82 +122,88 @@ MODULE_PARM(max_interrupt_work, "i"); #define epic_debug debug static int epic_debug = 1; -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the SMC "EPIC/100", the SMC -single-chip Ethernet controllers for PCI. This chip is used on -the SMC EtherPower II boards. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS will assign the -PCI INTA signal to a (preferably otherwise unused) system IRQ line. -Note: Kernel versions earlier than 1.3.73 do not support shared PCI -interrupt lines. - -III. Driver operation +/* The rest of these values should never change. */ -IIIa. Ring buffers -IVb. References +enum pci_flags_bit { + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, +}; -http://www.smsc.com/main/datasheets/83c171.pdf -http://www.smsc.com/main/datasheets/83c175.pdf -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html -http://www.national.com/pf/DP/DP83840A.html -IVc. Errata +typedef enum { + SMSC_83C170, + SMSC_83C175, +} chip_t; -*/ -/* The rest of these values should never change. */ +struct epic100_chip_info { + const char *name; +}; -static struct net_device *epic_probe1(struct pci_dev *pdev, long ioaddr, int irq, - int chip_id, int card_idx); -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, +/* indexed by chip_t */ +static struct epic100_chip_info epic100_chip_info[] __devinitdata = { + { "SMSC EPIC/100 83c170" }, + { "SMSC EPIC/C 83c175" }, }; -struct chip_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, pci_flags; - int io_size, min_latency; - struct net_device *(*probe1)(struct pci_dev *pdev, - long ioaddr, int irq, int chip_idx, - int fnd_cnt); -} chip_tbl[] = { - {"SMSC EPIC/100 83c170", 0x10B8, 0x0005, 0x7fff, - PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1}, - {"SMSC EPIC/C 83c175", 0x10B8, 0x0006, 0x7fff, - PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1}, - {0,}, + +static struct pci_device_id epic100_pci_tbl[] __devinitdata = { + { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170, }, + { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C175, }, + { 0,}, }; +MODULE_DEVICE_TABLE (pci, epic100_pci_tbl); + /* Offsets to registers, using the (ugh) SMC names. */ enum epic_registers { - COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14, - PCIBurstCnt=0x18, - TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28, /* Rx error counters. */ - MIICtrl=0x30, MIIData=0x34, MIICfg=0x38, - LAN0=64, /* MAC address. */ - MC0=80, /* Multicast filter table. */ - RxCtrl=96, TxCtrl=112, TxSTAT=0x74, - PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC, + COMMAND = 0, + INTSTAT = 4, + INTMASK = 8, + GENCTL = 0x0C, + NVCTL = 0x10, + EECTL = 0x14, + PCIBurstCnt = 0x18, + TEST1 = 0x1C, + CRCCNT = 0x20, + ALICNT = 0x24, + MPCNT = 0x28, /* Rx error counters. */ + MIICtrl = 0x30, + MIIData = 0x34, + MIICfg = 0x38, + LAN0 = 64, /* MAC address. */ + MC0 = 80, /* Multicast filter table. */ + RxCtrl = 96, + TxCtrl = 112, + TxSTAT = 0x74, + PRxCDAR = 0x84, + RxSTAT = 0xA4, + EarlyRx = 0xB0, + PTxCDAR = 0xC4, + TxThresh = 0xDC, }; + /* Interrupt register bits, using my own meaningful names. */ enum IntrStatus { - TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000, - PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000, - RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100, - TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010, - RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001, + TxIdle = 0x40000, + RxIdle = 0x20000, + IntrSummary = 0x010000, + PCIBusErr170 = 0x7000, + PCIBusErr175 = 0x1000, + PhyEvent175 = 0x8000, + RxStarted = 0x0800, + RxEarlyWarn = 0x0400, + CntFull = 0x0200, + TxUnderrun = 0x0100, + TxEmpty = 0x0080, + TxDone = 0x0020, RxError = 0x0010, + RxOverflow = 0x0008, + RxFull = 0x0004, + RxHeader = 0x0002, + RxDone = 0x0001, }; /* The EPIC100 Rx and Tx buffer descriptors. */ @@ -202,7 +244,7 @@ struct epic_private { unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - u8 pci_bus, pci_dev_fn; /* PCI bus location. */ + struct pci_dev *pdev; u16 chip_id; struct net_device_stats stats; @@ -240,196 +282,9 @@ static int epic_close(struct net_device *dev); static struct net_device_stats *epic_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); - -/* A list of all installed EPIC devices, for removing the driver module. */ -static struct net_device *root_epic_dev = NULL; - -#ifndef CARDBUS -static int __init epic100_probe(void) -{ - int cards_found = 0; - int chip_idx, irq; - u16 pci_command, new_command; - unsigned char pci_bus, pci_device_fn; - struct net_device *dev; - - struct pci_dev *pcidev = NULL; - while ((pcidev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pcidev)) - != NULL) { - long pci_ioaddr = pcidev->resource[0].start; - int vendor = pcidev->vendor; - int device = pcidev->device; - - for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == chip_tbl[chip_idx].vendor_id - && (device & chip_tbl[chip_idx].device_id_mask) == - chip_tbl[chip_idx].device_id) - break; - if (chip_tbl[chip_idx].vendor_id == 0 /* Compiled out! */ - || check_region(pci_ioaddr, chip_tbl[chip_idx].io_size)) - continue; - pci_bus = pcidev->bus->number; - pci_device_fn = pcidev->devfn; - irq = pcidev->irq; - - /* EPIC-specific code: Soft-reset the chip ere setting as master. */ - outl(0x0001, pci_ioaddr + GENCTL); - - /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - pci_read_config_word(pcidev, PCI_COMMAND, &pci_command); - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled Ethernet" - " device %4.4x-%4.4x." - " Updating PCI command %4.4x->%4.4x.\n", - vendor, device, pci_command, new_command); - pci_write_config_word(pcidev, PCI_COMMAND, new_command); - } - - dev = chip_tbl[chip_idx].probe1(pcidev, pci_ioaddr, irq, - chip_idx, cards_found); - - /* Check the latency timer. */ - if (dev) { - u8 pci_latency; - pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < chip_tbl[chip_idx].min_latency) { - printk(KERN_INFO " PCI latency timer (CFLT) value of %d is " - "unreasonably low, setting to %d.\n", pci_latency, - chip_tbl[chip_idx].min_latency); - pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, - chip_tbl[chip_idx].min_latency); - } - dev = 0; - cards_found++; - } - } - - return cards_found ? 0 : -ENODEV; -} -#endif /* not CARDBUS */ - -static struct net_device *epic_probe1(struct pci_dev *pdev, long ioaddr, int irq, - int chip_idx, int card_idx) -{ - struct epic_private *ep; - int i, option = 0, duplex = 0; - struct net_device *dev; - -// FIXME if (dev && dev->mem_start) { -// option = dev->mem_start; -// duplex = (dev->mem_start & 16) ? 1 : 0; -// } -// else - if (card_idx >= 0 && card_idx < MAX_UNITS) { - if (options[card_idx] >= 0) - option = options[card_idx]; - if (full_duplex[card_idx] >= 0) - duplex = full_duplex[card_idx]; - } - - dev = init_etherdev(NULL, 0); - - dev->base_addr = ioaddr; - dev->irq = irq; - printk(KERN_INFO "%s: SMC EPIC/100 at %#lx, IRQ %d, ", - dev->name, ioaddr, dev->irq); - - /* Bring the chip out of low-power mode. */ - outl(0x4200, ioaddr + GENCTL); - /* Magic?! If we don't set this bit the MII interface won't work. */ - outl(0x0008, ioaddr + TEST1); - - /* Turn on the MII transceiver. */ - outl(0x12, ioaddr + MIICfg); - if (chip_idx == 1) - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); - outl(0x0200, ioaddr + GENCTL); - - /* This could also be read from the EEPROM. */ - for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4); - - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); - - if (epic_debug > 1) { - printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name); - for (i = 0; i < 64; i++) - printk(" %4.4x%s", read_eeprom(ioaddr, i), - i % 16 == 15 ? "\n" : ""); - } - - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, EPIC_TOTAL_SIZE, dev->name); - - /* The data structures must be quadword aligned. */ - ep = kmalloc(sizeof(*ep), GFP_KERNEL | GFP_DMA); - memset(ep, 0, sizeof(*ep)); - dev->priv = ep; - - ep->next_module = root_epic_dev; - root_epic_dev = dev; - - ep->lock = SPIN_LOCK_UNLOCKED; - ep->pci_bus = pdev->bus->number; - ep->pci_dev_fn = pdev->devfn; - ep->chip_id = pdev->device; - - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ - { - int phy, phy_idx; - for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys); - phy++) { - int mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { - ep->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver #%d control " - "%4.4x status %4.4x.\n" - KERN_INFO "%s: Autonegotiation advertising %4.4x " - "link partner %4.4x.\n", - dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status, - dev->name, mdio_read(ioaddr, phy, 4), - mdio_read(ioaddr, phy, 5)); - } - } - if (phy_idx == 0) { - printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", - dev->name); - /* Use the known PHY address of the EPII. */ - ep->phys[0] = 3; - } - } - - /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */ - if (ep->chip_id == 6) - outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL); - outl(0x0008, ioaddr + GENCTL); - /* The lower four bits are the media type. */ - ep->force_fd = duplex; - ep->default_port = option; - if (ep->default_port) - ep->medialock = 1; - /* The Epic-specific entries in the device structure. */ - dev->open = &epic_open; - dev->hard_start_xmit = &epic_start_xmit; - dev->stop = &epic_close; - dev->get_stats = &epic_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; - dev->tx_timeout = epic_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - netif_stop_queue (dev); - return dev; -} - /* Serial EEPROM section. */ /* EEPROM_Ctrl bits. */ @@ -533,7 +388,7 @@ epic_open(struct net_device *dev) /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); - if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev)) { + if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, EPIC100_MODULE_NAME, dev)) { MOD_DEC_USE_COUNT; return -EBUSY; } @@ -609,6 +464,7 @@ epic_open(struct net_device *dev) return 0; } + /* Reset the chip to recover from a PCI transaction error. This may occur at interrupt time. */ static void epic_pause(struct net_device *dev) @@ -978,6 +834,7 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) spin_unlock (&ep->lock); } + static int epic_rx(struct net_device *dev) { struct epic_private *ep = (struct epic_private *)dev->priv; @@ -1054,6 +911,7 @@ static int epic_rx(struct net_device *dev) return work_done; } + static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1106,6 +964,7 @@ static int epic_close(struct net_device *dev) return 0; } + static struct net_device_stats *epic_get_stats(struct net_device *dev) { struct epic_private *ep = (struct epic_private *)dev->priv; @@ -1121,6 +980,7 @@ static struct net_device_stats *epic_get_stats(struct net_device *dev) return &ep->stats; } + /* Set or clear the multicast filter for this adaptor. Note that we only use exclusion around actually queueing the new frame, not around filling ep->setup_frame. This is non-deterministic @@ -1187,6 +1047,7 @@ static void set_rx_mode(struct net_device *dev) return; } + static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { long ioaddr = dev->base_addr; @@ -1229,132 +1090,213 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } - -#ifdef CARDBUS - -#include -static dev_node_t *epic_attach(dev_locator_t *loc) +static int __devinit epic100_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { + struct epic_private *ep; + int i, option = 0, duplex = 0, irq, chip_idx; struct net_device *dev; - u16 dev_id; - u32 io; - u8 irq; - struct pci_dev *pdev; - - if (loc->bus != LOC_PCI) return NULL; - pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); - if (!pdev) return NULL; - printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", - pdev->bus->number, pdev->devfn); - io = pdev->resource[0].start; + long ioaddr; + static int card_idx = -1; + + chip_idx = ent->driver_data; + + ioaddr = pci_resource_start (pdev, 0); + if (!ioaddr) + return -ENODEV; + irq = pdev->irq; - dev_id = pdev->device; - io &= ~3; - if (io == 0 || irq == 0) { - printk(KERN_ERR "The EPIC/C CardBus Ethernet interface was not " - "assigned an %s.\n" KERN_ERR " It will not be activated.\n", - io == 0 ? "I/O address" : "IRQ"); - return NULL; - } - dev = epic_probe1(pdev, io, irq, 2, -1); - if (dev) { - dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - strcpy(node->dev_name, dev->name); - node->major = node->minor = 0; - node->next = NULL; - MOD_INC_USE_COUNT; - return node; - } - return NULL; -} + if (!irq) + return -ENODEV; -static void epic_suspend(dev_node_t *node) -{ - struct net_device **devp, **next; - printk(KERN_INFO "epic_suspend(%s)\n", node->dev_name); - for (devp = &root_epic_dev; *devp; devp = next) { - next = &((struct epic_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; - } - if (*devp) { - long ioaddr = (*devp)->base_addr; - epic_pause(*devp); - /* Put the chip into low-power mode. */ - outl(0x0008, ioaddr + GENCTL); + /* We do a request_region() to register /proc/ioports info. */ + if (!request_region(ioaddr, EPIC_TOTAL_SIZE, EPIC100_MODULE_NAME)) + return -EBUSY; + + pci_enable_device (pdev); + + /* EPIC-specific code: Soft-reset the chip ere setting as master. */ + outl(0x0001, ioaddr + GENCTL); + + pci_set_master (pdev); + +// FIXME if (dev && dev->mem_start) { +// option = dev->mem_start; +// duplex = (dev->mem_start & 16) ? 1 : 0; +// } +// else + + card_idx++; + if (card_idx >= 0 && card_idx < MAX_UNITS) { + if (options[card_idx] >= 0) + option = options[card_idx]; + if (full_duplex[card_idx] >= 0) + duplex = full_duplex[card_idx]; } -} -static void epic_resume(dev_node_t *node) -{ - struct net_device **devp, **next; - printk(KERN_INFO "epic_resume(%s)\n", node->dev_name); - for (devp = &root_epic_dev; *devp; devp = next) { - next = &((struct epic_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; + + dev = init_etherdev(NULL, sizeof (*ep)); + if (!dev) + goto err_out_free_region; + + dev->base_addr = ioaddr; + dev->irq = irq; + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", + dev->name, epic100_chip_info[chip_idx].name, + ioaddr, dev->irq); + + /* Bring the chip out of low-power mode. */ + outl(0x4200, ioaddr + GENCTL); + /* Magic?! If we don't set this bit the MII interface won't work. */ + outl(0x0008, ioaddr + TEST1); + + /* Turn on the MII transceiver. */ + outl(0x12, ioaddr + MIICfg); + if (chip_idx == 1) + outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); + outl(0x0200, ioaddr + GENCTL); + + /* This could also be read from the EEPROM. */ + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4); + + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + + if (epic_debug > 1) { + printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name); + for (i = 0; i < 64; i++) + printk(" %4.4x%s", read_eeprom(ioaddr, i), + i % 16 == 15 ? "\n" : ""); } - if (*devp) { - epic_restart(*devp); + + /* The data structures must be quadword aligned, + * init_etherdev ensures this */ + ep = dev->priv; + memset(ep, 0, sizeof(*ep)); + + ep->lock = SPIN_LOCK_UNLOCKED; + ep->chip_id = pdev->device; + ep->pdev = pdev; + pdev->driver_data = dev; + + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + { + int phy, phy_idx; + for (phy = 1, phy_idx = 0; phy < 32 && phy_idx < sizeof(ep->phys); + phy++) { + int mii_status = mdio_read(ioaddr, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + ep->phys[phy_idx++] = phy; + printk(KERN_INFO "%s: MII transceiver #%d control " + "%4.4x status %4.4x.\n" + KERN_INFO "%s: Autonegotiation advertising %4.4x " + "link partner %4.4x.\n", + dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status, + dev->name, mdio_read(ioaddr, phy, 4), + mdio_read(ioaddr, phy, 5)); + } + } + if (phy_idx == 0) { + printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + /* Use the known PHY address of the EPII. */ + ep->phys[0] = 3; + } } + + /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */ + if (ep->chip_id == 6) + outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL); + outl(0x0008, ioaddr + GENCTL); + + /* The lower four bits are the media type. */ + ep->force_fd = duplex; + ep->default_port = option; + if (ep->default_port) + ep->medialock = 1; + + /* The Epic-specific entries in the device structure. */ + dev->open = epic_open; + dev->hard_start_xmit = epic_start_xmit; + dev->stop = epic_close; + dev->get_stats = epic_get_stats; + dev->set_multicast_list = set_rx_mode; + dev->do_ioctl = mii_ioctl; + dev->tx_timeout = epic_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + netif_stop_queue (dev); + + return 0; + +err_out_free_region: + release_region(ioaddr, EPIC_TOTAL_SIZE); + return -ENODEV; } -static void epic_detach(dev_node_t *node) + + +static void __devexit epic100_remove_one (struct pci_dev *pdev) { - struct net_device **devp, **next; - printk(KERN_INFO "epic_detach(%s)\n", node->dev_name); - for (devp = &root_epic_dev; *devp; devp = next) { - next = &((struct epic_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; - } - if (*devp) { - unregister_netdev(*devp); - kfree(*devp); - *devp = *next; - kfree(node); - MOD_DEC_USE_COUNT; - } + struct net_device *dev = pdev->driver_data; + + unregister_netdev(dev); + release_region(dev->base_addr, EPIC_TOTAL_SIZE); + kfree(dev); } -struct driver_operations epic_ops = { - "epic_cb", epic_attach, epic_suspend, epic_resume, epic_detach -}; -#endif /* Cardbus support */ +static void epic100_suspend (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + long ioaddr = dev->base_addr; + + epic_pause(dev); + /* Put the chip into low-power mode. */ + outl(0x0008, ioaddr + GENCTL); +} -static int __init epic100_init_module(void) +static void epic100_resume (struct pci_dev *pdev) { - if (epic_debug) - printk(KERN_INFO "%s", version); + struct net_device *dev = pdev->driver_data; -#ifdef CARDBUS - register_driver(&epic_ops); - return 0; -#else - return epic100_probe(); -#endif + epic_restart (dev); } -static void __exit epic100_cleanup_module(void) + +static struct pci_driver epic100_driver = { + name: EPIC100_MODULE_NAME, + id_table: epic100_pci_tbl, + probe: epic100_init_one, + remove: epic100_remove_one, + suspend: epic100_suspend, + resume: epic100_resume, +}; + + +static int __init epic100_init (void) { - struct net_device *next_dev; + printk (KERN_INFO "%s", version); + + if (pci_register_driver (&epic100_driver) > 0) + return 0; + + return -ENODEV; +} -#ifdef CARDBUS - unregister_driver(&epic_ops); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_epic_dev) { - struct epic_private *ep = (struct epic_private *)root_epic_dev->priv; - next_dev = ep->next_module; - unregister_netdev(root_epic_dev); - release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE); - kfree(root_epic_dev); - root_epic_dev = next_dev; - kfree(ep); - } +static void __exit epic100_cleanup (void) +{ + pci_unregister_driver (&epic100_driver); } -module_init(epic100_init_module); -module_exit(epic100_cleanup_module); + +module_init(epic100_init); +module_exit(epic100_cleanup); /* diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index e35eddb449c1..536b82165fdb 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -381,11 +381,11 @@ void hdlcdrv_transmitter(struct net_device *dev, struct hdlcdrv_state *s) if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { s->hdlctx.tx_state = 0; s->hdlctx.numflags = 1; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); break; } memcpy(s->hdlctx.buffer, skb->data+1, pkt_len); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); s->hdlctx.bp = s->hdlctx.buffer; append_crc_ccitt(s->hdlctx.buffer, pkt_len); s->hdlctx.len = pkt_len+2; /* the appended CRC */ diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c index f572a5ea65b6..e461f8807137 100644 --- a/drivers/net/ltpc.c +++ b/drivers/net/ltpc.c @@ -246,23 +246,9 @@ static int sendup_buffer (struct net_device *dev); /* Dma Memory related stuff, cribbed directly from 3c505.c */ -/* Pure 2^n version of get_order */ -static inline int __get_order(unsigned long size) -{ - int order; - - size = (size - 1) >> (PAGE_SHIFT - 1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static unsigned long dma_mem_alloc(int size) { - int order = __get_order(size); + int order = get_order(size); return __get_dma_pages(GFP_KERNEL, order); } @@ -1364,7 +1350,7 @@ void cleanup_module(void) if(debug&DEBUG_VERBOSE) printk("free_pages\n"); - free_pages( (unsigned long) ltdmabuf, __get_order(1000)); + free_pages( (unsigned long) ltdmabuf, get_order(1000)); ltdmabuf=NULL; ltdmacbuf=NULL; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 1e53dc964f31..c72546740693 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -105,11 +105,6 @@ MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(full_duplex, "i"); -#ifdef BROKEN_FEATURES -MODULE_PARM(use_fifo_buffer, "i"); -MODULE_PARM(use_memory_ops, "i"); -MODULE_PARM(no_wait, "i"); -#endif /* Now-standard PC card module parameters. */ static u_int irq_mask = 0xdeb8; /* IRQ3,4,5,7,9,10,11,12,14,15 */ @@ -124,16 +119,6 @@ static int max_interrupt_work = 32; /* Force full duplex modes? */ static int full_duplex = 0; -#ifdef BROKEN_FEATURES -/* Performance features: best left disabled. */ -/* Set to buffer all Tx/RxFIFO accesses. */ -static int use_fifo_buffer = 0; -/* Set iff memory ops are faster than I/O ops. */ -static int use_memory_ops = 0; -/* Set iff disabling the WAIT signal is reliable and faster. */ -static int no_wait = 0; -#endif - /* To minimize the size of the driver source and make the driver more readable not all constants are symbolically defined. You'll need the manual if you want to understand driver details anyway. */ @@ -484,27 +469,6 @@ static void tc574_config(dev_link_t *link) CS_CHECK(RequestIRQ, link->handle, &link->irq); CS_CHECK(RequestConfiguration, link->handle, &link->conf); - dev->mem_start = 0; -#ifdef BROKEN_FEATURES - if (use_memory_ops) { - win_req_t req; - memreq_t mem; - req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | - WIN_ENABLE | WIN_USE_WAIT; - req.Base = 0; - req.Size = 0x1000; - req.AccessSpeed = 0; - link->win = (window_handle_t)link->handle; - i = CardServices(RequestWindow, &link->win, &req); - if (i == CS_SUCCESS) { - mem.Page = mem.CardOffset = 0; - CardServices(MapMemPage, link->win, &mem); - dev->mem_start = (long)(ioremap(req.Base, 0x1000)) + 0x800; - } else - cs_error(link->handle, RequestWindow, i); - } -#endif - dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -551,10 +515,6 @@ static void tc574_config(dev_link_t *link) for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n")); - if (dev->mem_start) - printk(KERN_INFO" Acceleration window at memory base %#lx.\n", - dev->mem_start); - { u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; union wn3_config config; @@ -629,8 +589,6 @@ failed: static void tc574_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; - struct el3_private *lp = link->priv; - struct net_device *dev = &lp->dev; DEBUG(0, "3c574_release(0x%p)\n", link); @@ -644,10 +602,6 @@ static void tc574_release(u_long arg) CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); - if (link->win) { - iounmap((void *)(dev->mem_start - 0x800)); - CardServices(ReleaseWindow, link->win); - } link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); @@ -674,6 +628,7 @@ static int tc574_event(event_t event, int priority, link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -689,6 +644,7 @@ static int tc574_event(event_t event, int priority, if (link->state & DEV_CONFIG) { if (link->open) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); } CardServices(ReleaseConfiguration, link->handle); } @@ -701,6 +657,7 @@ static int tc574_event(event_t event, int priority, CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { tc574_reset(dev); + set_bit(LINK_STATE_START, &dev->state); netif_start_queue (dev); } } @@ -837,19 +794,6 @@ static void tc574_reset(struct net_device *dev) wait_for_completion(dev, TotalReset|0x10); -#ifdef BROKEN_FEATURES - /* Set the PIO ctrl bits in the PC card LAN COR using Runner window 1. */ - if (dev->mem_start || no_wait) { - u8 lan_cor; - outw(1<<11, ioaddr + RunnerRdCtrl); - lan_cor = inw(ioaddr) & ~0x30; - if (dev->mem_start) /* Iff use_memory_ops worked! */ - lan_cor |= 0x10; - if (no_wait) - lan_cor |= 0x20; - outw(lan_cor, ioaddr); - } -#endif /* Clear any transactions in progress. */ outw(0, ioaddr + RunnerWrCtrl); outw(0, ioaddr + RunnerRdCtrl); @@ -883,10 +827,10 @@ static void tc574_reset(struct net_device *dev) inb(ioaddr + i); inw(ioaddr + 10); inw(ioaddr + 12); - EL3WINDOW(4); - /* New: On the Vortex/Odie we must also clear the BadSSD counter.. */ inb(ioaddr + 12); + inb(ioaddr + 13); + /* .. enable any extra statistics bits.. */ outw(0x0040, ioaddr + Wn4_NetDiag); /* .. re-sync MII and re-fill what NWay is advertising. */ @@ -974,9 +918,6 @@ static void pop_tx_status(struct net_device *dev) static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; -#ifdef BROKEN_FEATURES - long flags = 0; -#endif DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " "status %4.4x.\n", dev->name, (long)skb->len, @@ -984,38 +925,9 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue (dev); -#ifdef BROKEN_FEATURES - if (use_fifo_buffer) { - /* Avoid other accesses to the chip while RunnerWrCtrl is non-zero. */ - spin_lock_irqsave(&lp->lock, flags); - outw((((skb->len + 7)>>2)<<1), ioaddr + RunnerWrCtrl); - DEBUG(0, "TxFree %x, tx length %x, RunnerWrCtrl is %4.4x.\n", - inw(ioaddr+TxFree), skb->len, inw(ioaddr+RunnerWrCtrl)); - } - - /* Put out the doubleword header... */ - /* ... and the packet rounded to a doubleword. */ - if (dev->mem_start) { - writew(skb->len, (void *)dev->mem_start); - writew(0, (void *)dev->mem_start); - copy_to_pc((void*)dev->mem_start, skb->data, (skb->len+3)&~3); - } else { - outw(skb->len, ioaddr + TX_FIFO); - outw(0, ioaddr + TX_FIFO); - outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2); - } - - if (use_fifo_buffer) { - DEBUG(0, " RunnerWr/RdCtrl is %4.4x/%4.4x, TxFree %x.\n", - inw(ioaddr + RunnerWrCtrl), inw(ioaddr + RunnerRdCtrl), - inw(ioaddr + TxFree)); - spin_unlock_irqrestore (&lp->lock, flags); - } -#else outw(skb->len, ioaddr + TX_FIFO); outw(0, ioaddr + TX_FIFO); outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2); -#endif dev->trans_start = jiffies; @@ -1041,27 +953,24 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) ioaddr_t ioaddr, status; int work_budget = max_interrupt_work; - if (lp == NULL) + if (!test_bit(LINK_STATE_START, &dev->state)) return; spin_lock (&lp->lock); ioaddr = dev->base_addr; -#ifdef PCMCIA_DEBUG DEBUG(3, "%s: interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); -#endif while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | RxEarly | StatsFull)) { -#if 0 - if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) { + if (!test_bit(LINK_STATE_START, &dev->state) || + ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: Interrupt from dead card\n", dev->name); break; } -#endif if (status & RxComplete) work_budget = el3_rx(dev, work_budget); @@ -1119,10 +1028,8 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); } -#ifdef PCMCIA_DEBUG DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); -#endif spin_unlock (&lp->lock); } @@ -1140,9 +1047,8 @@ static void media_check(u_long arg) u_long flags; u_short /* cable, */ media, partner; -#if 0 - if (dev->start == 0) goto reschedule; -#endif + if (!test_bit(LINK_STATE_START, &dev->state)) + goto reschedule; /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ @@ -1253,6 +1159,12 @@ static void update_stats(struct net_device *dev) EL3WINDOW(4); inb(ioaddr + 12); + { + u8 up = inb(ioaddr + 13); + lp->stats.rx_bytes += (up & 0x0f) << 16; + lp->stats.tx_bytes += (up & 0xf0) << 12; + } + EL3WINDOW(1); } @@ -1289,30 +1201,8 @@ static int el3_rx(struct net_device *dev, int worklimit) skb->dev = dev; skb_reserve(skb, 2); -#ifdef BROKEN_FEATURES - if (use_fifo_buffer) { - outw(((pkt_len+3)>>2)<<1, ioaddr + RunnerRdCtrl); - DEBUG(0,"Start Rx %x -- RunnerRdCtrl is %4.4x.\n", - pkt_len, inw(ioaddr + RunnerRdCtrl)); - } - if (dev->mem_start) { - copy_from_pc(skb_put(skb, pkt_len), - (void*)dev->mem_start, (pkt_len+3)&~3); - } else { - insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), - ((pkt_len+3)>>2)); - } - if (use_fifo_buffer) { - DEBUG(0," RunnerRdCtrl is now %4.4x.\n", - inw(ioaddr + RunnerRdCtrl)); - outw(0, ioaddr + RunnerRdCtrl); - DEBUG(0, " Rx packet with data %2.2x:%2.2x:%2.2x\n", - skb->head[0], skb->head[1], skb->head[2]); - } -#else insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), ((pkt_len+3)>>2)); -#endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index b819be85616e..60ec6ebe71f2 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -4,7 +4,7 @@ Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org - 3c589_cs.c 1.143 1999/12/30 21:28:10 + 3c589_cs.c 1.145 2000/02/11 03:11:51 The network driver code is based on Donald Becker's 3c589 code: @@ -117,7 +117,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.143 1999/12/30 21:28:10 (David Hinds)"; +"3c589_cs.c 1.145 2000/02/11 03:11:51 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -513,6 +513,7 @@ static int tc589_event(event_t event, int priority, link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -528,6 +529,7 @@ static int tc589_event(event_t event, int priority, if (link->state & DEV_CONFIG) { if (link->open) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); } CardServices(ReleaseConfiguration, link->handle); } @@ -540,6 +542,7 @@ static int tc589_event(event_t event, int priority, CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { tc589_reset(dev); + set_bit(LINK_STATE_START, &dev->state); netif_start_queue (dev); } } @@ -748,22 +751,22 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) inw(ioaddr + EL3_STATUS)); netif_stop_queue (dev); - if (1) { + { struct el3_private *lp = (struct el3_private *)dev->priv; lp->stats.tx_bytes += skb->len; - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0x00, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - - dev->trans_start = jiffies; - if (inw(ioaddr + TX_FREE) > 1536) { - netif_start_queue (dev); - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); } + /* Put out the doubleword header... */ + outw(skb->len, ioaddr + TX_FIFO); + outw(0x00, ioaddr + TX_FIFO); + /* ... and the packet rounded to a doubleword. */ + outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); + + dev->trans_start = jiffies; + if (inw(ioaddr + TX_FREE) > 1536) { + netif_start_queue (dev); + } else + /* Interrupt us when the FIFO has room for max-sized packet. */ + outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); dev_kfree_skb(skb); pop_tx_status(dev); @@ -779,29 +782,20 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) ioaddr_t ioaddr, status; int i = 0; - if (lp == NULL) + if (!test_bit(LINK_STATE_START, &dev->state)) return; ioaddr = dev->base_addr; -#ifdef PCMCIA_DEBUG - if (dev->interrupt) { - printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n", - dev->name); - return; - } - dev->interrupt = 1; DEBUG(3, "%s: interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); -#endif while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { -#if 0 - if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) { + if (!test_bit(LINK_STATE_START, &dev->state) || + ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); break; } -#endif if (status & RxComplete) el3_rx(dev); @@ -860,11 +854,8 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) } lp->last_irq = jiffies; -#ifdef PCMCIA_DEBUG DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); - dev->interrupt = 0; -#endif return; } @@ -876,9 +867,8 @@ static void media_check(u_long arg) u_short media, errs; u_long flags; -#if 0 - if (dev->start == 0) goto reschedule; -#endif + if (!test_bit(LINK_STATE_START, &dev->state)) + goto reschedule; EL3WINDOW(1); /* Check for pending interrupt with expired latency timer: with diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in index 243b5c89648a..2a3011532230 100644 --- a/drivers/net/pcmcia/Config.in +++ b/drivers/net/pcmcia/Config.in @@ -20,7 +20,6 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then if [ "$CONFIG_CARDBUS" = "y" ]; then dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m dep_tristate ' DEC Tulip CardBus support' CONFIG_PCMCIA_TULIP m - dep_tristate ' SMC EPIC CardBus support' CONFIG_PCMCIA_EPIC100 m fi bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile index dfd4ef18630d..11c583dac58c 100644 --- a/drivers/net/pcmcia/Makefile +++ b/drivers/net/pcmcia/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o # Cardbus client drivers obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o obj-$(CONFIG_PCMCIA_TULIP) += tulip_cb.o -obj-$(CONFIG_PCMCIA_EPIC100) += epic100_cb.o O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) @@ -49,6 +48,3 @@ M_OBJS := $(filter-out $(export-objs), $(obj-m)) MX_OBJS := $(filter $(export-objs), $(obj-m)) include $(TOPDIR)/Rules.make - -epic100_cb.o: ../epic100.c - $(CC) $(CFLAGS) -DMODULE -DCARDBUS -c -o $@ ../epic100.c diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index f13b02889daf..0dbf0e85c96b 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -594,6 +594,7 @@ static int fmvj18x_event(event_t event, int priority, link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -609,6 +610,7 @@ static int fmvj18x_event(event_t event, int priority, if (link->state & DEV_CONFIG) { if (link->open) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); } CardServices(ReleaseConfiguration, link->handle); } @@ -621,6 +623,7 @@ static int fmvj18x_event(event_t event, int priority, CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { fjn_reset(dev); + set_bit(LINK_STATE_START, &dev->state); netif_start_queue (dev); } } diff --git a/drivers/net/pcmcia/netwave_cs.c b/drivers/net/pcmcia/netwave_cs.c index dd99d84acef9..b1214ae2ed8e 100644 --- a/drivers/net/pcmcia/netwave_cs.c +++ b/drivers/net/pcmcia/netwave_cs.c @@ -1020,6 +1020,7 @@ static int netwave_event(event_t event, int priority, link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); link->release.expires = jiffies + 5; add_timer(&link->release); } @@ -1035,6 +1036,7 @@ static int netwave_event(event_t event, int priority, if (link->state & DEV_CONFIG) { if (link->open) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); } CardServices(ReleaseConfiguration, link->handle); } @@ -1047,6 +1049,7 @@ static int netwave_event(event_t event, int priority, CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { netwave_reset(dev); + set_bit(LINK_STATE_START, &dev->state); netif_start_queue (dev); } } @@ -1296,7 +1299,7 @@ static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) { dev_link_t *link = &priv->link; int i; - if (dev == NULL) + if ((dev == NULL) || !test_bit(LINK_STATE_START, &dev->state)) return; spin_lock (&priv->lock); diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index a3c22cc7a4b1..4a4ebf2aef39 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -1153,6 +1153,11 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) return; } + if (!test_bit(LINK_STATE_START, &dev->state)) { + DEBUG(2, "%s: interrupt from dead card\n", dev->name); + goto exception; + } + do { /* WARNING: MACE_IR is a READ/CLEAR port! */ status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 0af9aa04d670..f1b5bc02cbc1 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -11,7 +11,7 @@ Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org - pcnet_cs.c 1.110 1999/12/06 21:39:18 + pcnet_cs.c 1.112 2000/02/11 01:24:44 The network driver code is based on Donald Becker's NE2000 code: @@ -72,7 +72,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.110 1999/12/06 21:39:18 (David Hinds)"; +"pcnet_cs.c 1.112 2000/02/11 01:24:44 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -211,7 +211,8 @@ static hw_info_t hw_info[] = { DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF }, { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 }, { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 }, - { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 } + { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 }, + { /* PCMCIA Technology OEM */ 0x01c8, 0xa0, 0x0c, 0 } }; #define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) @@ -306,7 +307,6 @@ static dev_link_t *pcnet_attach(void) for (i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; ethdev_init(dev); @@ -596,6 +596,7 @@ static void pcnet_config(dev_link_t *link) int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; int manfid = 0, prodid = 0, has_shmem = 0; u_short buf[64]; + config_info_t conf; hw_info_t *hw_info; DEBUG(0, "pcnet_config(0x%p)\n", link); @@ -614,6 +615,10 @@ static void pcnet_config(dev_link_t *link) /* Configure card */ link->state |= DEV_CONFIG; + /* Look up current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && @@ -908,7 +913,6 @@ static int pcnet_close(struct net_device *dev) free_irq(dev->irq, dev); link->open--; - clear_bit(LINK_STATE_START, &dev->state); del_timer(&info->watchdog); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 897e93d03fcb..1b84dba11c7c 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1113,6 +1113,7 @@ static int smc91c92_event(event_t event, int priority, link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; add_timer(&link->release); @@ -1129,6 +1130,7 @@ static int smc91c92_event(event_t event, int priority, if (link->state & DEV_CONFIG) { if (link->open) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); } CardServices(ReleaseConfiguration, link->handle); } @@ -1152,6 +1154,7 @@ static int smc91c92_event(event_t event, int priority, } if (link->open) { smc_reset(dev); + set_bit(LINK_STATE_START, &dev->state); netif_start_queue (dev); } } @@ -1503,16 +1506,14 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) u_short saved_bank, saved_pointer, mask, status; char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ - if (smc == NULL) + if ((smc == NULL) || !test_bit(LINK_STATE_START, &dev->state)) return; ioaddr = dev->base_addr; spin_lock (&smc->lock); -#ifdef PCMCIA_DEBUG DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name, irq, ioaddr); -#endif smc->watchdog = 0; saved_bank = inw(ioaddr + BANK_SELECT); @@ -1523,7 +1524,6 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (dev->start) DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent" "/ejected device.\n", dev->name, irq); - dev->interrupt = 0; #endif goto irq_done; } @@ -1588,9 +1588,7 @@ static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock (&smc->lock); -#ifdef PCMCIA_DEBUG DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq); -#endif irq_done: @@ -1912,9 +1910,8 @@ static void media_check(u_long arg) ioaddr_t ioaddr = dev->base_addr; u_short i, media, saved_bank; -#if 0 - if (dev->start == 0) goto reschedule; -#endif + if (!test_bit(LINK_STATE_START, &dev->state)) + goto reschedule; saved_bank = inw(ioaddr + BANK_SELECT); SMC_SELECT_BANK(2); diff --git a/drivers/net/pcmcia/wavelan_cs.c b/drivers/net/pcmcia/wavelan_cs.c index b8ec9510429b..49ce66592a9f 100644 --- a/drivers/net/pcmcia/wavelan_cs.c +++ b/drivers/net/pcmcia/wavelan_cs.c @@ -4663,6 +4663,7 @@ wavelan_event(event_t event, /* The event received */ { /* Accept no more transmissions */ netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); /* Release the card */ wv_pcmcia_release((u_long) link); @@ -4701,6 +4702,7 @@ wavelan_event(event_t event, /* The event received */ if(link->open) { netif_stop_queue (dev); + clear_bit(LINK_STATE_START, &dev->state); } CardServices(ReleaseConfiguration, link->handle); } @@ -4716,6 +4718,7 @@ wavelan_event(event_t event, /* The event received */ if(link->open) /* If RESET -> True, If RESUME -> False ??? */ { wv_hw_reset(dev); + set_bit(LINK_STATE_START, &dev->state); netif_start_queue (dev); } } diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index b424f9e9914f..a6c295e352f5 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -723,7 +723,7 @@ xirc2ps_attach(void) dev->stop = &do_stop; dev->tx_timeout = xirc_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - netif_start_queue (dev); + netif_start_queue(dev); /* Register with Card Services */ link->next = dev_list; @@ -1239,7 +1239,7 @@ xirc2ps_config(dev_link_t * link) /* we can now register the device with the net subsystem */ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - netif_start_queue (dev); + netif_start_queue(dev); if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); goto config_error; @@ -1340,7 +1340,8 @@ xirc2ps_event(event_t event, int priority, case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); + netif_stop_queue(dev); + clear_bit(LINK_STATE_START, &dev->state); link->release.expires = jiffies + HZ / 20; add_timer(&link->release); } @@ -1355,7 +1356,8 @@ xirc2ps_event(event_t event, int priority, case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - netif_stop_queue (dev); + netif_stop_queue(dev); + clear_bit(LINK_STATE_START, &dev->state); lp->suspended=1; do_powerdown(dev); } @@ -1371,7 +1373,8 @@ xirc2ps_event(event_t event, int priority, if (link->open) { do_reset(dev,1); lp->suspended=0; - netif_start_queue (dev); + set_bit(LINK_STATE_START, &dev->state); + netif_start_queue(dev); } } break; @@ -1400,6 +1403,8 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ spin_lock (&lp->lock); + if (!test_bit(LINK_STATE_START, &dev->state)) + return; ioaddr = dev->base_addr; if (lp->mohawk) { /* must disable the interrupt */ @@ -1555,7 +1560,7 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) DEBUG(0, "PTR not changed?\n"); } else lp->stats.tx_packets += lp->last_ptr_value - n; - netif_wake_queue (dev); + netif_wake_queue(dev); } if (tx_status & 0x0002) { /* Execessive collissions */ DEBUG(0, "tx restarted due to execssive collissions\n"); @@ -1613,7 +1618,7 @@ static void xirc_tx_timeout (struct net_device *dev) if (lp->suspended) { dev->trans_start = jiffies; lp->stats.tx_dropped++; - netif_start_queue (dev); + netif_start_queue(dev); return; } @@ -1622,7 +1627,7 @@ static void xirc_tx_timeout (struct net_device *dev) /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; - netif_start_queue (dev); + netif_start_queue(dev); } @@ -1638,7 +1643,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", skb, dev, pktlen); - netif_stop_queue (dev); + netif_stop_queue(dev); /* adjust the packet length to min. required * and hope that the buffer is large enough @@ -1673,7 +1678,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb (skb); dev->trans_start = jiffies; - netif_start_queue (dev); + netif_start_queue(dev); lp->stats.tx_bytes += pktlen; return 0; } @@ -1818,7 +1823,7 @@ do_open(struct net_device *dev) link->open++; MOD_INC_USE_COUNT; - netif_start_queue (dev); + netif_start_queue(dev); lp->suspended = 0; do_reset(dev,1); @@ -2136,7 +2141,7 @@ do_stop(struct net_device *dev) if (!link) return -ENODEV; - netif_stop_queue (dev); + netif_stop_queue(dev); SelectPage(0); PutByte(XIRCREG_CR, 0); /* disable interrupts */ diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index ae671c83df45..8504ee052e9c 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.95 2000/02/10 21:14:24 davem Exp $ +/* $Id: sunlance.c,v 1.97 2000/02/14 09:02:32 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -602,7 +602,7 @@ static void lance_tx_dvma(struct net_device *dev) lp->init_ring(dev); load_csrs(lp); init_restart_lance(lp); - return; + goto out; } } @@ -618,7 +618,7 @@ static void lance_tx_dvma(struct net_device *dev) lp->init_ring(dev); load_csrs(lp); init_restart_lance(lp); - return; + goto out; } } else if ((bits & LE_T1_POK) == LE_T1_POK) { /* @@ -644,7 +644,7 @@ static void lance_tx_dvma(struct net_device *dev) if (test_bit(LINK_STATE_XOFF, &dev->state) && TX_BUFFS_AVAIL > 0) netif_wake_queue(dev); - +out: spin_unlock(&lp->lock); } @@ -773,7 +773,7 @@ static void lance_tx_pio(struct net_device *dev) lp->init_ring(dev); load_csrs(lp); init_restart_lance(lp); - return; + goto out; } } @@ -789,7 +789,7 @@ static void lance_tx_pio(struct net_device *dev) lp->init_ring(dev); load_csrs(lp); init_restart_lance(lp); - return; + goto out; } } else if ((bits & LE_T1_POK) == LE_T1_POK) { /* @@ -815,7 +815,7 @@ static void lance_tx_pio(struct net_device *dev) if (test_bit(LINK_STATE_XOFF, &dev->state) && TX_BUFFS_AVAIL > 0) netif_wake_queue(dev); - +out: spin_unlock(&lp->lock); } @@ -1014,7 +1014,7 @@ static int lance_reset(struct net_device *dev) return status; } -static void lance_piocopy_from_skb(volatile void *dest, char *src, int len) +static void lance_piocopy_from_skb(volatile void *dest, unsigned char *src, int len) { unsigned long piobuf = (unsigned long) dest; u32 *p32; @@ -1128,10 +1128,10 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; - lp->stats.tx_bytes += len; - spin_lock_irq(&lp->lock); + lp->stats.tx_bytes += len; + entry = lp->tx_new & TX_RING_MOD_MASK; if (lp->pio_buffer) { sbus_writew((-len) | 0xf000, &ib->btx_ring[entry].length); @@ -1154,19 +1154,20 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); - spin_unlock_irq(&lp->lock); - /* Kick the lance: transmit now */ sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP); - dev->trans_start = jiffies; - dev_kfree_skb(skb); - + /* Read back CSR to invalidate the E-Cache. * This is needed, because DMA_DSBL_WR_INV is set. */ if (lp->dregs) sbus_readw(lp->lregs + RDP); + spin_unlock_irq(&lp->lock); + + dev->trans_start = jiffies; + dev_kfree_skb(skb); + return 0; } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 5d412d161d5a..11df38ad0e09 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -865,7 +865,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) np->stats.tx_packets++; } /* Free the original skb. */ - kfree_skb(np->tx_skbuff[entry]); + dev_kfree_skb_irq(np->tx_skbuff[entry]); np->tx_skbuff[entry] = 0; } if (np->tx_full && @@ -1147,13 +1147,13 @@ static int netdev_close(struct net_device *dev) np->rx_ring[i].rx_length = 0; np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (np->rx_skbuff[i]) { - kfree_skb(np->rx_skbuff[i]); + dev_kfree_skb(np->rx_skbuff[i]); } np->rx_skbuff[i] = 0; } for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) - kfree_skb(np->tx_skbuff[i]); + dev_kfree_skb(np->tx_skbuff[i]); np->tx_skbuff[i] = 0; } diff --git a/drivers/pci/pcisyms.c b/drivers/pci/pcisyms.c index 9dffe21436b5..310f758403b1 100644 --- a/drivers/pci/pcisyms.c +++ b/drivers/pci/pcisyms.c @@ -20,9 +20,11 @@ EXPORT_SYMBOL(pci_write_config_dword); EXPORT_SYMBOL(pci_devices); EXPORT_SYMBOL(pci_root_buses); EXPORT_SYMBOL(pci_enable_device); +EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_find_class); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_slot); +EXPORT_SYMBOL(pci_find_subsys); EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_power_state); EXPORT_SYMBOL(pci_assign_resource); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 704f7c95c726..8b8a1f8cea49 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -2,7 +2,7 @@ PCMCIA Card Services -- core services - cs.c 1.247 2000/01/15 04:30:35 + cs.c 1.249 2000/02/10 23:26:11 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -69,7 +69,7 @@ static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data); int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"cs.c 1.247 2000/01/15 04:30:35 (David Hinds)"; +"cs.c 1.249 2000/02/10 23:26:11 (David Hinds)"; #endif #ifdef CONFIG_PCI @@ -341,6 +341,7 @@ int register_ss_entry(int nsock, struct pccard_operations * ss_entry) s->sock = ns; s->setup.data = sockets; s->setup.function = &setup_socket; + s->setup_timeout = 0; s->shutdown.data = sockets; s->shutdown.function = &shutdown_socket; /* base address = 0, map = 0 */ @@ -486,7 +487,17 @@ static void setup_socket(u_long i) socket_info_t *s = socket_table[i]; get_socket_status(s, &val); - if (val & SS_DETECT) { + if (val & SS_PENDING) { + /* Does the socket need more time? */ + DEBUG(2, "cs: setup_socket(%ld): status pending\n", i); + if (++s->setup_timeout > 100) { + printk(KERN_NOTICE "cs: socket %ld voltage interrogation" + " timed out\n", i); + } else { + s->setup.expires = jiffies + HZ/10; + add_timer(&s->setup); + } + } else if (val & SS_DETECT) { DEBUG(1, "cs: setup_socket(%ld): applying power\n", i); s->state |= SOCKET_PRESENT; s->socket.flags = 0; @@ -532,7 +543,7 @@ static void reset_socket(u_long i) udelay((long)reset_time); s->socket.flags &= ~SS_RESET; set_socket(s, &s->socket); - s->unreset_timeout = 0; + s->setup_timeout = 0; s->setup.expires = jiffies + unreset_delay; s->setup.function = &unreset_socket; add_timer(&s->setup); @@ -571,12 +582,11 @@ static void unreset_socket(u_long i) } } else { DEBUG(2, "cs: socket %ld not ready yet\n", i); - if (s->unreset_timeout > unreset_limit) { + if (++s->setup_timeout > unreset_limit) { printk(KERN_NOTICE "cs: socket %ld timed out during" " reset\n", i); s->state &= ~EVENT_MASK; } else { - s->unreset_timeout++; s->setup.expires = jiffies + unreset_check; add_timer(&s->setup); } diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index cac2d350a92a..f355c337b831 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -131,7 +131,7 @@ typedef struct socket_info_t { u_int real_clients; client_handle_t reset_handle; struct timer_list setup, shutdown; - u_long unreset_timeout; + u_long setup_timeout; pccard_mem_map cis_mem; u_char *cis_virt; config_t *config; diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 73c177d8dcc2..18d47d9a807f 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -82,9 +82,9 @@ static const char *version = static void irq_count(int, void *, struct pt_regs *); static inline int _check_irq(int irq, int flags) { - if (request_irq(irq, irq_count, flags, "x", NULL) != 0) + if (request_irq(irq, irq_count, flags, "x", irq_count) != 0) return -1; - free_irq(irq, NULL); + free_irq(irq, irq_count); return 0; } @@ -570,28 +570,26 @@ static void irq_count(int irq, void *dev, struct pt_regs *regs) DEBUG(2, "-> hit on irq %d\n", irq); } -static u_int __init test_irq(u_short sock, int irq, int pci) +static u_int __init test_irq(u_short sock, int irq) { - u_char csc = (pci) ? 0 : irq; - DEBUG(2, " testing %s irq %d\n", pci ? "PCI" : "ISA", irq); - - if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0) + DEBUG(2, " testing ISA irq %d\n", irq); + if (request_irq(irq, irq_count, 0, "scan", irq_count) != 0) return 1; irq_hits = 0; irq_sock = sock; __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/100); if (irq_hits) { - free_irq(irq, NULL); + free_irq(irq, irq_count); DEBUG(2, " spurious hit!\n"); return 1; } /* Generate one interrupt */ - i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4)); + i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4)); i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); udelay(1000); - free_irq(irq, NULL); + free_irq(irq, irq_count); /* mask all interrupts */ i365_set(sock, I365_CSCINT, 0); @@ -617,10 +615,10 @@ static u_int __init isa_scan(u_short sock, u_int mask0) set_bridge_state(sock); i365_set(sock, I365_CSCINT, 0); for (i = 0; i < 16; i++) - if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0)) + if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0)) mask1 |= (1 << i); for (i = 0; i < 16; i++) - if ((mask1 & (1 << i)) && (test_irq(sock, i, 0) != 0)) + if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0)) mask1 ^= (1 << i); } @@ -1543,7 +1541,7 @@ static int __init init_i82365(void) /* Set up interrupt handler(s) */ #ifdef CONFIG_ISA if (grab_irq != 0) - request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL); + request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); #endif if (register_ss_entry(sockets, &pcic_operations) != 0) @@ -1573,7 +1571,7 @@ static void __exit exit_i82365(void) del_timer(&poll_timer); #ifdef CONFIG_ISA if (grab_irq != 0) - free_irq(cs_irq, NULL); + free_irq(cs_irq, pcic_interrupt); #endif for (i = 0; i < sockets; i++) { /* Turn off all interrupt sources! */ diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index ff25ac893ae4..8939ea9f6652 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -2,7 +2,7 @@ Device driver for Databook TCIC-2 PCMCIA controller - tcic.c 1.108 1999/12/09 20:17:29 + tcic.c 1.111 2000/02/15 04:13:12 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -60,7 +60,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"tcic.c 1.108 1999/12/09 20:17:29 (David Hinds)"; +"tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)"; #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) #else #define DEBUG(n, args...) @@ -243,11 +243,11 @@ static u_int __init try_irq(int irq) u_short cfg; irq_hits = 0; - if (request_irq(irq, irq_count, 0, "irq scan", NULL) != 0) + if (request_irq(irq, irq_count, 0, "irq scan", irq_count) != 0) return -1; mdelay(10); if (irq_hits) { - free_irq(irq, NULL); + free_irq(irq, irq_count); return -1; } @@ -258,7 +258,7 @@ static u_int __init try_irq(int irq) tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM); udelay(1000); - free_irq(irq, NULL); + free_irq(irq, irq_count); /* Turn off interrupts */ tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF); @@ -299,9 +299,9 @@ static u_int __init irq_scan(u_int mask0) /* Fallback: just find interrupts that aren't in use */ for (i = 0; i < 16; i++) if ((mask0 & (1 << i)) && - (request_irq(i, irq_count, 0, "x", NULL) == 0)) { + (request_irq(i, irq_count, 0, "x", irq_count) == 0)) { mask1 |= (1 << i); - free_irq(i, NULL); + free_irq(i, irq_count); } printk("default"); } @@ -475,7 +475,8 @@ static int __init init_tcic(void) u_int cs_mask = mask & ((cs_irq) ? (1< 0; i--) if ((cs_mask & (1 << i)) && - (request_irq(i, tcic_interrupt, 0, "tcic", NULL) == 0)) + (request_irq(i, tcic_interrupt, 0, "tcic", + tcic_interrupt) == 0)) break; cs_irq = i; if (cs_irq == 0) poll_interval = HZ; @@ -501,7 +502,7 @@ static int __init init_tcic(void) printk(KERN_NOTICE "tcic: register_ss_entry() failed\n"); release_region(tcic_base, 16); if (cs_irq != 0) - free_irq(cs_irq, NULL); + free_irq(cs_irq, tcic_interrupt); return -ENODEV; } @@ -519,7 +520,7 @@ static void __exit exit_tcic(void) cli(); if (cs_irq != 0) { tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00); - free_irq(cs_irq, NULL); + free_irq(cs_irq, tcic_interrupt); } if (tcic_timer_pending) del_timer(&poll_timer); diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 7e26f3491d45..e66f3cedece1 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -507,7 +507,7 @@ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) } do_poke_blanked_console = 1; - mark_bh(CONSOLE_BH); + tasklet_schedule(&console_tasklet); add_keyboard_randomness(keycode); tty = ttytab? ttytab[fg_console]: NULL; @@ -616,7 +616,7 @@ static void put_queue(int ch) wake_up(&keypress_wait); if (tty) { tty_insert_flip_char(tty, ch, 0); - tty_schedule_flip(tty); + con_schedule_flip(tty); } } @@ -630,7 +630,7 @@ static void puts_queue(char *cp) tty_insert_flip_char(tty, *cp, 0); cp++; } - tty_schedule_flip(tty); + con_schedule_flip(tty); } static void applkey(int key, char mode) @@ -742,7 +742,7 @@ static void send_intr(void) if (!tty) return; tty_insert_flip_char(tty, 0, TTY_BREAK); - tty_schedule_flip(tty); + con_schedule_flip(tty); } static void scroll_forw(void) diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index a2dd9fb7f2ff..3b94d70a6594 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -183,3 +183,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then fi endmenu + +if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then + source drivers/scsi/pcmcia/Config.in +fi + diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 3dbbfda15120..873703e120eb 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -13,6 +13,16 @@ MIX_OBJS := MOD_LIST_NAME := SCSI_MODULES SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c)) +ALL_SUB_DIRS := pcmcia +ifeq ($(CONFIG_PCMCIA),y) + SUB_DIRS += pcmcia + MOD_IN_SUB_DIRS += pcmcia +else + ifeq ($(CONFIG_PCMCIA),m) + MOD_IN_SUB_DIRS += pcmcia + endif +endif + CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 38550e1d3054..30faaa9ad9be 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -200,13 +200,9 @@ **************************************************************************/ -#if defined(PCMCIA) -#define MODULE -#endif - #include -#if defined(PCMCIA) +#ifdef PCMCIA #undef MODULE #endif @@ -877,9 +873,9 @@ static int tc1550_porttest(int io_port) static int checksetup(struct aha152x_setup *setup) { - int i; #if !defined(PCMCIA) + int i; for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++) ; diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 61ce25c36efb..57802859cbc6 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1,4 +1,4 @@ -/* $Id: esp.c,v 1.90 2000/01/28 13:42:56 jj Exp $ +/* $Id: esp.c,v 1.91 2000/02/14 08:46:24 jj Exp $ * esp.c: EnhancedScsiProcessor Sun SCSI driver code. * * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) @@ -1412,9 +1412,13 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp) sp->SCp.this_residual = sp->request_bufflen; sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; sp->SCp.buffers_residual = 0; - sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer, - sp->SCp.this_residual); - sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in); + if (sp->request_bufflen) { + sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer, + sp->SCp.this_residual); + sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in); + } else { + sp->SCp.ptr = NULL; + } } else { sp->SCp.buffer = (struct scatterlist *) sp->buffer; sp->SCp.buffers_residual = sbus_map_sg(esp->sdev, @@ -1427,12 +1431,12 @@ static void esp_get_dmabufs(struct esp *esp, Scsi_Cmnd *sp) static void esp_release_dmabufs(struct esp *esp, Scsi_Cmnd *sp) { - if (sp->use_sg == 0) { + if (sp->use_sg) { + sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg); + } else if (sp->request_bufflen) { sbus_unmap_single(esp->sdev, sp->SCp.have_data_in, sp->request_bufflen); - } else { - sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg); } } diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 979f1295c11f..59d9f2415322 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -270,10 +270,6 @@ **************************************************************************/ -#ifdef PCMCIA -#define MODULE -#endif - #include #ifdef PCMCIA diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 0ede63b87fd2..adafbe43e1ba 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -253,7 +253,7 @@ mesh_detect(Scsi_Host_Template *tp) continue; } mesh_host->unique_id = nmeshes; -#if !defined(MODULE) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)) +#if !defined(MODULE) note_scsi_host(mesh, mesh_host); #endif @@ -305,9 +305,7 @@ mesh_detect(Scsi_Host_Template *tp) if (mesh_sync_period < minper) mesh_sync_period = minper; -#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) feature_set(mesh, FEATURE_MESH_enable); -#endif mdelay(200); mesh_init(ms); diff --git a/drivers/scsi/pcmcia/Config.in b/drivers/scsi/pcmcia/Config.in new file mode 100644 index 000000000000..5416bdef22e9 --- /dev/null +++ b/drivers/scsi/pcmcia/Config.in @@ -0,0 +1,23 @@ +# +# PCMCIA SCSI adapter configuration +# + +mainmenu_option next_comment +comment 'PCMCIA SCSI adapter support' + +bool 'PCMCIA SCSI adapter support' CONFIG_SCSI_PCMCIA +if [ "$CONFIG_SCSI_PCMCIA" = "y" ]; then + dep_tristate ' Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m + dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m + dep_tristate ' Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m + if [ "$CONFIG_CARDBUS" = "y" ]; then + dep_tristate ' Adaptec APA1480 CardBus support' CONFIG_PCMCIA_APA1480 m + fi +fi + +if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \ + "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_APA1480" = "y" ]; then + define_bool CONFIG_PCMCIA_SCSICARD y +fi + +endmenu diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile new file mode 100644 index 000000000000..d37c6fc5f31e --- /dev/null +++ b/drivers/scsi/pcmcia/Makefile @@ -0,0 +1,67 @@ +# +# drivers/scsi/pcmcia/Makefile +# +# Makefile for the Linux PCMCIA SCSI drivers. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +MOD_LIST_NAME := PCMCIA_SCSI_MODULES + +obj-y := +obj-m := +obj-n := +obj- := + +vpath %c .. + +CFLAGS_aha152x.o = -DPCMCIA -D__NO_VERSION__ -DAHA152X_STAT +CFLAGS_aic7xxx.o = -DPCMCIA -D__NO_VERSION__ +CFLAGS_fdomain.o = -DPCMCIA -D__NO_VERSION__ +CFLAGS_qlogicfas.o = -DPCMCIA -D__NO_VERSION__ + +# 16-bit client drivers +obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o +obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o +obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o + +# Cardbus client drivers +obj-$(CONFIG_PCMCIA_APA1480) += apa1480_cb.o + +list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o apa1480_cb.o +aha152x-objs := aha152x_stub.o aha152x.o +apa1480-objs := apa1480_stub.o aic7xxx.o +fdomain-objs := fdomain_stub.o fdomain.o +qlogic-objs := qlogic_stub.o qlogicfas.o + +# Extract lists of the multi-part drivers. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(filter-out $(export-objs), $(obj-m)) +MX_OBJS := $(filter $(export-objs), $(obj-m)) +MI_OBJS := $(filter-out $(export-objs), $(int-m)) +MIX_OBJS := $(filter $(export-objs), $(int-m)) + +include $(TOPDIR)/Rules.make + +aha152x_cs.o: $(aha152x-objs) + $(LD) -r -o $@ $(aha152x-objs) + +apa1480_cb.o: $(apa1480-objs) + $(LD) -r -o $@ $(apa1480-objs) + +fdomain_cs.o: $(fdomain-objs) + $(LD) -r -o $@ $(fdomain-objs) + +qlogic_cs.o: $(qlogic-objs) + $(LD) -r -o $@ $(qlogic-objs) diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c new file mode 100644 index 000000000000..7450470a1902 --- /dev/null +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -0,0 +1,437 @@ +/*====================================================================== + + A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards. + + This driver supports the Adaptec AHA-1460, the New Media Bus + Toaster, and the New Media Toast & Jam. + + aha152x_cs.c 1.52 2000/01/11 01:04:31 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> +#include +#include <../drivers/scsi/aha152x.h> + +#include +#include +#include +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"aha152x_cs.c 1.52 2000/01/11 01:04:31 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +/* SCSI bus setup options */ +static int host_id = 7; +static int reconnect = 1; +static int parity = 1; +static int synchronous = 0; +static int reset_delay = 100; +static int ext_trans = 0; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(host_id, "i"); +MODULE_PARM(reconnect, "i"); +MODULE_PARM(parity, "i"); +MODULE_PARM(synchronous, "i"); +MODULE_PARM(reset_delay, "i"); +MODULE_PARM(ext_trans, "i"); + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + struct Scsi_Host *host; + int ndev; + dev_node_t node[8]; +} scsi_info_t; + +extern void aha152x_setup(char *str, int *ints); + +static void aha152x_release_cs(u_long arg); +static int aha152x_event(event_t event, int priority, + event_callback_args_t *args); + +static dev_link_t *aha152x_attach(void); +static void aha152x_detach(dev_link_t *); + +static Scsi_Host_Template driver_template = AHA152X; + +static dev_link_t *dev_list = NULL; + +static dev_info_t dev_info = "aha152x_cs"; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================*/ + +static dev_link_t *aha152x_attach(void) +{ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + DEBUG(0, "aha152x_attach()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; link->priv = info; + link->release.function = &aha152x_release_cs; + link->release.data = (u_long)link; + + link->io.NumPorts1 = 0x20; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.event_handler = &aha152x_event; + client_reg.EventMask = + CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + aha152x_detach(link); + return NULL; + } + + return link; +} /* aha152x_attach */ + +/*====================================================================*/ + +static void aha152x_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "aha152x_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) { + aha152x_release_cs((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + +} /* aha152x_detach */ + +/*====================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void aha152x_config_cs(dev_link_t *link) +{ + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn, ints[8]; + u_char tuple_data[64]; + Scsi_Device *dev; + dev_node_t *node, **tail; + struct Scsi_Host *host; + + DEBUG(0, "aha152x_config(0x%p)\n", link); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.TupleData = tuple_data; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + + /* Configure card */ + driver_template.module = &__this_module; + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + /* For New Media T&J, look for a SCSI window */ + if (parse.cftable_entry.io.win[0].len >= 0x20) + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + else if ((parse.cftable_entry.io.nwin > 1) && + (parse.cftable_entry.io.win[1].len >= 0x20)) + link->io.BasePort1 = parse.cftable_entry.io.win[1].base; + if ((parse.cftable_entry.io.nwin > 0) && + (link->io.BasePort1 < 0xffff)) { + link->conf.ConfigIndex = parse.cftable_entry.index; + i = CardServices(RequestIO, handle, &link->io); + if (i == CS_SUCCESS) break; + } + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + /* A bad hack... */ + release_region(link->io.BasePort1, link->io.NumPorts1); + + /* Set configuration options for the aha152x driver */ + ints[0] = 7; + ints[1] = link->io.BasePort1; + ints[2] = link->irq.AssignedIRQ; + ints[3] = host_id; + ints[4] = reconnect; + ints[5] = parity; + ints[6] = synchronous; + ints[7] = reset_delay; + if (ext_trans) { + ints[8] = ext_trans; ints[0] = 8; + } + aha152x_setup("PCMCIA setup", ints); + + scsi_register_module(MODULE_SCSI_HA, &driver_template); + + tail = &link->dev; + info->ndev = 0; + for (host = scsi_hostlist; host; host = host->next) + if (host->hostt == &driver_template) + for (dev = host->host_queue; dev; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + node = &info->node[info->ndev]; + node->minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node->major = SCSI_TAPE_MAJOR; + sprintf(node->dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node->major = SCSI_DISK0_MAJOR; + sprintf(node->dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node->major = SCSI_CDROM_MAJOR; + sprintf(node->dev_name, "sr#%04lx", id); + break; + default: + node->major = SCSI_GENERIC_MAJOR; + sprintf(node->dev_name, "sg#%04lx", id); + break; + } + *tail = node; tail = &node->next; + info->ndev++; + info->host = dev->host; + } + *tail = NULL; + if (info->ndev == 0) + printk(KERN_INFO "aha152x_cs: no SCSI devices found\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + aha152x_release_cs((u_long)link); + return; + +} /* aha152x_config_cs */ + +/*====================================================================*/ + +static void aha152x_release_cs(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "aha152x_release_cs(0x%p)\n", link); + + if (GET_USE_COUNT(driver_template.module) != 0) { + DEBUG(1, "aha152x_cs: release postponed, " + "device still open\n"); + link->state |= DEV_STALE_CONFIG; + return; + } + + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + if (link->state & DEV_STALE_LINK) + aha152x_detach(link); + +} /* aha152x_release_cs */ + +/*====================================================================*/ + +static int aha152x_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + scsi_info_t *info = link->priv; + + DEBUG(0, "aha152x_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + aha152x_config_cs(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + Scsi_Cmnd tmp; + CardServices(RequestConfiguration, link->handle, &link->conf); + tmp.host = info->host; + aha152x_host_reset(&tmp); + } + break; + } + return 0; +} /* aha152x_event */ + +/*====================================================================*/ + +static int __init init_aha152x_cs(void) { + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "aha152x_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &aha152x_attach, &aha152x_detach); + return 0; +} + +static void __exit exit_aha152x_cs(void) { + DEBUG(0, "aha152x_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + aha152x_detach(dev_list); +} + +module_init(init_aha152x_cs); +module_exit(exit_aha152x_cs); + diff --git a/drivers/scsi/pcmcia/apa1480_stub.c b/drivers/scsi/pcmcia/apa1480_stub.c new file mode 100644 index 000000000000..a6419f194d30 --- /dev/null +++ b/drivers/scsi/pcmcia/apa1480_stub.c @@ -0,0 +1,174 @@ +/*====================================================================== + + A driver for the Adaptec APA1480 CardBus SCSI Host Adapter + + apa1480_cb.c 1.19 2000/02/14 22:39:25 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> +#include +#include <../drivers/scsi/aic7xxx.h> + +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"apa1480_cb.c 1.19 2000/02/14 22:39:25 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int reset = 1; +static int ultra = 0; + +MODULE_PARM(reset, "i"); +MODULE_PARM(ultra, "i"); + +/*====================================================================*/ + +static Scsi_Host_Template driver_template = AIC7XXX; + +extern void aic7xxx_setup(char *, int *); + +static dev_node_t *apa1480_attach(dev_locator_t *loc); +static void apa1480_detach(dev_node_t *node); + +struct driver_operations apa1480_ops = { + "apa1480_cb", apa1480_attach, NULL, NULL, apa1480_detach +}; + +/*====================================================================*/ + +static dev_node_t *apa1480_attach(dev_locator_t *loc) +{ + u_char bus, devfn; + Scsi_Device *dev; + dev_node_t *node; + char s[60]; + int n = 0; + struct Scsi_Host *host; + + if (loc->bus != LOC_PCI) return NULL; + bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; + printk(KERN_INFO "apa1480_attach(bus %d, function %d)\n", + bus, devfn); + + driver_template.module = &__this_module; + + sprintf(s, "no_probe:1,no_reset:%d,ultra:%d", + (reset==0), (ultra!=0)); + aic7xxx_setup(s, NULL); + scsi_register_module(MODULE_SCSI_HA, &driver_template); + + node = kmalloc(7 * sizeof(dev_node_t), GFP_KERNEL); + for (host = scsi_hostlist; host; host = host->next) + if (host->hostt == &driver_template) + for (dev = host->host_queue; dev; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + node[n].minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node[n].major = SCSI_TAPE_MAJOR; + sprintf(node[n].dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node[n].major = SCSI_DISK0_MAJOR; + sprintf(node[n].dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node[n].major = SCSI_CDROM_MAJOR; + sprintf(node[n].dev_name, "sr#%04lx", id); + break; + default: + node[n].major = SCSI_GENERIC_MAJOR; + sprintf(node[n].dev_name, "sg#%04lx", id); + break; + } + if (n) node[n-1].next = &node[n]; + n++; + } + if (n == 0) { + printk(KERN_INFO "apa1480_cs: no SCSI devices found\n"); + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + kfree(node); + return NULL; + } else + node[n-1].next = NULL; + + MOD_INC_USE_COUNT; + return node; +} + +static void apa1480_detach(dev_node_t *node) +{ + MOD_DEC_USE_COUNT; + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + kfree(node); +} + +/*====================================================================*/ + +static int __init init_apa1480_cb(void) { + DEBUG(0, "%s\n", version); + register_driver(&apa1480_ops); + return 0; +} + +static void __exit exit_apa1480_cb(void) { + DEBUG(0, "apa1480_cs: unloading\n"); + unregister_driver(&apa1480_ops); +} + +module_init(init_apa1480_cb); +module_exit(exit_apa1480_cb); diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c new file mode 100644 index 000000000000..558bf3317bb4 --- /dev/null +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -0,0 +1,398 @@ +/*====================================================================== + + A driver for Future Domain-compatible PCMCIA SCSI cards + + fdomain_cs.c 1.41 1999/11/15 06:05:48 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> +#include +#include <../drivers/scsi/fdomain.h> + +#include +#include +#include +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"fdomain_cs.c 1.41 1999/11/15 06:05:48 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + int ndev; + dev_node_t node[8]; +} scsi_info_t; + +extern void fdomain_setup(char *str, int *ints); + +static void fdomain_release(u_long arg); +static int fdomain_event(event_t event, int priority, + event_callback_args_t *args); + +static dev_link_t *fdomain_attach(void); +static void fdomain_detach(dev_link_t *); + +static Scsi_Host_Template driver_template = FDOMAIN_16X0; + +static dev_link_t *dev_list = NULL; + +static dev_info_t dev_info = "fdomain_cs"; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================*/ + +static dev_link_t *fdomain_attach(void) +{ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + DEBUG(0, "fdomain_attach()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; link->priv = info; + link->release.function = &fdomain_release; + link->release.data = (u_long)link; + + link->io.NumPorts1 = 0x10; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.event_handler = &fdomain_event; + client_reg.EventMask = + CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + fdomain_detach(link); + return NULL; + } + + return link; +} /* fdomain_attach */ + +/*====================================================================*/ + +static void fdomain_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "fdomain_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) { + fdomain_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + +} /* fdomain_detach */ + +/*====================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void fdomain_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn, ints[3]; + u_char tuple_data[64]; + Scsi_Device *dev; + dev_node_t *node, **tail; + struct Scsi_Host *host; + + DEBUG(0, "fdomain_config(0x%p)\n", link); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.TupleData = tuple_data; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + + /* Configure card */ + driver_template.module = &__this_module; + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigIndex = parse.cftable_entry.index; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + i = CardServices(RequestIO, handle, &link->io); + if (i == CS_SUCCESS) break; + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + /* A bad hack... */ + release_region(link->io.BasePort1, link->io.NumPorts1); + + /* Set configuration options for the fdomain driver */ + ints[0] = 2; + ints[1] = link->io.BasePort1; + ints[2] = link->irq.AssignedIRQ; + fdomain_setup("PCMCIA setup", ints); + + scsi_register_module(MODULE_SCSI_HA, &driver_template); + + tail = &link->dev; + info->ndev = 0; + for (host = scsi_hostlist; host; host = host->next) + if (host->hostt == &driver_template) + for (dev = host->host_queue; dev; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + node = &info->node[info->ndev]; + node->minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node->major = SCSI_TAPE_MAJOR; + sprintf(node->dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node->major = SCSI_DISK0_MAJOR; + sprintf(node->dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node->major = SCSI_CDROM_MAJOR; + sprintf(node->dev_name, "sr#%04lx", id); + break; + default: + node->major = SCSI_GENERIC_MAJOR; + sprintf(node->dev_name, "sg#%04lx", id); + break; + } + *tail = node; tail = &node->next; + info->ndev++; + } + *tail = NULL; + if (info->ndev == 0) + printk(KERN_INFO "fdomain_cs: no SCSI devices found\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + fdomain_release((u_long)link); + return; + +} /* fdomain_config */ + +/*====================================================================*/ + +static void fdomain_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "fdomain_release(0x%p)\n", link); + + if (GET_USE_COUNT(&__this_module) != 0) { + DEBUG(1, "fdomain_cs: release postponed, " + "device still open\n"); + link->state |= DEV_STALE_CONFIG; + return; + } + + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + if (link->state & DEV_STALE_LINK) + fdomain_detach(link); + +} /* fdomain_release */ + +/*====================================================================*/ + +static int fdomain_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "fdomain_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + fdomain_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + fdomain_16x0_reset(NULL, 0); + } + break; + } + return 0; +} /* fdomain_event */ + +/*====================================================================*/ + +static int __init init_fdomain_cs(void) { + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "fdomain_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &fdomain_attach, &fdomain_detach); + return 0; +} + +static void __exit exit_fdomain_cs(void) { + DEBUG(0, "fdomain_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + fdomain_detach(dev_list); +} + +module_init(init_fdomain_cs); +module_exit(exit_fdomain_cs); diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c new file mode 100644 index 000000000000..c3f1d03a59a3 --- /dev/null +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -0,0 +1,428 @@ +/*====================================================================== + + A driver for the Qlogic SCSI card + + qlogic_cs.c 1.77 2000/02/01 19:08:09 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> +#include + +#include <../drivers/scsi/qlogicfas.h> + +#define qlogic_reset(h) qlogicfas_reset(h, 0) + +#include +#include +#include +#include +#include +#include + +extern void qlogicfas_preset(int port, int irq); + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"qlogic_cs.c 1.77 2000/02/01 19:08:09 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + u_short manf_id; + int ndev; + dev_node_t node[8]; +} scsi_info_t; + +static void qlogic_release(u_long arg); +static int qlogic_event(event_t event, int priority, + event_callback_args_t *args); + +static dev_link_t *qlogic_attach(void); +static void qlogic_detach(dev_link_t *); + +static Scsi_Host_Template driver_template = QLOGICFAS; + +static dev_link_t *dev_list = NULL; + +static dev_info_t dev_info = "qlogic_cs"; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================*/ + +static dev_link_t *qlogic_attach(void) +{ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + DEBUG(0, "qlogic_attach()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; link->priv = info; + link->release.function = &qlogic_release; + link->release.data = (u_long)link; + + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.event_handler = &qlogic_event; + client_reg.EventMask = + CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + qlogic_detach(link); + return NULL; + } + + return link; +} /* qlogic_attach */ + +/*====================================================================*/ + +static void qlogic_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "qlogic_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) { + qlogic_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + +} /* qlogic_detach */ + +/*====================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void qlogic_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn; + u_short tuple_data[32]; + Scsi_Device *dev; + dev_node_t **tail, *node; + struct Scsi_Host *host; + + DEBUG(0, "qlogic_config(0x%p)\n", link); + + tuple.TupleData = (cisdata_t *)tuple_data; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + + tuple.DesiredTuple = CISTPL_MANFID; + if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && + (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) + info->manf_id = le16_to_cpu(tuple.TupleData[0]); + + /* Configure card */ + driver_template.module = &__this_module; + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigIndex = parse.cftable_entry.index; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; + if (link->io.BasePort1 != 0) { + i = CardServices(RequestIO, handle, &link->io); + if (i == CS_SUCCESS) break; + } + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + /* set ATAcmd */ + outb(0xb4, link->io.BasePort1+0xd); + outb(0x24, link->io.BasePort1+0x9); + outb(0x04, link->io.BasePort1+0xd); + } + + /* A bad hack... */ + release_region(link->io.BasePort1, link->io.NumPorts1); + + /* The KXL-810AN has a bigger IO port window */ + if (link->io.NumPorts1 == 32) + qlogicfas_preset(link->io.BasePort1+16, link->irq.AssignedIRQ); + else + qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ); + + scsi_register_module(MODULE_SCSI_HA, &driver_template); + + tail = &link->dev; + info->ndev = 0; + for (host = scsi_hostlist; host; host = host->next) + if (host->hostt == &driver_template) + for (dev = host->host_queue; dev; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + node = &info->node[info->ndev]; + node->minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node->major = SCSI_TAPE_MAJOR; + sprintf(node->dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node->major = SCSI_DISK0_MAJOR; + sprintf(node->dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node->major = SCSI_CDROM_MAJOR; + sprintf(node->dev_name, "sr#%04lx", id); + break; + default: + node->major = SCSI_GENERIC_MAJOR; + sprintf(node->dev_name, "sg#%04lx", id); + break; + } + *tail = node; tail = &node->next; + info->ndev++; + } + *tail = NULL; + if (info->ndev == 0) + printk(KERN_INFO "qlogic_cs: no SCSI devices found\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + qlogic_release((u_long)link); + return; + +} /* qlogic_config */ + +/*====================================================================*/ + +static void qlogic_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "qlogic_release(0x%p)\n", link); + + if (GET_USE_COUNT(&__this_module) != 0) { + DEBUG(0, "qlogic_cs: release postponed, device still open\n"); + link->state |= DEV_STALE_CONFIG; + return; + } + + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + if (link->state & DEV_STALE_LINK) + qlogic_detach(link); + +} /* qlogic_release */ + +/*====================================================================*/ + +static int qlogic_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "qlogic_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + qlogic_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + scsi_info_t *info = link->priv; + CardServices(RequestConfiguration, link->handle, &link->conf); + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + outb( 0x80, link->io.BasePort1+0xd); + outb( 0x24, link->io.BasePort1+0x9); + outb( 0x04, link->io.BasePort1+0xd); + } + qlogic_reset(NULL); + } + break; + } + return 0; +} /* qlogic_event */ + +/*====================================================================*/ + +static int __init init_qlogic_cs(void) { + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "qlogic_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach); + return 0; +} + +static void __exit exit_qlogic_cs(void) { + DEBUG(0, "qlogic_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + qlogic_detach(dev_list); +} + +module_init(init_qlogic_cs); +module_exit(exit_qlogic_cs); diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index 6196d8eb2d20..9bc66953da23 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -21,7 +21,7 @@ Version 0.46 1/30/97 - kernel 1.2.0+ Functions as standalone, loadable, and PCMCIA driver, the latter from - Dave Hind's PCMCIA package. + Dave Hinds' PCMCIA package. Redistributable under terms of the GNU Public License @@ -107,7 +107,6 @@ #ifdef PCMCIA #undef QL_INT_ACTIVE_HIGH #define QL_INT_ACTIVE_HIGH 0 -#define MODULE #endif #include diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index a7418f18be60..89265a47f0f7 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1074,7 +1074,7 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd, } sg_count -= n; } - } else { + } else if (Cmnd->request_bufflen) { Cmnd->SCp.ptr = (char *)(unsigned long) sbus_map_single(qpti->sdev, Cmnd->request_buffer, @@ -1083,6 +1083,10 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd, cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr); cmd->dataseg[0].d_count = Cmnd->request_bufflen; cmd->segment_cnt = 1; + } else { + cmd->dataseg[0].d_base = 0; + cmd->dataseg[0].d_count = 0; + cmd->segment_cnt = 1; /* Shouldn't this be 0? */ } /* Committed, record Scsi_Cmd so we can find it later. */ diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index 06be153261de..b6298ca83920 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -253,6 +253,7 @@ static short *beep_buf; static volatile struct dbdma_cmd *beep_dbdma_cmd; static void (*orig_mksound)(unsigned int, unsigned int); static int is_pbook_3400; +static unsigned char *latch_base; static int is_pbook_G3; static unsigned char *macio_base; @@ -3695,7 +3696,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) } else if (is_pbook_3400) { feature_set(awacs_node, FEATURE_IOBUS_enable); udelay(10); - in_8((unsigned char *)0xf301a190); + in_8(latch_base + 0x190); } /* Resume pending sounds. */ PMacPlay(); @@ -5698,7 +5699,9 @@ void __init dmasound_init(void) * sound input. The 0x100 enables the SCSI bus * terminator power. */ - in_8((unsigned char *)0xf301a190); + latch_base = (unsigned char *) ioremap + (0xf301a000, 0x1000); + in_8(latch_base + 0x190); } else if (machine_is_compatible("PowerBook1,1") || machine_is_compatible("AAPL,PowerBook1998")) { struct device_node* mio; diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index a6d6603ace76..2e981bb996f0 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -2456,7 +2456,7 @@ static struct initvol { ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1370_state *s; mm_segment_t fs; @@ -2569,7 +2569,7 @@ static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii return -1; } -static void es1370_remove(struct pci_dev *dev) +static void __devinit es1370_remove(struct pci_dev *dev) { struct es1370_state *s = (struct es1370_state *)dev->driver_data; @@ -2589,7 +2589,7 @@ static void es1370_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static const struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 21e2c7c2b549..34054f77b6b5 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -2611,7 +2611,7 @@ static struct initvol { ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1371_state *s; mm_segment_t fs; @@ -2764,7 +2764,7 @@ static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pcii return -1; } -static void es1371_remove(struct pci_dev *dev) +static void __devinit es1371_remove(struct pci_dev *dev) { struct es1371_state *s = (struct es1371_state *)dev->driver_data; @@ -2788,7 +2788,7 @@ static void es1371_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static const struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index 72fbd14a5b4a..40331cb0b4b5 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -2190,10 +2190,9 @@ static int solo1_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct solo1_state *s; - struct pm_dev *pmdev; if (!RSRCISIOREGION(pcidev, 0) || !RSRCISIOREGION(pcidev, 1) || @@ -2293,7 +2292,7 @@ static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid return -1; } -static void solo1_remove(struct pci_dev *dev) +static void __devinit solo1_remove(struct pci_dev *dev) { struct solo1_state *s = (struct solo1_state *)dev->driver_data; @@ -2319,7 +2318,7 @@ static void solo1_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static const struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 6e17c8f93014..8a1dc66323a5 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -2430,7 +2430,7 @@ static struct initvol { ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { static const char __initlocaldata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller"; struct sv_state *s; @@ -2598,7 +2598,7 @@ static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) return -1; } -static void sv_remove(struct pci_dev *dev) +static void __devinit sv_remove(struct pci_dev *dev) { struct sv_state *s = (struct sv_state *)dev->driver_data; @@ -2625,7 +2625,7 @@ static void sv_remove(struct pci_dev *dev) dev->driver_data = NULL; } -static const struct pci_device_id id_table[] = { +static const struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 95974324c6ff..7f7b8687ed15 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -9,6 +9,9 @@ if [ ! "$CONFIG_USB" = "n" ]; then comment 'USB Controllers' dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB + if [ "$CONFIG_USB_UHCI" != "n" ]; then + bool ' USB-UHCI High Bandwidth (EXPERIMENTAL)' CONFIG_USB_UHCI_HIGH_BANDWIDTH + fi dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB if [ "$CONFIG_USB_UHCI_ALT" != "n" ]; then bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE @@ -28,10 +31,8 @@ comment 'USB Devices' bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC bool ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT - bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI + bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA - bool ' USB Belkin Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN - bool ' USB Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PERACOM fi dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB @@ -43,7 +44,8 @@ comment 'USB Devices' fi dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB - + dep_tristate ' PLUSB Prolific USB-Network driver' CONFIG_USB_PLUSB $CONFIG_USB + comment 'USB HID' dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB if [ "$CONFIG_USB_HID" != "y" ]; then diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 8712d60329cf..7f02917c0f44 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_USB_DC2XX) += dc2xx.o obj-$(CONFIG_USB_STORAGE) += usb-storage.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_DABUSB) += dabusb.o +obj-$(CONFIG_USB_PLUSB) += plusb.o obj-$(CONFIG_USB_OV511) += ov511.o # Extract lists of the multi-part drivers. diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c index 349a127a845a..ce7bc7e348ca 100644 --- a/drivers/usb/hid.c +++ b/drivers/usb/hid.c @@ -1233,6 +1233,19 @@ static void hid_init_input(struct hid_device *hid) } } +#define USB_VENDOR_ID_WACOM 0x056a +#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 +#define USB_DEVICE_ID_WACOM_INTUOS 0x0021 + +struct hid_blacklist { + __u16 idVendor; + __u16 idProduct; +} hid_blacklist[] = { + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE }, + { 0, 0 } +}; + static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) { struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; @@ -1241,6 +1254,10 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) unsigned rsize = 0; int n; + for (n = 0; hid_blacklist[n].idVendor; n++) + if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && + (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL; + if (interface->bInterfaceClass != USB_INTERFACE_CLASS_HID) return NULL; diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c index b2fd41ca49c3..1e00b7e49930 100644 --- a/drivers/usb/keybdev.c +++ b/drivers/usb/keybdev.c @@ -52,9 +52,9 @@ static unsigned char keybdev_mac_codes[256] = 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 42,105, 10,103,111, 0, 0, 0, 0, 0, 0, 0, - 76,125, 75, 0,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, - 0, 0, 0, 0,127, 24, 0,113, 0, 0, 0, 0, 0, 55, 55, 0 }; + 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, + 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, + 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 }; #endif diff --git a/drivers/usb/plusb.c b/drivers/usb/plusb.c new file mode 100644 index 000000000000..671ed942c425 --- /dev/null +++ b/drivers/usb/plusb.c @@ -0,0 +1,633 @@ +/*****************************************************************************/ + +/* + * plusb.c -- prolific pl-2302 driver. + * + * Copyright (C) 2000 Deti Fliegl (deti@fliegl.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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * + * $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $ + * + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG + +#include "usb.h" +#include "plusb.h" + +/* --------------------------------------------------------------------- */ + +#define NRPLUSB 4 + +/*-------------------------------------------------------------------*/ + +static plusb_t plusb[NRPLUSB]; + +/* --------------------------------------------------------------------- */ +static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_head *src) +{ + unsigned long flags; + struct list_head *tmp; + int ret = 0; + + spin_lock_irqsave (&s->lock, flags); + + if (list_empty (src)) { + // no elements in source buffer + ret = -1; + goto err; + } + tmp = src->next; + list_del (tmp); + list_add_tail (tmp, dst); + + err: spin_unlock_irqrestore (&s->lock, flags); + return ret; +} +/*-------------------------------------------------------------------*/ + +static int plusb_my_bulk(plusb_t *s, int pipe, void *data, int size, int *actual_length) +{ + int ret; + + dbg("plusb_my_bulk: len:%d",size); + + ret=usb_bulk_msg(s->usbdev, pipe, data, size, actual_length, 500); + if(ret<0) { + err("plusb: usb_bulk_msg failed(%d)",ret); + } + + if( ret == -EPIPE ) { + warn("CLEAR_FEATURE request to remove STALL condition."); + if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) + err("request failed"); + } + + dbg("plusb_my_bulk: finished act: %d", *actual_length); + return ret; +} + +/* --------------------------------------------------------------------- */ + +static void plusb_bh(void *context) +{ + plusb_t *s=context; + struct net_device_stats *stats=&s->net_stats; + int ret=0; + int actual_length; + skb_list_t *skb_list; + struct sk_buff *skb; + + dbg("plusb_bh: i:%d",in_interrupt()); + + while(!list_empty(&s->tx_skb_list)) { + + if(!(s->status&_PLUSB_TXOK)) + break; + + skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list); + if(!skb_list->state) { + dbg("plusb_bh: not yet ready"); + schedule(); + continue; + } + + skb=skb_list->skb; + ret=plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE), + skb->data, skb->len, &actual_length); + + if(ret || skb->len != actual_length ||!(skb->len%64)) { + plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE), + NULL, 0, &actual_length); + } + + if(!ret) { + stats->tx_packets++; + stats->tx_bytes+=skb->len; + } + else { + stats->tx_errors++; + stats->tx_aborted_errors++; + } + + dbg("plusb_bh: dev_kfree_skb"); + + dev_kfree_skb(skb); + skb_list->state=0; + plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list); + } + + dbg("plusb_bh: finished"); + s->in_bh=0; +} + +/* --------------------------------------------------------------------- */ + +static int plusb_net_xmit(struct sk_buff *skb, struct net_device *dev) +{ + plusb_t *s=dev->priv; + skb_list_t *skb_list; + int ret=NET_XMIT_SUCCESS; + + dbg("plusb_net_xmit: len:%d i:%d",skb->len,in_interrupt()); + + if(!s->connected || list_empty(&s->free_skb_list)) { + ret=NET_XMIT_CN; + goto lab; + } + + plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list); + skb_list = list_entry (s->tx_skb_list.prev, skb_list_t, skb_list); + skb_list->skb=skb; + skb_list->state=1; + +lab: + if(s->in_bh) + return ret; + + dbg("plusb_net_xmit: queue_task"); + + s->in_bh=1; + queue_task(&s->bh, &tq_scheduler); + + dbg("plusb_net_xmit: finished"); + return ret; + +} + +/* --------------------------------------------------------------------- */ + +static void plusb_bulk_complete(urb_t *purb) +{ + plusb_t *s=purb->context; + + dbg("plusb_bulk_complete: status:%d length:%d",purb->status,purb->actual_length); + if(!s->connected) + return; + + if( !purb->status) { + struct sk_buff *skb; + unsigned char *dst; + int len=purb->transfer_buffer_length; + struct net_device_stats *stats=&s->net_stats; + + skb=dev_alloc_skb(len); + + if(!skb) { + err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len); + stats->rx_dropped++; + return; + } + + dst=(char *)skb_put(skb, len); + memcpy( dst, purb->transfer_buffer, len); + + skb->dev=&s->net_dev; + skb->protocol=eth_type_trans(skb, skb->dev); + stats->rx_packets++; + stats->rx_bytes+=len; + netif_rx(skb); + } + else + purb->status=0; +} + +/* --------------------------------------------------------------------- */ + +static void plusb_int_complete(urb_t *purb) +{ + plusb_t *s=purb->context; + s->status=((unsigned char*)purb->transfer_buffer)[0]&255; +#if 0 + if((s->status&0x3f)!=0x20) { + warn("invalid device status %02X", s->status); + return; + } +#endif + if(!s->connected) + return; + + if(s->status&_PLUSB_RXD) { + int ret; + + if(s->bulkurb->status) { + err("plusb_int_complete: URB still in use"); + return; + } + + ret=usb_submit_urb(s->bulkurb); + if(ret && ret!=-EBUSY) { + err("plusb_int_complete: usb_submit_urb failed"); + } + } + + if(purb->status || s->status!=160) + dbg("status: %p %d buf: %02X", purb->dev, purb->status, s->status); +} + +/* --------------------------------------------------------------------- */ + +static void plusb_free_all(plusb_t *s) +{ + struct list_head *skb; + skb_list_t *skb_list; + + dbg("plusb_free_all"); + run_task_queue(&tq_immediate); + + if(s->inturb) { + dbg("unlink inturb"); + usb_unlink_urb(s->inturb); + } + + if(s->inturb && s->inturb->transfer_buffer) { + dbg("kfree inturb->transfer_buffer"); + kfree(s->inturb->transfer_buffer); + s->inturb->transfer_buffer=NULL; + } + + if(s->inturb) { + dbg("free_urb inturb"); + usb_free_urb(s->inturb); + s->inturb=NULL; + } + + if(s->bulkurb) { + dbg("unlink bulkurb"); + usb_unlink_urb(s->bulkurb); + } + + if(s->bulkurb && s->bulkurb->transfer_buffer) { + dbg("kfree bulkurb->transfer_buffer"); + kfree(s->bulkurb->transfer_buffer); + s->bulkurb->transfer_buffer=NULL; + } + if(s->bulkurb) { + dbg("free_urb bulkurb"); + usb_free_urb(s->bulkurb); + s->bulkurb=NULL; + } + + while(!list_empty(&s->free_skb_list)) { + skb=s->free_skb_list.next; + list_del(skb); + skb_list = list_entry (skb, skb_list_t, skb_list); + kfree(skb_list); + } + + while(!list_empty(&s->tx_skb_list)) { + skb=s->tx_skb_list.next; + list_del(skb); + skb_list = list_entry (skb, skb_list_t, skb_list); + kfree(skb_list); + } + dbg("plusb_free_all: finished"); +} + +/*-------------------------------------------------------------------*/ + +static int plusb_alloc(plusb_t *s) +{ + int i; + skb_list_t *skb; + + dbg("plusb_alloc"); + + for(i=0 ; i < _SKB_NUM ; i++) { + skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL); + if(!skb) { + err("kmalloc for skb_list failed"); + goto reject; + } + memset(skb, 0, sizeof(skb_list_t)); + list_add(&skb->skb_list, &s->free_skb_list); + } + + dbg("inturb allocation:"); + s->inturb=usb_alloc_urb(0); + if(!s->inturb) { + err("alloc_urb failed"); + goto reject; + } + + dbg("bulkurb allocation:"); + s->bulkurb=usb_alloc_urb(0); + if(!s->bulkurb) { + err("alloc_urb failed"); + goto reject; + } + + dbg("bulkurb/inturb init:"); + s->inturb->dev=s->usbdev; + s->inturb->pipe=usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE); + s->inturb->transfer_buffer=kmalloc(64, GFP_KERNEL); + if(!s->inturb->transfer_buffer) { + err("kmalloc failed"); + goto reject; + } + + s->inturb->transfer_buffer_length=1; + s->inturb->complete=plusb_int_complete; + s->inturb->context=s; + s->inturb->interval=10; + + dbg("inturb submission:"); + if(usb_submit_urb(s->inturb)<0) { + err("usb_submit_urb failed"); + goto reject; + } + + dbg("bulkurb init:"); + s->bulkurb->dev=s->usbdev; + s->bulkurb->pipe=usb_rcvbulkpipe (s->usbdev, _PLUSB_BULKINPIPE); + s->bulkurb->transfer_buffer=kmalloc(_BULK_DATA_LEN, GFP_KERNEL); + if(!s->bulkurb->transfer_buffer) { + err("kmalloc failed"); + goto reject; + } + + s->bulkurb->transfer_buffer_length=_BULK_DATA_LEN; + s->bulkurb->complete=plusb_bulk_complete; + s->bulkurb->context=s; + + dbg("plusb_alloc: finished"); + + return 0; + + reject: + dbg("plusb_alloc: failed"); + + plusb_free_all(s); + return -ENOMEM; +} + +/*-------------------------------------------------------------------*/ + +static int plusb_net_open(struct net_device *dev) +{ + plusb_t *s=dev->priv; + + dbg("plusb_net_open"); + + if(plusb_alloc(s)) + return -ENOMEM; + + s->opened=1; + MOD_INC_USE_COUNT; + + dbg("plusb_net_open: success"); + + return 0; + +} + +/* --------------------------------------------------------------------- */ + +static int plusb_net_stop(struct net_device *dev) +{ + plusb_t *s=dev->priv; + + dbg("plusb_net_stop"); + + plusb_free_all(s); + s->opened=0; + MOD_DEC_USE_COUNT; + dbg("plusb_net_stop:finished"); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static struct net_device_stats *plusb_net_get_stats(struct net_device *dev) +{ + plusb_t *s=dev->priv; + + dbg("net_device_stats"); + + return &s->net_stats; +} + +/* --------------------------------------------------------------------- */ + +static plusb_t *plusb_find_struct (void) +{ + int u; + + for (u = 0; u < NRPLUSB; u++) { + plusb_t *s = &plusb[u]; + if (!s->connected) + return s; + } + return NULL; +} + +/* --------------------------------------------------------------------- */ + +static void plusb_disconnect (struct usb_device *usbdev, void *ptr) +{ + plusb_t *s = ptr; + + dbg("plusb_disconnect"); + s->connected = 0; + + plusb_free_all(s); + + if(!s->opened && s->net_dev.name) { + dbg("unregistering netdev: %s",s->net_dev.name); + unregister_netdev(&s->net_dev); + kfree(s->net_dev.name); + s->net_dev.name=NULL; + } + + dbg("plusb_disconnect: finished"); + MOD_DEC_USE_COUNT; +} + +/* --------------------------------------------------------------------- */ + +int plusb_net_init(struct net_device *dev) +{ + dbg("plusb_net_init"); + + dev->open=plusb_net_open; + dev->stop=plusb_net_stop; + dev->hard_start_xmit=plusb_net_xmit; + dev->get_stats = plusb_net_get_stats; + ether_setup(dev); + dev->tx_queue_len = 0; + dev->flags = IFF_POINTOPOINT|IFF_NOARP; + + + dbg("plusb_net_init: finished"); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum) +{ + plusb_t *s; + + dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", + usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum); + + if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct != 0x1) + return NULL; + + /* We don't handle multiple configurations */ + if (usbdev->descriptor.bNumConfigurations != 1) + return NULL; + + s = plusb_find_struct (); + if (!s) + return NULL; + + s->usbdev = usbdev; + + if (usb_set_configuration (s->usbdev, usbdev->config[0].bConfigurationValue) < 0) { + err("set_configuration failed"); + return NULL; + } + + if (usb_set_interface (s->usbdev, 0, 0) < 0) { + err("set_interface failed"); + return NULL; + } + + if(!s->net_dev.name) { + s->net_dev.name=kmalloc(16, GFP_KERNEL); + + if(!s->net_dev.name || dev_alloc_name(&s->net_dev,"plusb%d")<0) { + err("alloc name failed\n"); + return NULL; + } + + s->net_dev.init=plusb_net_init; + s->net_dev.priv=s; + if(!register_netdev(&s->net_dev)) + info("registered: %s", s->net_dev.name); + else { + err("register_netdev failed"); + kfree(s->net_dev.name); + s->net_dev.name=NULL; + } + } + + s->connected = 1; + + if(s->opened) { + dbg("net device already allocated, restarting USB transfers"); + plusb_alloc(s); + } + + info("bound to interface: %d dev: %p", ifnum, usbdev); + MOD_INC_USE_COUNT; + return s; +} +/* --------------------------------------------------------------------- */ + +static struct usb_driver plusb_driver = +{ + name: "plusb", + probe: plusb_probe, + disconnect: plusb_disconnect, +}; + +/* --------------------------------------------------------------------- */ + +int __init plusb_init (void) +{ + unsigned u; + dbg("plusb_init"); + + /* initialize struct */ + for (u = 0; u < NRPLUSB; u++) { + plusb_t *s = &plusb[u]; + memset (s, 0, sizeof (plusb_t)); + s->bh.routine = (void (*)(void *))plusb_bh; + s->bh.data = s; + INIT_LIST_HEAD (&s->tx_skb_list); + INIT_LIST_HEAD (&s->free_skb_list); + spin_lock_init (&s->lock); + } + + /* register misc device */ + usb_register (&plusb_driver); + + dbg("plusb_init: driver registered"); + + return 0; +} + +/* --------------------------------------------------------------------- */ + +void __exit plusb_cleanup (void) +{ + unsigned u; + + dbg("plusb_cleanup"); + for (u = 0; u < NRPLUSB; u++) { + plusb_t *s = &plusb[u]; + if(s->net_dev.name) { + dbg("unregistering netdev: %s",s->net_dev.name); + unregister_netdev(&s->net_dev); + kfree(s->net_dev.name); + s->net_dev.name=NULL; + } + } + usb_deregister (&plusb_driver); + dbg("plusb_cleanup: finished"); +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE +MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de"); +MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000"); + +/* --------------------------------------------------------------------- */ +int __init init_module (void) +{ + return plusb_init (); +} +/* --------------------------------------------------------------------- */ +void __exit cleanup_module (void) +{ + plusb_cleanup (); +} + +#endif + +/* --------------------------------------------------------------------- */ diff --git a/drivers/usb/plusb.h b/drivers/usb/plusb.h new file mode 100644 index 000000000000..a77ae0f01326 --- /dev/null +++ b/drivers/usb/plusb.h @@ -0,0 +1,48 @@ +#define _PLUSB_INTPIPE 0x1 +#define _PLUSB_BULKOUTPIPE 0x2 +#define _PLUSB_BULKINPIPE 0x3 + +#define _SKB_NUM 1000 +// 7 6 5 4 3 2 1 0 +// tx rx 1 0 +// 1110 0000 rxdata +// 1010 0000 idle +// 0010 0000 tx over +// 0110 tx over + rxd + +#define _PLUSB_RXD 0x40 +#define _PLUSB_TXOK 0x80 + +#ifdef __KERNEL__ +#define _BULK_DATA_LEN 16384 + +typedef struct +{ + struct list_head skb_list; + struct sk_buff *skb; + int state; +} skb_list_t,*pskb_list_t; + +typedef struct +{ + struct usb_device *usbdev; + + int status; + int connected; + int in_bh; + int opened; + + spinlock_t lock; + + urb_t *inturb; + urb_t *bulkurb; + + struct list_head tx_skb_list; + struct list_head free_skb_list; + struct tq_struct bh; + + struct net_device net_dev; + struct net_device_stats net_stats; +} plusb_t,*pplusb_t; + +#endif diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index 57238eb0b331..91cdf337c6eb 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -37,6 +37,7 @@ int usb_dc2xx_init(void); int usb_scanner_init(void); int usb_stor_init(void); int dabusb_init(void); +int plusb_init(void); int usb_mouse_init(void); int usb_kbd_init(void); int graphire_init(void); @@ -99,6 +100,9 @@ int usb_init(void) #ifdef CONFIG_USB_DABUSB dabusb_init(); #endif +#ifdef CONFIG_USB_PLUSB + plusb_init(); +#endif #ifdef CONFIG_USB_MOUSE usb_mouse_init(); #endif diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index 22e045cac33b..f87600e83869 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -14,6 +14,24 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (02/14/2000) gkh + * Removed the Belkin and Peracom functionality from the driver due to + * the lack of support from the vendor, and me not wanting people to + * accidenatly buy the device, expecting it to work with Linux. + * Added read_bulk_callback and write_bulk_callback to the type structure + * for the needs of the FTDI and WhiteHEAT driver. + * Changed all reverences to FTDI to FTDI_SIO at the request of Bill + * Ryder. + * Changed the output urb size back to the max endpoint size to make + * the ftdi_sio driver have it easier, and due to the fact that it didn't + * really increase the speed any. + * + * (02/11/2000) gkh + * Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a + * patch from Miles Lott (milos@insync.net). + * Fixed bug with not restoring the minor range that a device grabs, if + * the startup function fails (thanks Miles for finding this). + * * (02/05/2000) gkh * Added initial framework for the Keyspan PDA serial converter so that * Brian Warner has a place to put his code. @@ -228,6 +246,23 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor) } +static void return_serial (struct usb_serial *serial) +{ + int i; + + dbg("return_serial"); + + if (serial == NULL) + return; + + for (i = 0; i < serial->num_ports; ++i) { + serial_table[serial->minor + i] = NULL; + } + + return; +} + + #ifdef USES_EZUSB_FUNCTIONS /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ #define CPUCS_REG 0x7F92 @@ -264,67 +299,6 @@ static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) #endif /* USES_EZUSB_FUNCTIONS */ -static void serial_read_bulk (struct urb *urb) -{ - struct usb_serial *serial = (struct usb_serial *)urb->context; - struct tty_struct *tty = serial->tty; - unsigned char *data = urb->transfer_buffer; - int i; - - dbg("serial_read_irq"); - - if (urb->status) { - dbg("nonzero read bulk status received: %d", urb->status); - return; - } - -#ifdef DEBUG - if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ("0x%.2x ", data[i]); - } - printk ("\n"); - } -#endif - - if (urb->actual_length) { - for (i = 0; i < urb->actual_length ; ++i) { - tty_insert_flip_char(tty, data[i], 0); - } - tty_flip_buffer_push(tty); - } - - /* Continue trying to always read */ - if (usb_submit_urb(urb)) - dbg("failed resubmitting read urb"); - - return; -} - - -static void serial_write_bulk (struct urb *urb) -{ - struct usb_serial *serial = (struct usb_serial *) urb->context; - struct tty_struct *tty = serial->tty; - - dbg("serial_write_irq"); - - if (urb->status) { - dbg("nonzero write bulk status received: %d", urb->status); - return; - } - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); - - return; -} - - - /***************************************************************************** * Driver tty interface functions *****************************************************************************/ @@ -547,53 +521,6 @@ static void serial_unthrottle (struct tty_struct * tty) } -#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) -/***************************************************************************** - * eTek specific driver functions - *****************************************************************************/ -static int etek_serial_open (struct tty_struct *tty, struct file *filp) -{ - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("etek_serial_open port %d", port); - - if (serial->active[port]) { - dbg ("device already open"); - return -EINVAL; - } - serial->active[port] = 1; - - /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb[port])) - dbg("usb_submit_urb(read bulk) failed"); - - /* Need to do device specific setup here (control lines, baud rate, etc.) */ - /* FIXME!!! */ - - return (0); -} - - -static void etek_serial_close(struct tty_struct *tty, struct file * filp) -{ - struct usb_serial *serial = (struct usb_serial *) tty->driver_data; - int port = MINOR(tty->device) - serial->minor; - - dbg("etek_serial_close port %d", port); - - /* Need to change the control lines here */ - /* FIXME */ - - /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb[port]); - usb_unlink_urb (&serial->read_urb[port]); - serial->active[port] = 0; -} -#endif /* defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) */ - - - #ifdef CONFIG_USB_SERIAL_WHITEHEAT /***************************************************************************** * Connect Tech's White Heat specific driver functions @@ -851,6 +778,9 @@ static int visor_startup (struct usb_serial *serial) case VISOR_FUNCTION_HOTSYNC: string = "HotSync"; break; + case VISOR_FUNCTION_CONSOLE: + string = "Console"; + break; case VISOR_FUNCTION_REMOTE_FILE_SYS: string = "Remote File System"; break; @@ -879,11 +809,11 @@ static int visor_startup (struct usb_serial *serial) #endif /* CONFIG_USB_SERIAL_VISOR*/ -#ifdef CONFIG_USB_SERIAL_FTDI +#ifdef CONFIG_USB_SERIAL_FTDI_SIO /****************************************************************************** - * FTDI Serial Converter specific driver functions + * FTDI SIO Serial Converter specific driver functions ******************************************************************************/ -static int ftdi_serial_open (struct tty_struct *tty, struct file *filp) +static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; int port = MINOR(tty->device) - serial->minor; @@ -907,7 +837,7 @@ static int ftdi_serial_open (struct tty_struct *tty, struct file *filp) } -static void ftdi_serial_close (struct tty_struct *tty, struct file *filp) +static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp) { struct usb_serial *serial = (struct usb_serial *) tty->driver_data; int port = MINOR(tty->device) - serial->minor; @@ -924,7 +854,7 @@ static void ftdi_serial_close (struct tty_struct *tty, struct file *filp) } -#endif +#endif /* CONFIG_USB_SERIAL_FTDI_SIO */ #ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA @@ -1111,6 +1041,67 @@ static int generic_chars_in_buffer (struct tty_struct *tty) } +static void generic_read_bulk_callback (struct urb *urb) +{ + struct usb_serial *serial = (struct usb_serial *)urb->context; + struct tty_struct *tty = serial->tty; + unsigned char *data = urb->transfer_buffer; + int i; + + dbg("generic_read_bulk_callback"); + + if (urb->status) { + dbg("nonzero read bulk status received: %d", urb->status); + return; + } + +#ifdef DEBUG + if (urb->actual_length) { + printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); + for (i = 0; i < urb->actual_length; ++i) { + printk ("0x%.2x ", data[i]); + } + printk ("\n"); + } +#endif + + if (urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + } + + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); + + return; +} + + +static void generic_write_bulk_callback (struct urb *urb) +{ + struct usb_serial *serial = (struct usb_serial *) urb->context; + struct tty_struct *tty = serial->tty; + + dbg("generic_write_bulk_callback"); + + if (urb->status) { + dbg("nonzero write bulk status received: %d", urb->status); + return; + } + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + wake_up_interruptible(&tty->write_wait); + + return; +} + + + static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_serial *serial = NULL; @@ -1211,8 +1202,10 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) /* if this device type has a startup function, call it */ if (type->startup) { - if (type->startup (serial)) + if (type->startup (serial)) { + return_serial (serial); return NULL; + } } /* set up the endpoint information */ @@ -1223,19 +1216,29 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) err("Couldn't allocate bulk_in_buffer"); goto probe_error; } - FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), - serial->bulk_in_buffer[i], buffer_size, serial_read_bulk, serial); + if (serial->type->read_bulk_callback) { + FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), + serial->bulk_in_buffer[i], buffer_size, serial->type->read_bulk_callback, serial); + } else { + FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), + serial->bulk_in_buffer[i], buffer_size, generic_read_bulk_callback, serial); + } } for (i = 0; i < num_bulk_out; ++i) { - serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize * 2; + serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize; serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL); if (!serial->bulk_out_buffer[i]) { err("Couldn't allocate bulk_out_buffer"); goto probe_error; } - FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), - serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial_write_bulk, serial); + if (serial->type->write_bulk_callback) { + FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), + serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial->type->write_bulk_callback, serial); + } else { + FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), + serial->bulk_out_buffer[i], serial->bulk_out_size[i], generic_write_bulk_callback, serial); + } } #if 0 /* use this code when WhiteHEAT is up and running */ @@ -1295,7 +1298,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) usb_unlink_urb (&serial->write_urb[i]); usb_unlink_urb (&serial->read_urb[i]); serial->active[i] = 0; - serial_table[serial->minor + i] = NULL; } /* free up any memory that we allocated */ @@ -1313,6 +1315,10 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i); } + /* return the minor range that this device had */ + return_serial (serial); + + /* free up any memory that we allocated */ kfree (serial); } else { diff --git a/drivers/usb/usb-serial.h b/drivers/usb/usb-serial.h index 5a35b94b4837..6d8e978b5f28 100644 --- a/drivers/usb/usb-serial.h +++ b/drivers/usb/usb-serial.h @@ -35,17 +35,13 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); /* USB Serial devices vendor ids and device ids that this driver supports */ -#define BELKIN_VENDOR_ID 0x056c -#define BELKIN_SERIAL_CONVERTER_ID 0x8007 -#define PERACOM_VENDOR_ID 0x0565 -#define PERACOM_SERIAL_CONVERTER_ID 0x0001 #define CONNECT_TECH_VENDOR_ID 0x0710 #define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 #define CONNECT_TECH_WHITE_HEAT_ID 0x8001 #define HANDSPRING_VENDOR_ID 0x082d #define HANDSPRING_VISOR_ID 0x0100 #define FTDI_VENDOR_ID 0x0403 -#define FTDI_SERIAL_CONVERTER_ID 0x8372 +#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372 #define KEYSPAN_VENDOR_ID 0x06cd #define KEYSPAN_PDA_FAKE_ID 0x0103 #define KEYSPAN_PDA_ID 0x0103 @@ -125,6 +121,8 @@ struct usb_serial_device_type { int (*chars_in_buffer)(struct tty_struct *tty); void (*throttle)(struct tty_struct * tty); void (*unthrottle)(struct tty_struct * tty); + void (*read_bulk_callback)(struct urb *urb); + void (*write_bulk_callback)(struct urb *urb); }; @@ -135,6 +133,9 @@ static void generic_serial_close (struct tty_struct *tty, struct file *filp); static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); static int generic_write_room (struct tty_struct *tty); static int generic_chars_in_buffer (struct tty_struct *tty); +static void generic_read_bulk_callback (struct urb *urb); +static void generic_write_bulk_callback (struct urb *urb); + #ifdef CONFIG_USB_SERIAL_GENERIC /* All of the device info needed for the Generic Serial Converter */ @@ -154,59 +155,8 @@ static struct usb_serial_device_type generic_device = { write: generic_serial_write, write_room: generic_write_room, chars_in_buffer: generic_chars_in_buffer, -}; -#endif - -#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) -/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */ -static int etek_serial_open (struct tty_struct *tty, struct file *filp); -static void etek_serial_close (struct tty_struct *tty, struct file *filp); -#endif - -#ifdef CONFIG_USB_SERIAL_BELKIN -/* All of the device info needed for the Belkin Serial Converter */ -static __u16 belkin_vendor_id = BELKIN_VENDOR_ID; -static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER_ID; -static struct usb_serial_device_type belkin_device = { - name: "Belkin", - idVendor: &belkin_vendor_id, /* the Belkin vendor id */ - idProduct: &belkin_product_id, /* the Belkin serial converter product id */ - needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ - needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ - needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ - num_interrupt_in: 1, - num_bulk_in: 1, - num_bulk_out: 1, - num_ports: 1, - open: etek_serial_open, - close: etek_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, -}; -#endif - - -#ifdef CONFIG_USB_SERIAL_PERACOM -/* All of the device info needed for the Peracom Serial Converter */ -static __u16 peracom_vendor_id = PERACOM_VENDOR_ID; -static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER_ID; -static struct usb_serial_device_type peracom_device = { - name: "Peracom", - idVendor: &peracom_vendor_id, /* the Peracom vendor id */ - idProduct: &peracom_product_id, /* the Peracom serial converter product id */ - needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ - needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ - needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ - num_ports: 1, - num_interrupt_in: 1, - num_bulk_in: 1, - num_bulk_out: 1, - open: etek_serial_open, - close: etek_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, + read_bulk_callback: generic_read_bulk_callback, + write_bulk_callback: generic_write_bulk_callback }; #endif @@ -338,23 +288,25 @@ static struct usb_serial_device_type handspring_device = { chars_in_buffer: generic_chars_in_buffer, throttle: visor_throttle, unthrottle: visor_unthrottle, - startup: visor_startup + startup: visor_startup, + read_bulk_callback: generic_read_bulk_callback, + write_bulk_callback: generic_write_bulk_callback }; #endif -#ifdef CONFIG_USB_SERIAL_FTDI +#ifdef CONFIG_USB_SERIAL_FTDI_SIO /* function prototypes for a FTDI serial converter */ -static int ftdi_serial_open (struct tty_struct *tty, struct file *filp); -static void ftdi_serial_close (struct tty_struct *tty, struct file *filp); +static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp); +static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp); /* All of the device info needed for the Handspring Visor */ -static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; -static __u16 ftdi_product_id = FTDI_SERIAL_CONVERTER_ID; -static struct usb_serial_device_type ftdi_device = { - name: "FTDI", +static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; +static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID; +static struct usb_serial_device_type ftdi_sio_device = { + name: "FTDI SIO", idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */ - idProduct: &ftdi_product_id, /* the FTDI product id */ + idProduct: &ftdi_sio_product_id, /* the FTDI SIO product id */ needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ @@ -362,11 +314,13 @@ static struct usb_serial_device_type ftdi_device = { num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, - open: ftdi_serial_open, - close: ftdi_serial_close, + open: ftdi_sio_serial_open, + close: ftdi_sio_serial_close, write: generic_serial_write, write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer + chars_in_buffer: generic_chars_in_buffer, + read_bulk_callback: generic_read_bulk_callback, + write_bulk_callback: generic_write_bulk_callback }; #endif @@ -408,7 +362,9 @@ static struct usb_serial_device_type keyspan_pda_device = { close: keyspan_pda_serial_close, write: generic_serial_write, write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer + chars_in_buffer: generic_chars_in_buffer, + read_bulk_callback: generic_read_bulk_callback, + write_bulk_callback: generic_write_bulk_callback }; #endif @@ -423,17 +379,11 @@ static struct usb_serial_device_type *usb_serial_devices[] = { &whiteheat_fake_device, &whiteheat_device, #endif -#ifdef CONFIG_USB_SERIAL_BELKIN - &belkin_device, -#endif -#ifdef CONFIG_USB_SERIAL_PERACOM - &peracom_device, -#endif #ifdef CONFIG_USB_SERIAL_VISOR &handspring_device, #endif -#ifdef CONFIG_USB_SERIAL_FTDI - &ftdi_device, +#ifdef CONFIG_USB_SERIAL_FTDI_SIO + &ftdi_sio_device, #endif #ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA &keyspan_pda_fake_device, diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c index b79f9cc312ef..1b72efd92621 100644 --- a/drivers/usb/usb-uhci.c +++ b/drivers/usb/usb-uhci.c @@ -12,9 +12,10 @@ * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * - * $Id: usb-uhci.c,v 1.185 2000/02/05 21:29:19 acher Exp $ + * $Id: usb-uhci.c,v 1.197 2000/02/15 17:44:22 acher Exp $ */ +#include #include #include #include @@ -54,7 +55,6 @@ #define dbg(format, arg...) do {} while (0) #include -static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); #ifdef DEBUG_SYMBOLS #define _static @@ -70,9 +70,18 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); static kmem_cache_t *urb_priv_kmem; #endif -#define USE_CTRL_DEPTH_FIRST 1 // 0: Breadth first, 1: Depth first (standard) +#define USE_CTRL_DEPTH_FIRST 0 // 0: Breadth first, 1: Depth first +#define USE_BULK_DEPTH_FIRST 0 // 0: Breadth first, 1: Depth first +#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH +#define USE_RECLAMATION_LOOP +#else //#define USE_RECLAMATION_LOOP +#endif + +// stop bandwidth reclamation after (roughly) 50ms (depends also on +// hub polling interval) +#define IDLE_TIMEOUT (HZ/20) _static int rh_submit_urb (urb_t *urb); _static int rh_unlink_urb (urb_t *urb); @@ -101,22 +110,81 @@ void clean_descs(uhci_t *s, int force) } } /*-------------------------------------------------------------------*/ -_static void queue_urb (uhci_t *s, struct list_head *p) +#ifdef USE_RECLAMATION_LOOP +_static void enable_desc_loop(uhci_t *s, urb_t *urb) +{ + int flags; + + dbg("enable_desc_loop: enter"); + + spin_lock_irqsave (&s->qh_lock, flags); + s->chain_end->hw.qh.head=virt_to_bus(s->control_chain)|UHCI_PTR_QH; + s->loop_usage++; + ((urb_priv_t*)urb->hcpriv)->use_loop=1; + spin_unlock_irqrestore (&s->qh_lock, flags); + + dbg("enable_desc_loop: finished"); +} +/*-------------------------------------------------------------------*/ +_static void disable_desc_loop(uhci_t *s, urb_t *urb) +{ + int flags; + + dbg("disable_desc_loop: enter\n"); + + spin_lock_irqsave (&s->qh_lock, flags); + + if (((urb_priv_t*)urb->hcpriv)->use_loop) { + s->loop_usage--; + + if (!s->loop_usage) + s->chain_end->hw.qh.head=UHCI_PTR_TERM; + + ((urb_priv_t*)urb->hcpriv)->use_loop=0; + } + spin_unlock_irqrestore (&s->qh_lock, flags); + + dbg("disable_desc_loop: finished"); + +} +#endif +/*-------------------------------------------------------------------*/ +_static void queue_urb (uhci_t *s, urb_t *urb) { unsigned long flags=0; + struct list_head *p=&urb->urb_list; + spin_lock_irqsave (&s->urb_list_lock, flags); +#ifdef USE_RECLAMATION_LOOP + { + int type; + type=usb_pipetype (urb->pipe); + + if ((type == PIPE_BULK) || (type == PIPE_CONTROL)) + enable_desc_loop(s, urb); + } +#endif + ((urb_priv_t*)urb->hcpriv)->started=jiffies; list_add_tail (p, &s->urb_list); spin_unlock_irqrestore (&s->urb_list_lock, flags); } /*-------------------------------------------------------------------*/ -_static void dequeue_urb (uhci_t *s, struct list_head *p) +_static void dequeue_urb (uhci_t *s, urb_t *urb) { - list_del (p); +#ifdef USE_RECLAMATION_LOOP + int type; + + type=usb_pipetype (urb->pipe); + + if ((type == PIPE_BULK) || (type == PIPE_CONTROL)) + disable_desc_loop(s, urb); +#endif + list_del (&urb->urb_list); } /*-------------------------------------------------------------------*/ _static int alloc_td (uhci_desc_t ** new, int flags) @@ -219,6 +287,7 @@ _static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink) return 0; } + /*-------------------------------------------------------------------*/ _static int delete_desc (uhci_desc_t *element) { @@ -451,11 +520,6 @@ _static int init_skel (uhci_t *s) insert_qh (s, s->bulk_chain, qh, 0); s->control_chain = qh; -#ifdef USE_RECLAMATION_LOOP - s->chain_end->hw.qh.head=virt_to_bus(s->control_chain)|UHCI_PTR_QH; - info("Using loop for bandwidth reclamation."); -#endif - for (n = 0; n < 8; n++) s->int_chain[n] = 0; @@ -625,7 +689,7 @@ _static int uhci_submit_control_urb (urb_t *urb) list_add (&qh->desc_list, &urb_priv->desc_list); urb->status = -EINPROGRESS; - queue_urb (s, &urb->urb_list); // queue before inserting in desc chain + queue_urb (s, urb); // queue before inserting in desc chain qh->hw.qh.element&=~UHCI_PTR_TERM; @@ -635,8 +699,8 @@ _static int uhci_submit_control_urb (urb_t *urb) insert_qh (s, s->control_chain, qh, 1); // insert after control chain else insert_qh (s, s->bulk_chain, qh, 0); // insert before bulk chain - //uhci_show_queue(qh); + dbg("uhci_submit_control end"); return 0; } @@ -651,11 +715,12 @@ _static int uhci_submit_bulk_urb (urb_t *urb) unsigned int pipe = urb->pipe; int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)); int info, len; + int depth_first=USE_BULK_DEPTH_FIRST; // UHCI descriptor chasing method - /* shouldn't the clear_halt be done in the USB core or in the client driver? - Thomas */ - if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) && - usb_clear_halt (urb->dev, usb_pipeendpoint (pipe) | (pipe & USB_DIR_IN))) + + if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) return -EPIPE; + if (urb->transfer_buffer_length < 0) { err("Negative transfer length in submit_bulk"); return -EINVAL; @@ -685,7 +750,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb) do { // TBD: Really allow zero-length packets? int pktsze = len; - alloc_td (&td, UHCI_PTR_DEPTH); + alloc_td (&td, UHCI_PTR_DEPTH * depth_first); if (!td) { delete_qh (s, qh); @@ -708,7 +773,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb) td->hw.td.status |= TD_CTRL_IOC; // last one generates INT //dbg("insert td %p, len %i",td,pktsze); - insert_td (s, qh, td, UHCI_PTR_DEPTH); + insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first); /* Alternate Data0/1 (start with Data0) */ usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)); @@ -717,7 +782,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb) list_add (&qh->desc_list, &urb_priv->desc_list); urb->status = -EINPROGRESS; - queue_urb (s, &urb->urb_list); + queue_urb (s, urb); qh->hw.qh.element&=~UHCI_PTR_TERM; @@ -727,6 +792,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb) dbg("uhci_submit_bulk_urb: exit"); return 0; } + /*-------------------------------------------------------------------*/ // unlinks an urb by dequeuing its qh, waits some frames and forgets it // Problem: unlinking in interrupt requires waiting for one frame (udelay) @@ -758,7 +824,7 @@ _static int uhci_unlink_urb (urb_t *urb) if (urb->status == -EINPROGRESS) { // URB probably still in work - dequeue_urb (s, &urb->urb_list); + dequeue_urb (s, urb); s->unlink_urb_done=1; spin_unlock_irqrestore (&s->urb_list_lock, flags); @@ -773,7 +839,7 @@ _static int uhci_unlink_urb (urb_t *urb) unlink_td (s, td, 1); } // wait at least 1 Frame - uhci_wait_ms(1); + uhci_wait_ms(1); while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) { td = list_entry (p, uhci_desc_t, desc_list); list_del (p); @@ -991,7 +1057,7 @@ _static int uhci_submit_int_urb (urb_t *urb) list_add_tail (&td->desc_list, &urb_priv->desc_list); urb->status = -EINPROGRESS; - queue_urb (s, &urb->urb_list); + queue_urb (s, urb); insert_td_horizontal (s, s->int_chain[nint], td); // store in INT-TDs @@ -1083,7 +1149,7 @@ _static int uhci_submit_iso_urb (urb_t *urb) if (n == last) { urb->status = -EINPROGRESS; - queue_urb (s, &urb->urb_list); + queue_urb (s, urb); } insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td); // store in iso-tds //uhci_show_td(td); @@ -1194,14 +1260,44 @@ _static int uhci_submit_urb (urb_t *urb) #endif return ret; } -/* - urb->status = -EINPROGRESS; - queue_urb (s, &urb->urb_list); - dbg("submit_urb: exit"); -*/ return 0; } +#ifdef USE_RECLAMATION_LOOP +// Removes bandwidth reclamation if URB idles too long +void check_idling_urbs(uhci_t *s) +{ + struct list_head *p,*p2; + urb_t *urb; + int type; + + //dbg("check_idling_urbs: enter i:%d",in_interrupt()); + + spin_lock (&s->urb_list_lock); + p = s->urb_list.prev; + + while (p != &s->urb_list) { + p2 = p; + p = p->prev; + urb=list_entry (p2, urb_t, urb_list); + type=usb_pipetype (urb->pipe); + +#if 0 + err("URB timers: %li now: %li %i\n", + ((urb_priv_t*)urb->hcpriv)->started +IDLE_TIMEOUT, jiffies, + type); +#endif + if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) && + (((urb_priv_t*)urb->hcpriv)->use_loop) && + ((((urb_priv_t*)urb->hcpriv)->started +IDLE_TIMEOUT) < jiffies)) + disable_desc_loop(s,urb); + + } + spin_unlock (&s->urb_list_lock); + + //dbg("check_idling_urbs: finished"); +} +#endif /*------------------------------------------------------------------- Virtual Root Hub -------------------------------------------------------------------*/ @@ -1313,10 +1409,13 @@ _static int rh_init_int_timer (urb_t *urb); _static void rh_int_timer_do (unsigned long ptr) { int len; - urb_t *urb = (urb_t*) ptr; uhci_t *uhci = urb->dev->bus->hcpriv; +#ifdef USE_RECLAMATION_LOOP + check_idling_urbs(uhci); +#endif + if (uhci->rh.send) { len = rh_send_irq (urb); if (len > 0) { @@ -1558,9 +1657,11 @@ _static int rh_unlink_urb (urb_t *urb) { uhci_t *uhci = urb->dev->bus->hcpriv; - dbg("Root-Hub unlink IRQ"); - uhci->rh.send = 0; - del_timer (&uhci->rh.rh_int_timer); + if (uhci->rh.urb==urb) { + dbg("Root-Hub unlink IRQ"); + uhci->rh.send = 0; + del_timer (&uhci->rh.rh_int_timer); + } return 0; } /*-------------------------------------------------------------------*/ @@ -1741,7 +1842,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb) // got less data than requested if ( (actual_length < maxlength)) { if (urb->transfer_flags & USB_DISABLE_SPD) { - ret = -EREMOTEIO; // treat as real error + status = -EREMOTEIO; // treat as real error dbg("process_transfer: SPD!!"); break; // exit after this TD because SP was detected } @@ -1777,6 +1878,10 @@ _static int process_transfer (uhci_t *s, urb_t *urb) urb->status = status; +#ifdef USE_RECLAMATION_LOOP + disable_desc_loop(s,urb); +#endif + dbg("process_transfer: urb %p, wanted len %d, len %d status %x err %d", urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count); //dbg("process_transfer: exit"); @@ -1971,7 +2076,7 @@ _static int process_urb (uhci_t *s, struct list_head *p) int proceed = 0; dbg("dequeued urb: %p", urb); - dequeue_urb (s, p); + dequeue_urb (s, urb); #ifdef DEBUG_SLAB kmem_cache_free(urb_priv_kmem, urb->hcpriv); @@ -2181,6 +2286,23 @@ _static int __init uhci_start_usb (uhci_t *s) return 0; } +_static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data) +{ + uhci_t *s = (uhci_t*) dev->data; + dbg("handle_apm_event(%d)", rqst); + if (s) { + switch (rqst) { + case PM_SUSPEND: + reset_hc (s); + break; + case PM_RESUME: + start_hc (s); + break; + } + } + return 0; +} + _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size) { uhci_t *s; @@ -2236,7 +2358,7 @@ _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_add } s->rh.numports = s->maxports; - + s->loop_usage=0; if (init_skel (s)) { usb_free_bus (bus); kfree(s); @@ -2306,23 +2428,6 @@ _static int __init start_uhci (struct pci_dev *dev) return -1; } -_static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data) -{ - uhci_t *s = (uhci_t*) dev->data; - dbg("handle_apm_event(%d)", rqst); - if (s) { - switch (rqst) { - case PM_SUSPEND: - reset_hc (s); - break; - case PM_RESUME: - start_hc (s); - break; - } - } - return 0; -} - int __init uhci_init (void) { int retval = -ENODEV; @@ -2385,11 +2490,9 @@ void __exit uhci_cleanup (void) uhci_cleanup_dev(s); } #ifdef DEBUG_SLAB - - if(kmem_cache_destroy(uhci_desc_kmem)) err("uhci_desc_kmem remained"); - + if(kmem_cache_destroy(urb_priv_kmem)) err("urb_priv_kmem remained"); #endif diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h index fcb96c3e0253..e74e23bd8122 100644 --- a/drivers/usb/usb-uhci.h +++ b/drivers/usb/usb-uhci.h @@ -2,7 +2,7 @@ #define __LINUX_UHCI_H /* - $Id: usb-uhci.h,v 1.39 2000/02/05 20:25:27 acher Exp $ + $Id: usb-uhci.h,v 1.41 2000/02/13 21:37:38 acher Exp $ */ #define MODNAME "usb-uhci" #define VERSTR "version v1.184 time " __TIME__ " " __DATE__ @@ -155,6 +155,8 @@ typedef struct { typedef struct { struct list_head desc_list; // list pointer to all corresponding TDs/QHs associated with this request int short_control_packet; + unsigned long started; + int use_loop; } urb_priv_t, *purb_priv_t; struct virt_root_hub { @@ -197,6 +199,7 @@ typedef struct uhci { spinlock_t qh_lock; spinlock_t td_lock; struct virt_root_hub rh; //private data of the virtual root hub + int loop_usage; // URBs using bandwidth reclamation } uhci_t, *puhci_t; diff --git a/drivers/usb/usb_storage.c b/drivers/usb/usb_storage.c index 0ebb1e413925..ecff62a7d703 100644 --- a/drivers/usb/usb_storage.c +++ b/drivers/usb/usb_storage.c @@ -39,6 +39,14 @@ #include "usb.h" #include "usb_storage.h" +/* + * This is the size of the structure Scsi_Host_Template. We create + * an instance of this structure in this file and this is a check + * to see if this structure may have changed within the SCSI module. + * This is by no means foolproof, but it does help us some. + */ +#define SCSI_HOST_TEMPLATE_SIZE (104) + /* direction table -- this indicates the direction of the data * transfer for each command code -- a 1 indicates input */ @@ -1327,6 +1335,7 @@ static Scsi_Host_Template my_host_template = { NULL, /* reset */ NULL, /* slave_attach */ NULL, /* bios_param */ + NULL, /* select_queue_depths */ 1, /* can_queue */ -1, /* this_id */ SG_ALL, /* sg_tablesize */ @@ -1811,10 +1820,18 @@ static void storage_disconnect(struct usb_device *dev, void *ptr) * Initialization and registration ***********************************************************************/ -int usb_stor_init(void) +static int __init usb_stor_init(void) { // MOD_INC_USE_COUNT; + if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) { + printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ; + printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n", + SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ; + + return -1 ; + } + /* register the driver, return -1 if error */ if (usb_register(&storage_driver) < 0) return -1; @@ -1823,15 +1840,10 @@ int usb_stor_init(void) return 0; } -#ifdef MODULE -int init_module(void) +static void __exit usb_stor_exit(void) { - /* MDD: Perhaps we should register the host here */ - return usb_stor_init(); + usb_deregister(&storage_driver) ; } -void cleanup_module(void) -{ - usb_deregister(&storage_driver); -} -#endif +module_init(usb_stor_init) ; +module_exit(usb_stor_exit) ; diff --git a/drivers/video/bwtwofb.c b/drivers/video/bwtwofb.c index f40b873bab46..ebb5d5e56297 100644 --- a/drivers/video/bwtwofb.c +++ b/drivers/video/bwtwofb.c @@ -1,4 +1,4 @@ -/* $Id: bwtwofb.c,v 1.12 2000/01/21 03:57:05 anton Exp $ +/* $Id: bwtwofb.c,v 1.13 2000/02/14 02:50:25 davem Exp $ * bwtwofb.c: BWtwo frame buffer driver * * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) diff --git a/drivers/video/cgsixfb.c b/drivers/video/cgsixfb.c index f9a78e531038..2fd457eb6afa 100644 --- a/drivers/video/cgsixfb.c +++ b/drivers/video/cgsixfb.c @@ -1,4 +1,4 @@ -/* $Id: cgsixfb.c,v 1.21 1999/11/19 09:56:57 davem Exp $ +/* $Id: cgsixfb.c,v 1.22 2000/02/14 08:44:26 jj Exp $ * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver * * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) @@ -491,7 +491,7 @@ static void cg6_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int inde int i; spin_lock_irqsave(&fb->lock, flags); - bt->addr = index << 24; + sbus_writel(index << 24, &bt->addr); for (i = index; count--; i++){ sbus_writel(fb->color_map CM(i,0) << 24, &bt->color_map); diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c index 946270f45fce..8fbff9bc41f6 100644 --- a/drivers/video/matroxfb.c +++ b/drivers/video/matroxfb.c @@ -90,11 +90,6 @@ /* Debug register calls, too? */ #undef MATROXFB_DEBUG_REG -/* Log reentrancy attempts - you must have printstate() patch applied */ -#undef MATROXFB_DEBUG_REENTER -/* you must define DEBUG_REENTER to get debugged CONSOLEBH... */ -#undef MATROXFB_DEBUG_CONSOLEBH - #include #include #include @@ -1082,46 +1077,6 @@ static int default_cmode = CMODE_NVRAM; #define isMilleniumII(x) (0) #endif -#ifdef MATROXFB_DEBUG_REENTER -static atomic_t guard_counter = ATOMIC_INIT(1); -static atomic_t guard_printing = ATOMIC_INIT(1); -static void guard_start(void) { - if (atomic_dec_and_test(&guard_counter)) { /* first level */ - if (!(bh_mask & (1 << CONSOLE_BH))) /* and CONSOLE_BH disabled */ - return; /* is OK */ - /* otherwise it is first level with CONSOLE_BH enabled - - - if we are __sti or SMP, reentering from console_bh possible */ - atomic_dec(&guard_printing); /* disable reentrancy warning */ - printk(KERN_DEBUG "matroxfb entered without CONSOLE_BH disabled\n"); -#ifdef printstate - printstate(); -#endif - atomic_inc(&guard_printing); - return; - } - /* real reentering... You should be already warned by code above */ - if (atomic_dec_and_test(&guard_printing)) { -#ifdef printstate - printstate(); -#endif - } - atomic_inc(&guard_printing); -} - -static inline void guard_end(void) { - atomic_inc(&guard_counter); -} - -#define CRITBEGIN guard_start(); -#define CRITEND guard_end(); - -#else - -#define CRITBEGIN -#define CRITEND - -#endif - #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l)) static void matrox_cfbX_init(WPMINFO struct display* p) { @@ -1184,8 +1139,6 @@ static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, DBG("matrox_cfbX_bmove") - CRITBEGIN - sx *= fontwidth(p); dx *= fontwidth(p); width *= fontwidth(p); @@ -1216,8 +1169,6 @@ static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); mga_ydstlen(dy, height); WaitTillIdle(); - - CRITEND } #ifdef FBCON_HAS_CFB4 @@ -1229,8 +1180,6 @@ static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, DBG("matrox_cfb4_bmove") - CRITBEGIN - if ((sx | dx | width) & fontwidth(p) & 1) { fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width); return; @@ -1270,8 +1219,6 @@ static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, mga_outl(M_YDST, dy*pixx >> 5); mga_outl(M_LEN | M_EXEC, height); WaitTillIdle(); - - CRITEND } #endif @@ -1280,16 +1227,12 @@ static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int he DBG("matroxfb_accel_clear") - CRITBEGIN - mga_fifo(5); mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE); mga_outl(M_FCOL, color); mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); mga_ydstlen(sy, height); WaitTillIdle(); - - CRITEND } static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) { @@ -1308,8 +1251,6 @@ static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, i DBG("matrox_cfb4_clear") - CRITBEGIN - whattodo = 0; bgx = attr_bgcol_ec(p, conp); bgx |= bgx << 4; @@ -1361,8 +1302,6 @@ static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, i } } } - - CRITEND } #endif @@ -1410,8 +1349,6 @@ static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p yy *= fontheight(p); xx *= fontwidth(p); - CRITBEGIN - mga_fifo(8); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); @@ -1423,8 +1360,6 @@ static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); mga_ydstlen(yy, fontheight(p)); WaitTillIdle(); - - CRITEND } static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { @@ -1437,8 +1372,6 @@ static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, in yy *= fontheight(p); xx *= fontwidth(p); - CRITBEGIN - #ifdef __BIG_ENDIAN WaitTillIdle(); mga_outl(M_OPMODE, M_OPMODE_8BPP); @@ -1504,7 +1437,6 @@ static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, in #ifdef __BIG_ENDIAN mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); #endif - CRITEND } #ifdef FBCON_HAS_CFB8 @@ -1560,8 +1492,6 @@ static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* xx *= fontwidth(p); charcell = fontwidth(p) * fontheight(p); - CRITBEGIN - mga_fifo(3); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); mga_outl(M_FCOL, fgx); @@ -1577,8 +1507,6 @@ static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* xx += fontwidth(p); } WaitTillIdle(); - - CRITEND } static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { @@ -1613,8 +1541,6 @@ static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, c easy = 0; } - CRITBEGIN - #ifdef __BIG_ENDIAN WaitTillIdle(); mga_outl(M_OPMODE, M_OPMODE_8BPP); @@ -1676,7 +1602,6 @@ static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, c #ifdef __BIG_ENDIAN mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); #endif - CRITEND } #ifdef FBCON_HAS_CFB8 @@ -1739,8 +1664,6 @@ static void matrox_cfb4_revc(struct display* p, int xx, int yy) { xx |= (xx + fontwidth(p)) << 16; xx >>= 1; - CRITBEGIN - mga_fifo(5); mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); mga_outl(M_FCOL, 0xFFFFFFFF); @@ -1748,8 +1671,6 @@ static void matrox_cfb4_revc(struct display* p, int xx, int yy) { mga_outl(M_YDST, yy * p->var.xres_virtual >> 6); mga_outl(M_LEN | M_EXEC, fontheight(p)); WaitTillIdle(); - - CRITEND } #endif @@ -1762,16 +1683,12 @@ static void matrox_cfb8_revc(struct display* p, int xx, int yy) { yy *= fontheight(p); xx *= fontwidth(p); - CRITBEGIN - mga_fifo(4); mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); mga_outl(M_FCOL, 0x0F0F0F0F); mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); mga_ydstlen(yy, fontheight(p)); WaitTillIdle(); - - CRITEND } #endif @@ -1783,16 +1700,12 @@ static void matrox_cfbX_revc(struct display* p, int xx, int yy) { yy *= fontheight(p); xx *= fontwidth(p); - CRITBEGIN - mga_fifo(4); mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); mga_outl(M_FCOL, 0xFFFFFFFF); mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); mga_ydstlen(yy, fontheight(p)); WaitTillIdle(); - - CRITEND } static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) { @@ -2034,8 +1947,6 @@ static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) { cursorbase = ACCESS_FBINFO(video.vbase); h = ACCESS_FBINFO(features.DAC1064.cursorimage); - CRITBEGIN - #ifdef __BIG_ENDIAN WaitTillIdle(); mga_outl(M_OPMODE, M_OPMODE_32BPP); @@ -2066,8 +1977,6 @@ static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) { #ifdef __BIG_ENDIAN mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); #endif - - CRITEND } static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) { @@ -2138,8 +2047,6 @@ static int matroxfb_fastfont_tryset(WPMINFO struct display* p) { if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size)) return 0; - CRITBEGIN - mga_outl(M_OPMODE, M_OPMODE_8BPP); if (width <= 8) { if (width == 8) @@ -2231,8 +2138,6 @@ static int matroxfb_fastfont_tryset(WPMINFO struct display* p) { } mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); - CRITEND - return 1; } @@ -2250,8 +2155,6 @@ static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx, unsigned int step; MINFO_FROM_DISP(p); - CRITBEGIN - step = ACCESS_FBINFO(devflags.textstep); srcoff = (sy * p->next_line) + (sx * step); dstoff = (dy * p->next_line) + (dx * step); @@ -2279,7 +2182,6 @@ static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx, height--; } } - CRITEND } static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx, @@ -2293,8 +2195,6 @@ static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, i offs = sy * p->next_line + sx * step; val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8)); - CRITBEGIN - while (height > 0) { int i; for (i = width; i > 0; offs += step, i--) @@ -2302,7 +2202,6 @@ static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, i offs += p->next_line - width * step; height--; } - CRITEND } static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { @@ -2316,11 +2215,7 @@ static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8); if (chr & 0x10000) chr |= 0x08; - CRITBEGIN - mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr)); - - CRITEND } static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, @@ -2334,16 +2229,12 @@ static void matrox_text_putcs(struct vc_data* conp, struct display* p, const uns offs = yy * p->next_line + xx * step; attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4); - CRITBEGIN - while (count-- > 0) { unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8; if (chr & 0x10000) chr ^= 0x10008; mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr)); offs += step; } - - CRITEND } static void matrox_text_revc(struct display* p, int xx, int yy) { @@ -2354,11 +2245,7 @@ static void matrox_text_revc(struct display* p, int xx, int yy) { step = ACCESS_FBINFO(devflags.textstep); offs = yy * p->next_line + xx * step + 1; - CRITBEGIN - mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77); - - CRITEND } static int matrox_text_loadfont(WPMINFO struct display* p) { @@ -2377,8 +2264,6 @@ static int matrox_text_loadfont(WPMINFO struct display* p) { i = 2; font = (u_int8_t*)p->fontdata; - CRITBEGIN - mga_setr(M_SEQ_INDEX, 0x02, 0x04); while (fsize--) { int l; @@ -2392,8 +2277,6 @@ static int matrox_text_loadfont(WPMINFO struct display* p) { } mga_setr(M_SEQ_INDEX, 0x02, 0x03); - CRITEND - return 1; } @@ -2404,12 +2287,8 @@ static void matrox_text_createcursor(WPMINFO struct display* p) { matroxfb_createcursorshape(PMINFO p, 0); - CRITBEGIN - mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1); - - CRITEND } static void matrox_text_cursor(struct display* p, int mode, int x, int y) { @@ -2422,12 +2301,8 @@ static void matrox_text_cursor(struct display* p, int mode, int x, int y) { if (mode == CM_ERASE) { if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { - CRITBEGIN - mga_setr(M_CRTC_INDEX, 0x0A, 0x20); - CRITEND - ACCESS_FBINFO(cursor.state) = CM_ERASE; } return; @@ -2440,15 +2315,11 @@ static void matrox_text_cursor(struct display* p, int mode, int x, int y) { ACCESS_FBINFO(cursor.y) = y; pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x; - CRITBEGIN - mga_setr(M_CRTC_INDEX, 0x0F, pos); mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8); mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); - CRITEND - ACCESS_FBINFO(cursor.state) = CM_DRAW; } @@ -2717,8 +2588,6 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21; #endif - CRITBEGIN - mga_setr(M_CRTC_INDEX, 0x0D, p0); mga_setr(M_CRTC_INDEX, 0x0C, p1); #ifdef CONFIG_FB_MATROX_32MB @@ -2726,8 +2595,6 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { mga_setr(M_EXTVGA_INDEX, 0x08, p3); #endif mga_setr(M_EXTVGA_INDEX, 0x00, p2); - - CRITEND } /* @@ -3480,8 +3347,6 @@ static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const st DBG("DAC1064_restore_1") - CRITBEGIN - outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); @@ -3491,8 +3356,6 @@ static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const st for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]); } - - CRITEND } static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) { @@ -3501,17 +3364,13 @@ static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const st DBG("DAC1064_restore_2") - CRITBEGIN - for (i = 0; i < 3; i++) outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]); for (tmout = 500000; tmout; tmout--) { if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40) break; udelay(10); - }; - - CRITEND + } if (!tmout) printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); @@ -4306,8 +4165,6 @@ static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_st dprintk("%02X:", hw->ATTR[i]); dprintk("\n"); - CRITBEGIN - mga_inb(M_ATTR_RESET); mga_outb(M_ATTR_INDEX, 0); mga_outb(M_MISC_REG, hw->MiscOutReg); @@ -4329,8 +4186,6 @@ static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_st mga_outb(M_DAC_VAL, hw->DACpal[i]); mga_inb(M_ATTR_RESET); mga_outb(M_ATTR_INDEX, 0x20); - - CRITEND } static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -4434,14 +4289,10 @@ static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw DBG("MGA1064_restore") - CRITBEGIN - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); mga_outb(M_IEN, 0x00); mga_outb(M_CACHEFLUSH, 0x00); - CRITEND - DAC1064_restore_1(PMINFO hw, oldhw); vgaHWrestore(PMINFO hw, oldhw); for (i = 0; i < 6; i++) @@ -4456,10 +4307,7 @@ static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw DBG("MGAG100_restore") - CRITBEGIN - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - CRITEND DAC1064_restore_1(PMINFO hw, oldhw); vgaHWrestore(PMINFO hw, oldhw); @@ -4484,16 +4332,10 @@ static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_ dprintk("%02X:", hw->CRTCEXT[i]); dprintk("\n"); - CRITBEGIN - pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); - CRITEND - vgaHWrestore(PMINFO hw, oldhw); - CRITBEGIN - for (i = 0; i < 6; i++) mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); @@ -4511,13 +4353,11 @@ static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_ oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA); oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA); } - CRITEND if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) { /* agrhh... setting up PLL is very slow on Millenium... */ /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */ /* Maybe even we should call schedule() ? */ - CRITBEGIN outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]); outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A); outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0); @@ -4536,30 +4376,24 @@ static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_ udelay(10); } - CRITEND - if (!tmout) printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n"); else dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout); - CRITBEGIN } outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]); outTi3026(PMINFO TVP3026_XPLLADDR, 0x00); for (i = 3; i < 6; i++) outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]); - CRITEND if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) { int tmout; - CRITBEGIN outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F); for (tmout = 500000; tmout; --tmout) { if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) break; udelay(10); } - CRITEND if (!tmout) printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n"); else @@ -4954,15 +4788,11 @@ static void matroxfb_blank(int blank, struct fb_info *info) default: seq = 0x00; crtc = 0x00; break; } - CRITBEGIN - mga_outb(M_SEQ_INDEX, 1); mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); mga_outb(M_EXTVGA_INDEX, 1); mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); - CRITEND - #undef minfo } diff --git a/fs/bfs/file.c b/fs/bfs/file.c index c3d5a890549b..fe90391f1b72 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -19,9 +19,9 @@ #endif static struct file_operations bfs_file_operations = { - read: generic_file_read, - write: generic_file_write, - mmap: generic_file_mmap, + read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap, }; static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev) @@ -77,7 +77,8 @@ static int bfs_get_block(struct inode * inode, long block, /* if the file is not empty and the requested block is within the range of blocks allocated for this file, we can grant it */ if (inode->i_size && phys <= inode->iu_eblock) { - dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", create, block, phys); + dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", + create, block, phys); bh_result->b_dev = inode->i_dev; bh_result->b_blocknr = phys; bh_result->b_state |= (1UL << BH_Mapped); @@ -90,7 +91,8 @@ static int bfs_get_block(struct inode * inode, long block, /* if the last data block for this file is the last allocated block, we can extend the file trivially, without moving it anywhere */ if (inode->iu_eblock == s->su_lf_eblk) { - dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", create, block, phys); + dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", + create, block, phys); bh_result->b_dev = inode->i_dev; bh_result->b_blocknr = phys; bh_result->b_state |= (1UL << BH_Mapped); @@ -104,9 +106,10 @@ static int bfs_get_block(struct inode * inode, long block, /* Ok, we have to move this entire file to the next free block */ next_free_block = s->su_lf_eblk + 1; if (inode->iu_sblock) { /* if data starts on block 0 then there is no data */ - err = bfs_move_blocks(inode->i_dev, inode->iu_sblock, inode->iu_eblock, next_free_block); + err = bfs_move_blocks(inode->i_dev, inode->iu_sblock, + inode->iu_eblock, next_free_block); if (err) { - dprintf("failed to move ino=%08lx -> possible fs corruption\n", inode->i_ino); + dprintf("failed to move ino=%08lx -> fs corruption\n", inode->i_ino); goto out; } } else @@ -126,26 +129,30 @@ out: static int bfs_writepage(struct dentry *dentry, struct page *page) { - return block_write_full_page(page,bfs_get_block); + return block_write_full_page(page, bfs_get_block); } + static int bfs_readpage(struct dentry *dentry, struct page *page) { - return block_read_full_page(page,bfs_get_block); + return block_read_full_page(page, bfs_get_block); } + static int bfs_prepare_write(struct page *page, unsigned from, unsigned to) { - return block_prepare_write(page,from,to,bfs_get_block); + return block_prepare_write(page, from, to, bfs_get_block); } + static int bfs_bmap(struct address_space *mapping, long block) { - return generic_block_bmap(mapping,block,bfs_get_block); + return generic_block_bmap(mapping, block, bfs_get_block); } + struct address_space_operations bfs_aops = { - readpage: bfs_readpage, - writepage: bfs_writepage, - prepare_write: bfs_prepare_write, - commit_write: generic_commit_write, - bmap: bfs_bmap + readpage: bfs_readpage, + writepage: bfs_writepage, + prepare_write: bfs_prepare_write, + commit_write: generic_commit_write, + bmap: bfs_bmap }; struct inode_operations bfs_file_inops = { diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 670b85fc9d07..0fd42178c72b 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -269,14 +269,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; vaddr = eppnt->p_vaddr; - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) elf_type |= MAP_FIXED; -#ifdef __sparc__ - } else { - load_addr = get_unmapped_area(0, eppnt->p_filesz + - ELF_PAGEOFFSET(vaddr)); -#endif - } map_addr = do_mmap(file, load_addr + ELF_PAGESTART(vaddr), diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h index 17c61130aa9c..d1dde606e7e4 100644 --- a/include/asm-alpha/page.h +++ b/include/asm-alpha/page.h @@ -109,6 +109,20 @@ typedef unsigned long pgprot_t; #define BUG() __asm__ __volatile__("call_pal 129 # bugchk") #define PAGE_BUG(page) BUG() +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* !ASSEMBLY */ /* to align the pointer to the (next) page boundary */ diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h index f46fadbb8a58..e33597ff613a 100644 --- a/include/asm-arm/page.h +++ b/include/asm-arm/page.h @@ -65,6 +65,20 @@ extern void __bug(const char *file, int line, void *data); #define BUG() __bug(__FILE__, __LINE__, NULL) #define PAGE_BUG(page) __bug(__FILE__, __LINE__, page) +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* !__ASSEMBLY__ */ #include diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h index b941776f53d0..04a41eb5807a 100644 --- a/include/asm-i386/floppy.h +++ b/include/asm-i386/floppy.h @@ -190,7 +190,7 @@ static int fd_request_irq(void) static unsigned long dma_mem_alloc(unsigned long size) { - return __get_dma_pages(GFP_KERNEL,__get_order(size)); + return __get_dma_pages(GFP_KERNEL,get_order(size)); } @@ -207,7 +207,7 @@ static void _fd_dma_mem_free(unsigned long addr, unsigned long size) if((unsigned int) addr >= (unsigned int) high_memory) return vfree((void *)addr); else - free_pages(addr, __get_order(size)); + free_pages(addr, get_order(size)); } #define fd_dma_mem_free(addr, size) _fd_dma_mem_free(addr, size) diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index 67855d1639c0..9e159523a8ae 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -94,6 +94,20 @@ extern int console_loglevel; BUG(); \ } while (0) +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* __ASSEMBLY__ */ #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index db9a60c35fa2..f0d1b00bfcf8 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -130,7 +130,8 @@ extern unsigned long empty_zero_page[1024]; * area for the same reason. ;) */ #define VMALLOC_OFFSET (8*1024*1024) -#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \ + ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END (FIXADDR_START) diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index 64d04459913b..53eb9f963080 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h @@ -127,6 +127,18 @@ typedef union ia64_va { #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) #define PAGE_BUG(page) do { BUG(); } while (0) +extern __inline__ int get_order(unsigned long size) +{ + double d = size - 1; + long order; + + __asm__ ("getf.exp %0=%1" : "=r"(order) : "f"(d)); + order = order - PAGE_SHIFT - 0xffff + 1; + if (order < 0) + order = 0; + return order; +} + #endif /* !ASSEMBLY */ #define PAGE_OFFSET 0xe000000000000000 diff --git a/include/asm-m68k/page.h b/include/asm-m68k/page.h index 23dd731c8825..117abf25d3a7 100644 --- a/include/asm-m68k/page.h +++ b/include/asm-m68k/page.h @@ -97,6 +97,20 @@ typedef struct { unsigned long pgprot; } pgprot_t; /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* !__ASSEMBLY__ */ #include diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index aa740dcd03fc..4e087eb9fea6 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -65,6 +65,20 @@ typedef unsigned long pgprot_t; #endif /* !defined (STRICT_MM_TYPECHECKS) */ +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* _LANGUAGE_ASSEMBLY */ /* to align the pointer to the (next) page boundary */ diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index 8c8b8895480e..1be8ddfa50f2 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -113,6 +113,21 @@ static inline void* ___va(unsigned long p) #define MAP_PAGE_RESERVED (1<<15) extern unsigned long get_zero_page_fast(void); + +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ #endif /* _PPC_PAGE_H */ diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 6ab7eb70d2a6..303b2aa05a28 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -69,6 +69,8 @@ extern inline void flush_tlb_pgtables(struct mm_struct *mm, extern void flush_icache_range(unsigned long, unsigned long); extern void __flush_page_to_ram(unsigned long page_va); #define flush_page_to_ram(page) __flush_page_to_ram(page_address(page)) +extern void __flush_icache_page(unsigned long page_va); +#define flush_icache_page(vma, page) __flush_icache_page(page_address(page)) extern unsigned long va_to_phys(unsigned long address); extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address); diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 867c071229d2..24a374d4b8f4 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -76,6 +76,21 @@ extern int console_loglevel; #define PAGE_BUG(page) do { \ BUG(); \ } while (0) + +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif #endif /* __KERNEL__ */ diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h index 344640811ffc..1665806b57bc 100644 --- a/include/asm-sparc/page.h +++ b/include/asm-sparc/page.h @@ -129,6 +129,20 @@ BTFIXUPDEF_SETHI(sparc_unmapped_base) #define TASK_UNMAPPED_BASE BTFIXUP_SETHI(sparc_unmapped_base) +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #else /* !(__ASSEMBLY__) */ #define __pgprot(x) (x) diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h index 8829d323cc24..7faed17487f1 100644 --- a/include/asm-sparc/pgtable.h +++ b/include/asm-sparc/pgtable.h @@ -448,4 +448,7 @@ extern int io_remap_page_range(unsigned long from, unsigned long to, #endif /* !(__ASSEMBLY__) */ +/* We provide our own get_unmapped_area to cope with VA holes for userland */ +#define HAVE_ARCH_UNMAPPED_AREA + #endif /* !(_SPARC_PGTABLE_H) */ diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index dabfea993fea..3191b64fca6b 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h @@ -126,6 +126,20 @@ struct sparc_phys_banks { extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; +/* Pure 2^n version of get_order */ +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* !(__ASSEMBLY__) */ #endif /* !(__KERNEL__) */ diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index 878b99142c6f..7a3403150401 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.118 1999/12/21 21:24:35 davem Exp $ +/* $Id: pgtable.h,v 1.119 2000/02/14 02:53:44 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -280,17 +280,19 @@ extern pgd_t swapper_pg_dir[1]; * table. * 4) Splat. */ -extern void flush_icache_page(unsigned long phys_page); +extern void __flush_icache_page(unsigned long phys_page); #define update_mmu_cache(__vma, __address, _pte) \ do { \ unsigned short __flags = ((__vma)->vm_flags); \ if ((__flags & VM_EXEC) != 0 && \ ((pte_val(_pte) & (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED)) == \ (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED))) { \ - flush_icache_page(pte_pagenr(_pte) << PAGE_SHIFT); \ + __flush_icache_page(pte_pagenr(_pte) << PAGE_SHIFT); \ } \ } while(0) +#define flush_icache_page(vma, pg) do { } while(0) + /* Make a non-present pseudo-TTE. */ extern inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space) { @@ -351,4 +353,7 @@ extern int io_remap_page_range(unsigned long from, unsigned long offset, #endif /* !(__ASSEMBLY__) */ +/* We provide our own get_unmapped_area to cope with VA holes for userland */ +#define HAVE_ARCH_UNMAPPED_AREA + #endif /* !(_SPARC64_PGTABLE_H) */ diff --git a/include/linux/console.h b/include/linux/console.h index 1f4188a785a3..f8da31cbd0d7 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -16,6 +16,7 @@ #include #include +#include struct vc_data; struct console_font_op; @@ -90,6 +91,8 @@ extern struct console_cmdline console_list[MAX_CMDLINECONSOLES]; #define CON_CONSDEV (2) /* Last on the command line */ #define CON_ENABLED (4) +extern spinlock_t console_lock; + struct console { char name[8]; diff --git a/include/linux/hysdn_if.h b/include/linux/hysdn_if.h new file mode 100644 index 000000000000..68cc72078e10 --- /dev/null +++ b/include/linux/hysdn_if.h @@ -0,0 +1,49 @@ +/* $Id: hysdn_if.h,v 1.1 2000/02/10 19:47:50 werner Exp $ + + * Linux driver for HYSDN cards, ioctl definitions shared by hynetmgr and driver. + * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH + * + * Copyright 1999 by Werner Cornelius (werner@titro.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: hysdn_if.h,v $ + * Revision 1.1 2000/02/10 19:47:50 werner + * + * Initial release + * + * + */ + +/****************/ +/* error values */ +/****************/ +#define ERR_NONE 0 /* no error occured */ +#define ERR_ALREADY_BOOT 1000 /* we are already booting */ +#define EPOF_BAD_MAGIC 1001 /* bad magic in POF header */ +#define ERR_BOARD_DPRAM 1002 /* board DPRAM failed */ +#define EPOF_INTERNAL 1003 /* internal POF handler error */ +#define EPOF_BAD_IMG_SIZE 1004 /* POF boot image size invalid */ +#define ERR_BOOTIMG_FAIL 1005 /* 1. stage boot image did not start */ +#define ERR_BOOTSEQ_FAIL 1006 /* 2. stage boot seq handshake timeout */ +#define ERR_POF_TIMEOUT 1007 /* timeout waiting for card pof ready */ +#define ERR_NOT_BOOTED 1008 /* operation only allowed when booted */ +#define ERR_CONF_LONG 1009 /* conf line is to long */ +#define ERR_INV_CHAN 1010 /* invalid channel number */ +#define ERR_ASYNC_TIME 1011 /* timeout sending async data */ + + + + diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5729020695f5..8e33913d39f7 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -23,7 +23,6 @@ struct irqaction { enum { TIMER_BH = 0, - CONSOLE_BH, TQUEUE_BH, DIGI_BH, SERIAL_BH, @@ -47,8 +46,8 @@ enum { /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high frequency threaded job scheduling. For almost all the purposes - tasklets are more than enough. F.e. KEYBOARD_BH, CONSOLE_BH, all serial - device BHs et al. are converted to tasklets, not to softirqs. + tasklets are more than enough. F.e. all serial device BHs et + al. should be converted to tasklets, not to softirqs. */ enum @@ -243,24 +242,6 @@ extern __inline__ void mark_bh(int nr) tasklet_hi_schedule(bh_task_vec+nr); } -extern __inline__ void disable_bh_nosync(int nr) -{ - tasklet_disable_nosync(bh_task_vec+nr); -} - -extern __inline__ void disable_bh(int nr) -{ - tasklet_disable_nosync(bh_task_vec+nr); - if (!in_interrupt()) - tasklet_unlock_wait(bh_task_vec+nr); -} - -extern __inline__ void enable_bh(int nr) -{ - tasklet_enable(bh_task_vec+nr); -} - - extern void init_bh(int nr, void (*routine)(void)); extern void remove_bh(int nr); diff --git a/include/linux/isdn.h b/include/linux/isdn.h index b73358b68240..bf9b867d3044 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.90 2000/02/06 21:50:00 detabc Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,52 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.90 2000/02/06 21:50:00 detabc + * add rewriting of socket's and frame's saddr for udp-ipv4 dynip-connections. + * Include checksum-recompute of ip- and udp-header's. + * + * Revision 1.89 2000/02/05 22:11:33 detabc + * Add rewriting of socket's and frame's saddr adressfield for + * dynip-connections. Only for tcp/ipv4 and switchable per interface. + * Include checksum-recompute of ip- and tcp-header's. + * + * 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 +379,12 @@ #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 +#undef CONFIG_ISDN_WITH_ABC_IPV4_RW_SOCKADDR +#undef CONFIG_ISDN_WITH_ABC_IPV4_RWUDP_SOCKADDR /* New ioctl-codes */ @@ -359,6 +411,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) @@ -922,6 +975,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/kbd_kern.h b/include/linux/kbd_kern.h index 56dd41faccfa..ef922b03977a 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -69,6 +69,8 @@ extern int kbd_init(void); extern unsigned char getledstate(void); extern void setledstate(struct kbd_struct *kbd, unsigned int led); +extern struct tasklet_struct console_tasklet; + extern int do_poke_blanked_console; extern void (*kbd_ledfunc)(unsigned int led); @@ -76,13 +78,13 @@ extern void (*kbd_ledfunc)(unsigned int led); extern inline void show_console(void) { do_poke_blanked_console = 1; - mark_bh(CONSOLE_BH); + tasklet_schedule(&console_tasklet); } extern inline void set_console(int nr) { want_console = nr; - mark_bh(CONSOLE_BH); + tasklet_schedule(&console_tasklet); } extern inline void set_leds(void) @@ -162,7 +164,7 @@ extern task_queue con_task_queue; extern inline void con_schedule_flip(struct tty_struct *t) { queue_task(&t->flip.tqueue, &con_task_queue); - mark_bh(CONSOLE_BH); + tasklet_schedule(&console_tasklet); } #endif diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h index 5778d2ebb97f..b10f304a5ac6 100644 --- a/include/linux/kernelcapi.h +++ b/include/linux/kernelcapi.h @@ -1,11 +1,15 @@ /* - * $Id: kernelcapi.h,v 1.4 1999/09/10 17:24:19 calle Exp $ + * $Id: kernelcapi.h,v 1.5 2000/01/28 16:45:40 calle Exp $ * * Kernel CAPI 2.0 Interface for Linux * * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kernelcapi.h,v $ + * Revision 1.5 2000/01/28 16:45:40 calle + * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard), + * will search named driver and call the add_card function if one exist. + * * Revision 1.4 1999/09/10 17:24:19 calle * Changes for proposed standard for CAPI2.0: * - AK148 "Linux Exention" @@ -57,8 +61,17 @@ typedef struct kcapi_flagdef { int flag; } kcapi_flagdef; +typedef struct kcapi_carddef { + char driver[32]; + unsigned int port; + unsigned irq; + unsigned int membase; + int cardnr; +} kcapi_carddef; + /* new ioctls >= 10 */ #define KCAPI_CMD_TRACE 10 +#define KCAPI_CMD_ADDCARD 11 /* add card to named driver */ /* * flag > 2 => trace also data diff --git a/include/linux/parport.h b/include/linux/parport.h index 8a1e97501633..f228dc42e254 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -345,11 +345,11 @@ extern int parport_register_driver (struct parport_driver *); extern void parport_unregister_driver (struct parport_driver *); /* parport_register_device declares that a device is connected to a - port, and tells the kernel all it needs to know. pf is the - preemption function (may be NULL for no callback) kf is the wake-up - function (may be NULL for no callback) irq_func is the interrupt - handler (may be NULL for no interrupts) handle is a user pointer - that gets handed to callback functions. */ + port, and tells the kernel all it needs to know. + - pf is the preemption function (may be NULL for no callback) + - kf is the wake-up function (may be NULL for no callback) + - irq_func is the interrupt handler (may be NULL for no interrupts) + - handle is a user pointer that gets handed to callback functions. */ struct pardevice *parport_register_device(struct parport *port, const char *name, int (*pf)(void *), void (*kf)(void *), diff --git a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h index 904fba0b8275..e5c3280540dc 100644 --- a/include/pcmcia/ciscode.h +++ b/include/pcmcia/ciscode.h @@ -1,5 +1,5 @@ /* - * ciscode.h 1.39 1999/10/25 20:23:17 + * ciscode.h 1.40 2000/02/01 19:06:40 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -91,6 +91,8 @@ #define PRODID_OSITECH_JACK_336 0x0007 #define PRODID_OSITECH_SEVEN 0x0008 +#define MANFID_PIONEER 0x000b + #define MANFID_PSION 0x016c #define MANFID_QUATECH 0x0137 diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index fb3819ba81a1..b53657fadb7c 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -1,5 +1,5 @@ /* - * ss.h 1.25 1999/10/25 20:23:17 + * ss.h 1.26 2000/02/04 20:35:21 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -45,6 +45,7 @@ #define SS_CARDBUS 0x0800 #define SS_3VCARD 0x1000 #define SS_XVCARD 0x2000 +#define SS_PENDING 0x4000 /* for InquireSocket */ typedef struct socket_cap_t { diff --git a/include/pcmcia/version.h b/include/pcmcia/version.h index 4606b40b3749..4f6ffc70221c 100644 --- a/include/pcmcia/version.h +++ b/include/pcmcia/version.h @@ -1,4 +1,4 @@ -/* version.h 1.81 1999/12/23 21:37:32 (David Hinds) */ +/* version.h 1.83 2000/02/03 02:16:14 (David Hinds) */ -#define CS_RELEASE "3.1.9" -#define CS_RELEASE_CODE 0x3109 +#define CS_RELEASE "3.1.11" +#define CS_RELEASE_CODE 0x310b diff --git a/kernel/printk.c b/kernel/printk.c index 330ce3efebc4..457d36aa2e7a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -318,14 +318,14 @@ void console_print(const char *s) unsigned long flags; int len = strlen(s); - spin_lock_irqsave(&console_lock,flags); + spin_lock_irqsave(&console_lock, flags); c = console_drivers; while(c) { if ((c->flags & CON_ENABLED) && c->write) c->write(c, s, len); c = c->next; } - spin_unlock_irqrestore(&console_lock,flags); + spin_unlock_irqrestore(&console_lock, flags); } void unblank_console(void) @@ -333,14 +333,14 @@ void unblank_console(void) struct console *c; unsigned long flags; - spin_lock_irqsave(&console_lock,flags); + spin_lock_irqsave(&console_lock, flags); c = console_drivers; while(c) { if ((c->flags & CON_ENABLED) && c->unblank) c->unblank(); c = c->next; } - spin_unlock_irqrestore(&console_lock,flags); + spin_unlock_irqrestore(&console_lock, flags); } /* @@ -402,7 +402,7 @@ void register_console(struct console * console) * Put this console in the list - keep the * preferred driver at the head of the list. */ - spin_lock_irqsave(&console_lock,flags); + spin_lock_irqsave(&console_lock, flags); if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { console->next = console_drivers; console_drivers = console; @@ -445,7 +445,7 @@ void register_console(struct console * console) j = 0; } done: - spin_unlock_irqrestore(&console_lock,flags); + spin_unlock_irqrestore(&console_lock, flags); } @@ -455,7 +455,7 @@ int unregister_console(struct console * console) unsigned long flags; int res = 1; - spin_lock_irqsave(&console_lock,flags); + spin_lock_irqsave(&console_lock, flags); if (console_drivers == console) { console_drivers=console->next; res = 0; @@ -471,7 +471,7 @@ int unregister_console(struct console * console) } } - spin_unlock_irqrestore(&console_lock,flags); + spin_unlock_irqrestore(&console_lock, flags); return res; } diff --git a/mm/filemap.c b/mm/filemap.c index eac9633352a6..5d216c170742 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -479,8 +479,8 @@ static inline void __add_to_page_cache(struct page * page, struct page *alias; unsigned long flags; - flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced)); - page->flags = flags | (1 << PG_locked); + flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error)); + page->flags = flags | (1 << PG_locked) | (1 << PG_referenced); get_page(page); page->index = offset; add_page_to_inode_queue(mapping, page); diff --git a/mm/mmap.c b/mm/mmap.c index cab60332ae79..dfb02a95dba1 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -347,6 +347,7 @@ free_vma: * For mmap() without MAP_FIXED and shmat() with addr=0. * Return value 0 means ENOMEM. */ +#ifndef HAVE_ARCH_UNMAPPED_AREA unsigned long get_unmapped_area(unsigned long addr, unsigned long len) { struct vm_area_struct * vmm; @@ -366,6 +367,7 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len) addr = vmm->vm_end; } } +#endif #define vm_avl_empty (struct vm_area_struct *) NULL @@ -580,7 +582,7 @@ static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev, unsigned long start, unsigned long end) { unsigned long first = start & PGDIR_MASK; - unsigned long last = (end + PGDIR_SIZE - 1) & PGDIR_MASK; + unsigned long last = end + PGDIR_SIZE - 1; unsigned long start_index, end_index; if (!prev) { @@ -615,8 +617,10 @@ no_mmaps: */ start_index = pgd_index(first); end_index = pgd_index(last); - if (end_index > start_index) + if (end_index > start_index) { clear_page_tables(mm, start_index, end_index - start_index); + flush_tlb_pgtables(mm, first & PGDIR_MASK, last & PGDIR_MASK); + } } /* Munmap is split into 2 main parts -- this part which finds diff --git a/mm/mremap.c b/mm/mremap.c index 45bcf5264dbe..6ea05dd76d5b 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -165,19 +165,14 @@ static inline unsigned long move_vma(struct vm_area_struct * vma, * * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise * This option implies MREMAP_MAYMOVE. - * - * "__new_addr" toying in order to not change the saved stack layout - * for old x86 binaries that don't want %edi to change.. */ -asmlinkage unsigned long sys_mremap(unsigned long addr, +unsigned long do_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long __new_addr) + unsigned long flags, unsigned long new_addr) { - unsigned long new_addr = __new_addr; struct vm_area_struct *vma; unsigned long ret = -EINVAL; - down(¤t->mm->mmap_sem); if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE)) goto out; @@ -287,6 +282,17 @@ asmlinkage unsigned long sys_mremap(unsigned long addr, ret = move_vma(vma, addr, old_len, new_len, new_addr); } out: + return ret; +} + +asmlinkage unsigned long sys_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr) +{ + unsigned long ret; + + down(¤t->mm->mmap_sem); + ret = do_mremap(addr, old_len, new_len, flags, new_addr); up(¤t->mm->mmap_sem); return ret; } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 33eea733d496..6b3695c3eca6 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.73 2000/02/09 11:16:42 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.74 2000/02/14 20:56:30 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -659,6 +659,7 @@ static void tcp_synack_timer(struct sock *sk) if (req->retrans == 0) lopt->qlen_young--; tcp_openreq_free(req); + continue; } reqp = &req->dl_next; } -- 2.39.5