From c7a3ddd8779b449a602b28b20aa02731d9af0fe4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:23:24 -0500 Subject: [PATCH] Linux 2.2.19pre14 o Update slhc code for endianness (Dave Miller) o Update s390 dasd driver (Ulrich Weigand) o Allow more than 4K of partitions (Ulrich Weigand) o Fix check in sockfilter (Dave Miller) o Sparc updates (quad sbus sunhme detect, BUG()) (Dave Miller) o Fix hid locking and ston32 bugs (Paul Mackerras) o Update 3c59x drivers (Andrew Morton, Maciej Rozycki, Fred Maciel, Georg Engstrand, Brett Frankenberger, Don Becker, o Fix a usb message (Randy Dunlap) o Eicon driver updates (Armin Schindler) o Update 8139too driver (Jens David) o Fix USB hub locks (Paul Mackerras) o Fix missing keyspan config line (Paul Mackerras) o Merge S/390 bug fixes (Ulrich Weigand) o Some S/390 cleanups (Ulrich Weigand) o Update S/390 ELF magic (Ulrich Weigand) o Update hwc driver (Ulrich Weigand) o Update ctc driver (Ulrich Weigand) o Update iucv driver (Ulrich Weigand) o S/390 warning fixes (Ulrich Weigand) --- Documentation/ioctl-number.txt | 1 + Documentation/isdn/00-INDEX | 3 + Documentation/isdn/README.eicon | 20 +- Documentation/isdn/README.fax | 3 + Documentation/networking/vortex.txt | 361 +++++++- arch/s390/kernel/Makefile | 11 +- arch/s390/kernel/cpcmd.c | 6 +- arch/s390/kernel/debug.c | 1006 ++++++++++++---------- arch/s390/kernel/ebcdic.c | 9 + arch/s390/kernel/entry.S | 8 +- arch/s390/kernel/head.S | 36 +- arch/s390/kernel/irq.c | 10 + arch/s390/kernel/reipl.S | 8 +- arch/s390/kernel/s390_ext.c | 3 + arch/s390/kernel/s390_ksyms.c | 78 -- arch/s390/kernel/s390dyn.c | 3 + arch/s390/kernel/s390io.c | 39 +- arch/s390/kernel/signal.c | 7 +- arch/s390/kernel/smp.c | 5 + arch/s390/lib/strcmp.S | 4 +- arch/s390/lib/strncpy.S | 6 +- arch/s390/mm/init.c | 2 +- arch/s390/tools/dasdfmt/dasdfmt.c | 5 +- drivers/block/genhd.c | 15 +- drivers/isdn/Config.in | 17 +- drivers/isdn/Makefile | 2 +- drivers/isdn/eicon/Divas_mod.c | 151 ++++ drivers/isdn/eicon/Makefile | 27 +- drivers/isdn/eicon/adapter.h | 262 ++++++ drivers/isdn/eicon/bri.c | 714 ++++++++++++++++ drivers/isdn/eicon/common.c | 896 +++++++++++++++++++ drivers/isdn/eicon/constant.h | 176 ++++ drivers/isdn/eicon/divalog.h | 54 ++ drivers/isdn/eicon/divas.h | 229 +++++ drivers/isdn/eicon/dsp_defs.h | 300 +++++++ drivers/isdn/eicon/dspdids.h | 81 ++ drivers/isdn/eicon/eicon.h | 392 +-------- drivers/isdn/eicon/eicon_dsp.h | 130 +-- drivers/isdn/eicon/eicon_idi.c | 522 ++++++------ drivers/isdn/eicon/eicon_idi.h | 185 +--- drivers/isdn/eicon/eicon_io.c | 555 +++++------- drivers/isdn/eicon/eicon_isa.c | 62 +- drivers/isdn/eicon/eicon_isa.h | 35 +- drivers/isdn/eicon/eicon_mod.c | 669 +++++++-------- drivers/isdn/eicon/eicon_pci.c | 983 ++------------------- drivers/isdn/eicon/eicon_pci.h | 151 +--- drivers/isdn/eicon/fourbri.c | 573 +++++++++++++ drivers/isdn/eicon/fpga.c | 155 ++++ drivers/isdn/eicon/idi.c | 867 +++++++++++++++++++ drivers/isdn/eicon/idi.h | 143 ++++ drivers/isdn/eicon/kprintf.c | 535 ++++++++++++ drivers/isdn/eicon/lincfg.c | 407 +++++++++ drivers/isdn/eicon/linchr.c | 269 ++++++ drivers/isdn/eicon/linio.c | 747 ++++++++++++++++ drivers/isdn/eicon/linsys.c | 167 ++++ drivers/isdn/eicon/log.c | 176 ++++ drivers/isdn/eicon/pc.h | 317 +++++++ drivers/isdn/eicon/pc_maint.h | 162 ++++ drivers/isdn/eicon/pr_pc.h | 83 ++ drivers/isdn/eicon/pri.c | 530 ++++++++++++ drivers/isdn/eicon/sys.h | 116 +++ drivers/isdn/eicon/uxio.h | 217 +++++ drivers/isdn/eicon/xlog.c | 180 ++++ drivers/net/3c59x.c | 639 +++++++------- drivers/net/8139too.c | 241 ++++-- drivers/net/slhc.c | 10 +- drivers/net/sunhme.c | 18 +- drivers/s390/Config.in | 2 +- drivers/s390/Makefile | 5 +- drivers/s390/block/Makefile | 23 +- drivers/s390/block/dasd.c | 647 +++++++++----- drivers/s390/block/dasd.h | 1 - drivers/s390/block/dasd_3990_erp.c | 1232 +++++++++++++++++++++++++-- drivers/s390/block/dasd_3990_erp.h | 21 + drivers/s390/block/dasd_9343_erp.h | 18 + drivers/s390/block/dasd_diag.c | 17 +- drivers/s390/block/dasd_eckd.c | 69 +- drivers/s390/block/dasd_eckd.h | 19 + drivers/s390/block/dasd_fba.c | 17 +- drivers/s390/block/xpram.c | 4 +- drivers/s390/ccwcache.c | 12 +- drivers/s390/char/hwc.h | 22 +- drivers/s390/char/hwc_rw.c | 433 ++++++---- drivers/s390/char/hwc_rw.h | 9 - drivers/s390/idals.c | 87 +- drivers/s390/misc/Makefile | 3 +- drivers/s390/net/Makefile | 3 +- drivers/s390/net/ctc.c | 125 +-- drivers/s390/net/iucv.c | 9 +- drivers/s390/net/netiucv.c | 2 +- drivers/usb/hid.c | 18 +- drivers/usb/serial/Config.in | 1 + drivers/usb/usb.c | 13 +- drivers/video/promcon.c | 2 +- fs/proc/array.c | 4 +- include/asm-s390/bitops.h | 16 +- include/asm-s390/ccwcache.h | 6 +- include/asm-s390/dasd.h | 30 +- include/asm-s390/debug.h | 159 +++- include/asm-s390/elf.h | 3 +- include/asm-s390/idals.h | 47 +- include/asm-s390/io.h | 2 +- include/asm-s390/irq.h | 37 +- include/asm-s390/pgtable.h | 18 +- include/asm-s390/system.h | 29 +- include/asm-s390/todclk.h | 19 + include/asm-sparc/page.h | 6 +- include/asm-sparc64/page.h | 4 +- include/linux/blk.h | 2 +- include/linux/elf.h | 6 +- init/main.c | 6 - net/core/filter.c | 8 +- net/ipv6/ipv6_sockglue.c | 4 + scripts/makelst | 5 +- 114 files changed, 13460 insertions(+), 4559 deletions(-) create mode 100644 drivers/isdn/eicon/Divas_mod.c create mode 100644 drivers/isdn/eicon/adapter.h create mode 100644 drivers/isdn/eicon/bri.c create mode 100644 drivers/isdn/eicon/common.c create mode 100644 drivers/isdn/eicon/constant.h create mode 100644 drivers/isdn/eicon/divalog.h create mode 100644 drivers/isdn/eicon/divas.h create mode 100644 drivers/isdn/eicon/dsp_defs.h create mode 100644 drivers/isdn/eicon/dspdids.h create mode 100644 drivers/isdn/eicon/fourbri.c create mode 100644 drivers/isdn/eicon/fpga.c create mode 100644 drivers/isdn/eicon/idi.c create mode 100644 drivers/isdn/eicon/idi.h create mode 100644 drivers/isdn/eicon/kprintf.c create mode 100644 drivers/isdn/eicon/lincfg.c create mode 100644 drivers/isdn/eicon/linchr.c create mode 100644 drivers/isdn/eicon/linio.c create mode 100644 drivers/isdn/eicon/linsys.c create mode 100644 drivers/isdn/eicon/log.c create mode 100644 drivers/isdn/eicon/pc.h create mode 100644 drivers/isdn/eicon/pc_maint.h create mode 100644 drivers/isdn/eicon/pr_pc.h create mode 100644 drivers/isdn/eicon/pri.c create mode 100644 drivers/isdn/eicon/sys.h create mode 100644 drivers/isdn/eicon/uxio.h create mode 100644 drivers/isdn/eicon/xlog.c create mode 100644 drivers/s390/block/dasd_3990_erp.h create mode 100644 drivers/s390/block/dasd_9343_erp.h create mode 100644 include/asm-s390/todclk.h diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index 6f16292116f2..d3978957e85d 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -66,6 +66,7 @@ Code Seq# Include File Comments 0x22 all scsi/sg.h 'A' all linux/apm_bios.h 'C' all linux/soundcard.h +'D' all asm-s390/dasd.h 'F' all linux/fb.h 'I' all linux/isdn.h 'K' all linux/kd.h diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX index ca891ec75aec..9fee5f2e5c62 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 + diff --git a/Documentation/isdn/README.eicon b/Documentation/isdn/README.eicon index 73d8c92dd850..16dd09eb9e1c 100644 --- a/Documentation/isdn/README.eicon +++ b/Documentation/isdn/README.eicon @@ -1,4 +1,4 @@ -$Id: README.eicon,v 1.6 2000/01/27 09:54:44 armin Exp $ +$Id: README.eicon,v 1.10 2000/08/13 12:19:15 armin Exp $ (c) 1999,2000 Armin Schindler (mac@melware.de) (c) 1999,2000 Cytronics & Melware (info@melware.de) @@ -40,6 +40,7 @@ DIVA Server family ------------------ - DIVA Server BRI/PCI 2M - DIVA Server PRI/PCI 2M (9M 23M 30M) +- DIVA Server 4BRI/PCI supported functions of onboard DSPs: - analog modem - fax group 2/3 (Fax Class 2 commands) @@ -78,6 +79,10 @@ Example for loading and starting a BRI card with E-DSS1 Protocol. eiconctrl [-d DriverId] load etsi +Example for a BRI card with E-DSS1 Protocol with PtP configuration. + + eiconctrl [-d DriverId] load etsi -n -t1 -s1 + Example for loading and starting a PRI card with E-DSS1 Protocol. @@ -95,6 +100,18 @@ Just use "eiconctrl isdnlog on" and the driver will generate the necessary D-Channel traces for isdnlog. +FILECHECK: +A part of the eicon driver source code files are provided +by Eicon Technology. In order to get the best support from Eicon, +these files are tested with a checksum, just to know if the files +were modified. This does *not* mean, you are not allowed to modify the +driver. If you want to improve the driver or you fix a bug, please do +so and let me (or Eicon) know, about the necessary changes. So +every user knows, if the driver he uses is modified or checked with +Eicon files. When the driver has been loaded, in the syslog you will +find something like "verified" or "modified" right after the version. + + Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH for sponsoring and testing fax @@ -109,3 +126,4 @@ Have fun ! Armin Schindler mac@melware.de http://www.melware.de + diff --git a/Documentation/isdn/README.fax b/Documentation/isdn/README.fax index eeff9ce9f2c0..5314958a8a6e 100644 --- a/Documentation/isdn/README.fax +++ b/Documentation/isdn/README.fax @@ -24,6 +24,9 @@ Supported ISDN-Cards Eicon DIVA Server BRI/PCI - full support with both B-channels. +Eicon DIVA Server 4BRI/PCI + - full support with all B-channels. + Eicon DIVA Server PRI/PCI - full support on amount of B-channels depending on DSPs on board. diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt index 413aadf91557..bd394a752e14 100644 --- a/Documentation/networking/vortex.txt +++ b/Documentation/networking/vortex.txt @@ -1,35 +1,348 @@ +Documentation/networking/vortex.txt +Andrew Morton +18 Feb 2001 + + This document describes the usage and errata of the 3Com "Vortex" device -driver for Linux. +driver for Linux, 3c59x.c. + +The driver was written by Donald Becker + +Don is no longer the prime maintainer of this version of the driver. +Please report problems to one or more of: + + Andrew Morton + Netdev mailing list + Linux kernel mailing list + +Please note the 'Reporting and Diagnosing Problems' section at the end +of this file. This driver supports the following hardware: - 3c590, 3c592, 3c595, 3c597 - -When loaded as a module the following variables may be set: - name type description - debug int The debug message level, 0 (no messages) to 6 (wordy). - options int[] The media type override and card operation settings - (See list below.) - -An example of loading the vortex module is - insmod 3c59x.o debug=1 options=0,,12 -This sets the debug message level to minimal messages, sets the first card to -the 10baseT transceiver, the second to the EEPROM-set transceiver, and the -third card to operate in full-duplex mode using its 100baseTx transceiver. -(Note: card ordering is set by the PCI BIOS.) - -Possible media type settings + + 3c590 Vortex 10Mbps + 3c592 EISA 10mbps Demon/Vortex + 3c597 EISA Fast Demon/Vortex + 3c595 Vortex 100baseTx + 3c595 Vortex 100baseT4 + 3c595 Vortex 100base-MII + 3Com Vortex + 3c900 Boomerang 10baseT + 3c900 Boomerang 10Mbps Combo + 3c900 Cyclone 10Mbps Combo + 3c900B-FL Cyclone 10base-FL + 3c900 Cyclone 10Mbps TPO + 3c900 Cyclone 10Mbps TPC + 3c905 Boomerang 100baseTx + 3c905 Boomerang 100baseT4 + 3c905B Cyclone 100baseTx + 3c905B Cyclone 10/100/BNC + 3c905B-FX Cyclone 100baseFx + 3c905C Tornado + 3c980 Cyclone + 3cSOHO100-TX Hurricane + 3c555 Laptop Hurricane + 3c556 10/100 Mini PCI Adapter + 3c556B Laptop Hurricane + 3c575 Boomerang CardBus + 3CCFE575 Cyclone CardBus + 3CCFE656 Cyclone CardBus + 3CCFEM656 Cyclone CardBus + 3c575 series CardBus (unknown version) + 3c450 HomePNA Tornado + 3Com Boomerang (unknown version) + +Module parameters +================= + +There are several parameters which may be provided to the driver when +its module is loaded. These are usually placed in /etc/modules.conf +(used to be conf.modules). Example: + +options 3c59x debug=3 rx_copybreak=300 + +The supported parameters are: + +debug=N + + Where N is a number from 0 to 7. Anything above 3 produces a lot + of output in your system logs. debug=1 is default. + +options=N1,N2,N3,... + + Each number in the list provides an option to the corresponding + network card. So if you have two 3c905's and you wish to provide + them with option 0x204 you would use: + + options=0x204,0x204 + + The individual options are composed of a number of bitfields which + have the following meanings: + + ssible media type settings 0 10baseT 1 10Mbs AUI 2 undefined 3 10base2 (BNC) 4 100base-TX 5 100base-FX - 6 MII (not yet available) - 7 - - 8 Full-duplex bit - 8 10baseT full-duplex - 12 100baseTx full-duplex - 16 Bus-master enable bit (experimental use only!) + 6 MII (Media Independent Interface) + 7 Use default setting from EEPROM + 8 Autonegotiate + 9 External MII + 10 Use default setting from EEPROM + + When generating a value for the 'options' setting, the above media + selection values may be OR'ed (or added to) the following: + + 512 (0x200) Force full duplex mode. + 16 (0x10) Bus-master enable bit (Old Vortex cards only) + + For example: + + insmod 3c59x options=0x204 + + will force full-duplex 100base-TX, rather than allowing the usual + autonegotiation. + +full_duplex=N1,N2,N3... + + Similar to bit 9 of 'options'. Forces the corresponding card into + full-duplex mode. Please use this in preference to the `options' + parameter. + + In fact, please don't use this at all! You're better off getting + autonegotiation working properly. + +rx_copybreak=M + + The driver preallocates 32 full-sized (1536 byte) network buffers + for receiving. When a packet arrives, the driver has to decide + whether to leave the packet in its full-sized buffer, or to allocate + a smaller buffer and copy the packet across into it. + + This is a speed/space tradeoff. + + The value of rx_copybreak is used to decide when to make the copy. + If the packet size is less than rx_copybreak, the packet is copied. + The default value for rx_copybreak is 200 bytes. + +max_interrupt_work=N + + The driver's interrupt service routine can handle many receive and + transmit packets in a single invocation. It does this in a loop. + The value of max_interrupt_work governs how mnay times the interrupt + service routine will loop. The default value is 32 loops. If this + is exceeded the interrupt service routine gives up and generates a + warning message "eth0: Too much work in interrupt". + +compaq_ioaddr=N +compaq_irq=N +compaq_device_id=N + + "Variables to work-around the Compaq PCI BIOS32 problem".... + +enable_wol=N1,N2,N3,... + + Enable Wake-on-LAN support for the relevant interface. Donald + Becker's `ether-wake' application may be used to wake suspended + machines. + + +Media selection +--------------- + +A number of the older NICs such as the 3c590 and 3c900 series have +10base2 and AUI interfaces. + +Prior to January, 2001 this driver would autoeselect the 10base2 or AUI +port if it didn't detect activity on the 10baseT port. It would then +get stuck on the 10base2 port and a driver reload was necessary to +switch back to 10baseT. This behaviour could not be prevented with a +module option override. + +Later (current) versions of the driver _do_ support locking of the +media type. So if you load the driver module with + + modprobe 3c59x options=0 + +it will permanently select the 10baseT port. Automatic selection of +other media types does not occur. + + +Additional resources +-------------------- Details of the device driver implementation are at the top of the source file. + +Additional documentation is available at Don Becker's Linux Drivers site: + + http://www.scyld.com/network/vortex.html + +Donald Becker's driver development site: + + http://www.scyld.com/network + +Donald's vortex-diag program is useful for inspecting the NIC's state: + + http://www.scyld.com/diag/#pci-diags + +Donald's mii-diag program may be used for inspecting and manipulating +the NIC's Media Independent Interface subsystem: + + http://www.scyld.com/diag/#mii-diag + +Donald's wake-on-LAN page: + + http://www.scyld.com/expert/wake-on-lan.html + +3Com's documentation for many NICs, including the ones supported by +this driver is available at + + http://support.3com.com/partners/developer/developer_form.html + +3Com's DOS-based application for setting up the NICs EEPROMs: + + ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe + +Driver updates and a detailed changelog for the modifications which +were made for the 2.3/2,4 series kernel is available at + + http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 + + +Autonegotiation notes +--------------------- + + The driver uses a one-minute heartbeat for adapting to changes in + the external LAN environment. This means that when, for example, a + machine is unplugged from a hubbed 10baseT LAN plugged into a + switched 100baseT LAN, the throughput will be quite dreadful for up + to sixty seconds. Be patient. + + Cisco interoperability note from Walter Wong : + + On a side note, adding HAS_NWAY seems to share a problem with the + Cisco 6509 switch. Specifically, you need to change the spanning + tree parameter for the port the machine is plugged into to 'portfast' + mode. Otherwise, the negotiation fails. This has been an issue + we've noticed for a while but haven't had the time to track down. + + Cisco switches (Jeff Busch ) + + My "standard config" for ports to which PC's/servers connect directly: + + interface FastEthernet0/N + description machinename + load-interval 30 + spanning-tree portfast + + If autonegotiation is a problem, you may need to specify "speed + 100" and "duplex full" as well (or "speed 10" and "duplex half"). + + WARNING: DO NOT hook up hubs/switches/bridges to these + specially-configured ports! The switch will become very confused. + + +Reporting and diagnosing problems +--------------------------------- + +Maintainers find that accurate and complete problem reports are +invaluable in resolving driver problems. We are frequently not able to +reproduce problems and must rely on your patience and efforts to get to +the bottom of the problem. + +If you believe you have a driver problem here are some of the +steps you should take: + +- Is it really a driver problem? + + Eliminate some variables: try different cards, different + computers, different cables, different ports on the switch/hub, + different versions of the kernel or ofthe driver, etc. + +- OK, it's a driver problem. + + You need to generate a report. Typically this is an email to the + maintainer and/or linux-net@vger.kernel.org. The maintainer's + email address will be inthe driver source or in the MAINTAINERS file. + +- The contents of your report will vary a lot depending upon the + problem. If it's a kernel crash then you should refer to the + REPORTING-BUGS file. + + But for most problems it is useful to provide the following: + + o Kernel version, driver version + + o A copy of the banner message which the driver generates when + it is initialised. For example: + + eth0: 3Com PCI 3c905C Tornado at 0xa400, 00:50:da:6a:88:f0, IRQ 19 + 8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface. + MII transceiver found at address 24, status 782d. + Enabling bus-master transmits and whole-frame receives. + + o If it is a PCI device, the relevant output from 'lspci -vx', eg: + + 00:09.0 Ethernet controller: 3Com Corporation 3c905C-TX [Fast Etherlink] (rev 74) + Subsystem: 3Com Corporation: Unknown device 9200 + Flags: bus master, medium devsel, latency 32, IRQ 19 + I/O ports at a400 [size=128] + Memory at db000000 (32-bit, non-prefetchable) [size=128] + Expansion ROM at [disabled] [size=128K] + Capabilities: [dc] Power Management version 2 + 00: b7 10 00 92 07 00 10 02 74 00 00 02 08 20 00 00 + 10: 01 a4 00 00 00 00 00 db 00 00 00 00 00 00 00 00 + 20: 00 00 00 00 00 00 00 00 00 00 00 00 b7 10 00 10 + 30: 00 00 00 00 dc 00 00 00 00 00 00 00 05 01 0a 0a + + o A description of the environment: 10baseT? 100baseT? + full/half duplex? switched or hubbed? + + o Any additional module parameters which you may be providing to the driver. + + o Any kernel logs which are produced. The more the merrier. + If this is a large file and you are sending your report to a + mailing list, mention that you have the logfile, but don't send + it. If you're reporting direct to the maintainer then just send + it. + + To ensure that all kernel logs are available, add the + following line to /etc/syslog.conf: + + kern.* /var/log/messages + + Then restart syslogd with: + + /etc/rc.d/init.d/syslog restart + + (The above may vary, depending upon which Linux distribution you use). + + o If your problem is reproducible then that's great. Try the + following: + + 1) Increase the debug level. Usually this is done via: + + a) modprobe driver.o debug=7 + b) In /etc/conf.modules (or modules.conf): + options driver_name debug=7 + + 2) Recreate the problem with the higher debug level, + send all logs to the maintainer. + + 3) Download you card's diagnostic tool from Donald + Backer's website http://www.scyld.com/diag. Download + mii-diag.c as well. Build these. + + a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is + working correctly. Save the output. + + b) Run the above commands when the card is malfunctioning. Send + both sets of output. + +Finally, please be patient and be prepared to do some work. You may end up working on +this problem for a week or more as the maintainer asks more questions, asks for more +tests, asks for patches to be applied, etc. At the end of it all, the problem may even +remain unresolved. + diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 6490310140c1..abfe99df7777 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -18,16 +18,15 @@ endif all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ - setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - s390fpu.o s390io.o reipl.o debug.o s390_ext.o s390dyn.o \ - s390mach.o +O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o \ + setup.o sys_s390.o ptrace.o signal.o cpcmd.o \ + s390fpu.o reipl.o s390mach.o -OX_OBJS := s390_ksyms.o +OX_OBJS := debug.o ebcdic.o irq.o process.o s390_ext.o s390_ksyms.o s390dyn.o s390io.o MX_OBJS := ifdef CONFIG_SMP -O_OBJS += smp.o +OX_OBJS += smp.o endif ifeq ($(CONFIG_IEEEFPU_EMULATION),y) diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 93b1a2d0a756..a8c626d15aab 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -22,10 +22,10 @@ void cpcmd(char *cmd, char *response, int rlen) ASCEBC(obuffer,olen); if (response != NULL && rlen > 0) { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 4,%1\n\t" "O 4,%4\n\t" - "LRA 3,0(0,%2)\n\t" + "LRA 3,0(%2)\n\t" "LR 5,%3\n\t" ".long 0x83240008 # Diagnose 83\n\t" : /* no output */ @@ -34,7 +34,7 @@ void cpcmd(char *cmd, char *response, int rlen) : "2", "3", "4", "5" ); EBCASC(response, rlen); } else { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 3,%1\n\t" ".long 0x83230008 # Diagnose 83\n\t" : /* no output */ diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index f08881a0c917..52524b757331 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -10,48 +10,58 @@ * Bugreports to: */ +#include #include #include #include #include -#include #include #include -#include #include #include -#ifdef MODULE #include -#endif #include #define MIN(a,b) (((a)<(b))?(a):(b)) - -#if defined(CONFIG_ARCH_S390) -#define DEBUG_PROC_HEADER_SIZE 38 -#endif - -#define ADD_BUFFER 1000 +#define DEBUG_PROLOG_ENTRY -1 /* typedefs */ typedef struct file_private_info { - loff_t len; /* length of output in byte */ - int size; /* size of buffer for output */ - char *data; /* buffer for output */ - debug_info_t *debug_info; /* the debug information struct */ + loff_t offset; /* offset of last read in file */ + int act_area; /* number of last formated area */ + int act_entry; /* last formated entry (offset */ + /* relative to beginning of last */ + /* formated area) */ + size_t act_entry_offset; /* up to this offset we copied */ + /* in last read the last formated */ + /* entry to userland */ + char temp_buf[2048]; /* buffer for output */ + debug_info_t *debug_info_org; /* original debug information */ + debug_info_t *debug_info_snap; /* snapshot of debug information */ struct debug_view *view; /* used view of debug info */ } file_private_info_t; +typedef struct +{ + char *string; + /* + * This assumes that all args are converted into longs + * on L/390 this is the case for all types of parameter + * except of floats, and long long (32 bit) + * + */ + long args[0]; +} debug_sprintf_entry; + + extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); /* internal function prototyes */ static int debug_init(void); -static int debug_format_output(debug_info_t * debug_area, char *buf, - int size, struct debug_view *view); static ssize_t debug_output(struct file *file, char *user_buf, size_t user_len, loff_t * offset); static ssize_t debug_input(struct file *file, const char *user_buf, @@ -65,6 +75,7 @@ static struct proc_dir_entry struct file_operations *fops); static void debug_delete_proc_dir_entry(struct proc_dir_entry *root, struct proc_dir_entry *entry); +static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size); static void debug_info_get(debug_info_t *); static void debug_info_put(debug_info_t *); static int debug_prolog_level_fn(debug_info_t * id, @@ -72,38 +83,34 @@ static int debug_prolog_level_fn(debug_info_t * id, static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, struct file *file, const char *user_buf, size_t user_buf_size, loff_t * offset); -static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf); -static int debug_ascii_format_fn(debug_info_t * id, +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf); +static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, char *out_buf, const char *in_buf); -static int debug_ebcdic_format_fn(debug_info_t * id, - struct debug_view *view, char *out_buf, - const char *in_buf); +static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf); + +static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event); /* globals */ -struct debug_view debug_ascii_view = { - "ascii", +struct debug_view debug_raw_view = { + "raw", NULL, - &debug_dflt_header_fn, - &debug_ascii_format_fn, - NULL -}; - -struct debug_view debug_ebcdic_view = { - "ebcdic", + &debug_raw_header_fn, + &debug_raw_format_fn, NULL, - &debug_dflt_header_fn, - &debug_ebcdic_format_fn, NULL }; -struct debug_view debug_hex_view = { - "hex", +struct debug_view debug_hex_ascii_view = { + "hex_ascii", NULL, &debug_dflt_header_fn, - &debug_hex_format_fn, + &debug_hex_ascii_format_fn, + NULL, NULL }; @@ -112,13 +119,26 @@ struct debug_view debug_level_view = { &debug_prolog_level_fn, NULL, NULL, - &debug_input_level_fn + &debug_input_level_fn, + NULL +}; + +struct debug_view debug_sprintf_view = { + "sprintf", + NULL, + &debug_dflt_header_fn, + (debug_format_proc_t*)&debug_sprintf_format_fn, + NULL, + NULL }; + +unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; + /* static globals */ -static debug_info_t debug_areas[DEBUG_MAX_AREAS]; -static debug_info_t *free_area = 0; +static debug_info_t *debug_area_first = NULL; +static debug_info_t *debug_area_last = NULL; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) static struct semaphore debug_lock = MUTEX; #else @@ -143,9 +163,154 @@ static struct inode_operations debug_inode_ops = { static struct proc_dir_entry *debug_proc_root_entry; - /* functions */ +/* + * debug_info_alloc + * - alloc new debug-info + */ + +static debug_info_t* debug_info_alloc(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + int i; + + /* alloc everything */ + + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + if(!rc) + goto fail_malloc_rc; + rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); + if(!rc->active_entry) + goto fail_malloc_active_entry; + memset(rc->active_entry, 0, nr_areas * sizeof(int)); + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) + goto fail_malloc_areas; + for (i = 0; i < nr_areas; i++) { + rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC, + page_order); + if (!rc->areas[i]) { + for (i--; i >= 0; i--) { + free_pages((unsigned long) rc->areas[i], + page_order); + } + goto fail_malloc_areas2; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + /* initialize members */ + + spin_lock_init(&rc->lock); + rc->page_order = page_order; + rc->nr_areas = nr_areas; + rc->active_area = 0; + rc->level = DEBUG_DEFAULT_LEVEL; + rc->buf_size = buf_size; + rc->entry_size = sizeof(debug_entry_t) + buf_size; + strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); + rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; + memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct proc_dir_entry*)); + atomic_set(&(rc->ref_count), 0); + + return rc; + +fail_malloc_areas2: + kfree(rc->areas); +fail_malloc_areas: + kfree(rc->active_entry); +fail_malloc_active_entry: + kfree(rc); +fail_malloc_rc: + return NULL; +} + +/* + * debug_info_free + * - free memory debug-info + */ + +static void debug_info_free(debug_info_t* db_info){ + int i; + for (i = 0; i < db_info->nr_areas; i++) { + free_pages((unsigned long) db_info->areas[i], + db_info->page_order); + } + kfree(db_info->areas); + kfree(db_info->active_entry); + kfree(db_info); +} + +/* + * debug_info_create + * - create new debug-info + */ + +static debug_info_t* debug_info_create(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + + rc = debug_info_alloc(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; + + + /* create proc rood directory */ + + rc->proc_root_entry = + debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, + S_IFDIR | S_IRUGO | S_IXUGO | + S_IWUSR | S_IWGRP, NULL, NULL); + + /* append new element to linked list */ + + if(debug_area_first == NULL){ + /* first element in list */ + debug_area_first = rc; + rc->prev = NULL; + } + else{ + /* append element to end of list */ + debug_area_last->next = rc; + rc->prev = debug_area_last; + } + debug_area_last = rc; + rc->next = NULL; + + debug_info_get(rc); +out: + return rc; +} + +/* + * debug_info_copy + * - copy debug-info + */ + +static debug_info_t* debug_info_copy(debug_info_t* in) +{ + int i; + debug_info_t* rc; + rc = debug_info_alloc(in->name, in->page_order, + in->nr_areas, in->buf_size); + if(!rc) + goto out; + + for(i = 0; i < in->nr_areas; i++){ + memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order); + } +out: + return rc; +} + /* * debug_info_get * - increments reference count for debug-info @@ -179,44 +344,120 @@ static void debug_info_put(debug_info_t *db_info) } debug_delete_proc_dir_entry(debug_proc_root_entry, db_info->proc_root_entry); - for (i = 0; i < db_info->nr_areas; i++) { - free_pages((unsigned long) db_info->areas[i], - db_info->page_order); - } - kfree(db_info->areas); - db_info->areas = NULL; - *((debug_info_t **) db_info) = free_area; - free_area = db_info; + if(db_info == debug_area_first) + debug_area_first = db_info->next; + if(db_info == debug_area_last) + debug_area_last = db_info->prev; + if(db_info->prev) db_info->prev->next = db_info->next; + if(db_info->next) db_info->next->prev = db_info->prev; + debug_info_free(db_info); + } +} + +/* + * debug_format_entry: + * - format one debug entry and return size of formated data + */ + +static int debug_format_entry(file_private_info_t *p_info) +{ + debug_info_t *id_org = p_info->debug_info_org; + debug_info_t *id_snap = p_info->debug_info_snap; + struct debug_view *view = p_info->view; + debug_entry_t *act_entry; + size_t len = 0; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(id_org, view,p_info->temp_buf); + goto out; } + + act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] + + p_info->act_entry); + + if (act_entry->id.stck == 0LL) + goto out; /* empty entry */ + if (view->header_proc) + len += view->header_proc(id_org, view, p_info->act_area, + act_entry, p_info->temp_buf + len); + if (view->format_proc) + len += view->format_proc(id_org, view, p_info->temp_buf + len, + DEBUG_DATA(act_entry)); + out: + return len; } +/* + * debug_next_entry: + * - goto next entry in p_info + */ + +extern inline int debug_next_entry(file_private_info_t *p_info) +{ + debug_info_t *id = p_info->debug_info_snap; + if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ + p_info->act_entry = 0; + goto out; + } + if ((p_info->act_entry += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) + - id->entry_size)){ + + /* next area */ + p_info->act_entry = 0; + p_info->act_area++; + if(p_info->act_area >= id->nr_areas) + return 1; + } +out: + return 0; +} /* * debug_output: * - called for user read() - * - copies formated output form private_data of the file - * handle to the user buffer + * - copies formated debug entries to the user buffer */ static ssize_t debug_output(struct file *file, /* file descriptor */ char *user_buf, /* user buffer */ - size_t user_len, /* length of buffer */ + size_t len, /* length of buffer */ loff_t *offset /* offset in the file */ ) { - loff_t len; + size_t count = 0; + size_t entry_offset, size = 0; int rc; file_private_info_t *p_info; p_info = ((file_private_info_t *) file->private_data); - if (*offset >= p_info->len) { - return 0; /* EOF */ - } else { - len = MIN(user_len, (p_info->len - *offset)); - if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len))) - return rc;; - (*offset) += len; - return len; /* number of bytes "read" */ + if (*offset != p_info->offset) + return -EPIPE; + if(p_info->act_area >= p_info->debug_info_snap->nr_areas) + return 0; + + entry_offset = p_info->act_entry_offset; + + while(count < len){ + size = debug_format_entry(p_info); + size = MIN((len - count), (size - entry_offset)); + + if(size){ + if ((rc = copy_to_user(user_buf + count, + p_info->temp_buf + entry_offset, size))) + return rc; + } + count += size; + entry_offset = 0; + if(count != len) + if(debug_next_entry(p_info)) + goto out; } +out: + p_info->offset = *offset + count; + p_info->act_entry_offset = size; + *offset = p_info->offset; + return count; } /* @@ -235,68 +476,15 @@ static ssize_t debug_input(struct file *file, down(&debug_lock); p_info = ((file_private_info_t *) file->private_data); if (p_info->view->input_proc) - rc = p_info->view->input_proc(p_info->debug_info, + rc = p_info->view->input_proc(p_info->debug_info_org, p_info->view, file, user_buf, length, offset); + else + rc = -EPERM; up(&debug_lock); return rc; /* number of input characters */ } -/* - * debug_format_output: - * - calls prolog, header and format functions of view to format output - */ - -static int debug_format_output(debug_info_t * debug_area, char *buf, - int size, struct debug_view *view) -{ - int len = 0; - int i, j; - int nr_of_entries; - debug_entry_t *act_entry; - - /* print prolog */ - if (view->prolog_proc) - len += view->prolog_proc(debug_area, view, buf); - /* print debug records */ - if (!(view->format_proc) && !(view->header_proc)) - goto out; - nr_of_entries = PAGE_SIZE / debug_area->entry_size - << debug_area->page_order; - for (i = 0; i < debug_area->nr_areas; i++) { - act_entry = debug_area->areas[i]; - for (j = 0; j < nr_of_entries; j++) { - if (act_entry->id.fields.used == 0) - break; /* empty entry */ - if (view->header_proc) - len += view->header_proc(debug_area, view, i, - act_entry, buf + len); - if (view->format_proc) - len += view->format_proc(debug_area, view, - buf + len, - act_entry->data); - len += sprintf(buf + len, "\n"); - if (len > size) { - printk(KERN_ERR - "debug: error -- memory exceeded for (%s/%s)\n", - debug_area->name, view->name); - printk(KERN_ERR "debug: fix view %s!!\n", - view->name); - printk(KERN_ERR - "debug: area: %i (0 - %i) entry: %i (0 - %i)\n", - i, debug_area->nr_areas - 1, j, - nr_of_entries - 1); - goto out; - } - act_entry = (debug_entry_t *) (((char *) act_entry) + - debug_area->entry_size); - } - } - out: - return len; -} - - /* * debug_open: * - called for user open() @@ -306,119 +494,68 @@ static int debug_format_output(debug_info_t * debug_area, char *buf, static int debug_open(struct inode *inode, struct file *file) { - int i, j = 0, size = 0, rc = 0, f_entry_size = 0; + int i = 0, rc = 0; file_private_info_t *p_info; + debug_info_t *debug_info, *debug_info_snapshot; #ifdef DEBUG printk("debug_open\n"); #endif - -#ifdef MODULE MOD_INC_USE_COUNT; -#endif down(&debug_lock); /* find debug log and view */ - for (i = 0; i < DEBUG_MAX_AREAS; i++) { - if (debug_areas[i].areas == NULL) - continue; /* not in use */ - for (j = 0; j < DEBUG_MAX_VIEWS; j++) { - if (debug_areas[i].views[j] == NULL) + debug_info = debug_area_first; + while(debug_info != NULL){ + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (debug_info->views[i] == NULL) continue; - else if (debug_areas[i].proc_entries[j]->low_ino == + else if (debug_info->proc_entries[i]->low_ino == file->f_dentry->d_inode->i_ino) { goto found; /* found view ! */ } } + debug_info = debug_info->next; } /* no entry found */ rc = -EINVAL; goto out; + found: - if ((file->private_data = - kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { - printk(KERN_ERR "debug_open: kmalloc failed\n"); - rc = -ENOMEM; - goto out; - } - p_info = (file_private_info_t *) file->private_data; - /* - * the size for the formated output is calculated - * with the following formula: - * - * prolog-size - * + - * (record header size + record data field size) - * * number of entries per page - * * number of pages per area - * * number of areas - */ - - if (debug_areas[i].views[j]->prolog_proc) - size += - debug_areas[i].views[j]->prolog_proc(&debug_areas[i], - debug_areas[i]. - views[j], NULL); - - if (debug_areas[i].views[j]->header_proc) - f_entry_size = - debug_areas[i].views[j]->header_proc(&debug_areas[i], - debug_areas[i]. - views[j], 0, NULL, - NULL); - if (debug_areas[i].views[j]->format_proc) - f_entry_size += - debug_areas[i].views[j]->format_proc(&debug_areas[i], - debug_areas[i]. - views[j], NULL, - NULL); - if (f_entry_size) - f_entry_size += 1; /* \n in each line */ - - - size += f_entry_size - * (PAGE_SIZE / debug_areas[i].entry_size - << debug_areas[i].page_order) - * debug_areas[i].nr_areas + 1; /* terminating \0 */ -#ifdef DEBUG - printk("debug_open: size: %i\n", size); -#endif + /* make snapshot of current debug areas to get it consistent */ + + debug_info_snapshot = debug_info_copy(debug_info); - /* alloc some bytes more to be safe against bad views */ - if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) { - printk(KERN_ERR "debug_open: vmalloc failed\n"); - vfree(file->private_data); + if(!debug_info_snapshot){ + printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n"); rc = -ENOMEM; goto out; } - p_info->size = size; - p_info->debug_info = &debug_areas[i]; - p_info->view = debug_areas[i].views[j]; - - spin_lock_irq(&debug_areas[i].lock); - - p_info->len = - debug_format_output(&debug_areas[i], p_info->data, size, - debug_areas[i].views[j]); -#ifdef DEBUG - { - int ilen = p_info->len; - printk("debug_open: len: %i\n", ilen); + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + debug_info_free(debug_info_snapshot); + rc = -ENOMEM; + goto out; } -#endif + p_info = (file_private_info_t *) file->private_data; + p_info->offset = 0; + p_info->debug_info_snap = debug_info_snapshot; + p_info->debug_info_org = debug_info; + p_info->view = debug_info->views[i]; + p_info->act_area = 0; + p_info->act_entry = DEBUG_PROLOG_ENTRY; + p_info->act_entry_offset = 0; - spin_unlock_irq(&debug_areas[i].lock); - debug_info_get(&debug_areas[i]); + debug_info_get(debug_info); out: up(&debug_lock); -#ifdef MODULE if (rc != 0) MOD_DEC_USE_COUNT; -#endif return rc; } @@ -434,18 +571,11 @@ static int debug_close(struct inode *inode, struct file *file) #ifdef DEBUG printk("debug_close\n"); #endif - down(&debug_lock); p_info = (file_private_info_t *) file->private_data; - debug_info_put(p_info->debug_info); - if (p_info->data) { - vfree(p_info->data); - kfree(file->private_data); - } - up(&debug_lock); - -#ifdef MODULE + debug_info_free(p_info->debug_info_snap); + debug_info_put(p_info->debug_info_org); + kfree(file->private_data); MOD_DEC_USE_COUNT; -#endif return 0; /* success */ } @@ -522,74 +652,25 @@ debug_info_t *debug_register (char *name, int page_order, int nr_areas, int buf_size) { debug_info_t *rc = NULL; - int i; -#ifdef MODULE MOD_INC_USE_COUNT; -#endif if (!initialized) debug_init(); down(&debug_lock); - if (!free_area) { - printk(KERN_WARNING "debug: no free debug area for %s\n", - name); - goto out; - } - rc = free_area; - free_area = *((debug_info_t **) rc); - rc->areas = (debug_entry_t **) kmalloc(nr_areas * - sizeof(debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) { - free_area = rc; - rc = NULL; - goto out; - } - for (i = 0; i < nr_areas; i++) { - rc->areas[i] = - (debug_entry_t *) __get_free_pages(GFP_ATOMIC, - page_order); - if (!rc->areas[i]) { - for (i--; i >= 0; i--) { - free_pages((unsigned long) rc->areas[i], - page_order); - } - free_area = rc; - rc = NULL; - goto out; - } else { - memset(rc->areas[i], 0, PAGE_SIZE << page_order); - } - } - rc->page_order = page_order; - rc->nr_areas = nr_areas; - rc->active_area = 0; - rc->level = DEBUG_DEFAULT_LEVEL; - rc->buf_size = buf_size; - rc->entry_size = sizeof(debug_entry_t) - + buf_size - 4; /* must subtract data[4] */ - strncpy(rc->name, name, - MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); - rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; - memset(rc->active_entry, 0, nr_areas * sizeof(int)); - memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); - atomic_set(&(rc->ref_count), 0); - rc->proc_root_entry = - debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, - S_IFDIR | S_IRUGO | S_IXUGO | - S_IWUSR | S_IWGRP, NULL, NULL); + /* create new debug_info */ + + rc = debug_info_create(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; debug_register_view(rc, &debug_level_view); - debug_info_get(rc); printk(KERN_INFO "debug: reserved %d areas of %d pages for debugging %s\n", nr_areas, 1 << page_order, rc->name); out: if (rc == NULL){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif } up(&debug_lock); return rc; @@ -609,20 +690,44 @@ void debug_unregister(debug_info_t * id) debug_info_put(id); up(&debug_lock); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif out: return; } +/* + * debug_set_level: + * - set actual debug level + */ + +void debug_set_level(debug_info_t* id, int new_level) +{ + unsigned long flags; + if(!id) + return; + spin_lock_irqsave(&id->lock,flags); + if(new_level == DEBUG_OFF_LEVEL){ + id->level = DEBUG_OFF_LEVEL; + printk(KERN_INFO "debug: %s: switched off\n",id->name); + } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { + printk(KERN_INFO + "debug: %s: level %i is out of range (%i - %i)\n", + id->name, new_level, 0, DEBUG_MAX_LEVEL); + } else { + id->level = new_level; + printk(KERN_INFO + "debug: %s: new level %i\n",id->name,id->level); + } + spin_unlock_irqrestore(&id->lock,flags); +} + /* * proceed_active_entry: * - set active entry to next in the ring buffer */ -static inline void proceed_active_entry(debug_info_t * id) +extern inline void proceed_active_entry(debug_info_t * id) { if ((id->active_entry[id->active_area] += id->entry_size) > ((PAGE_SIZE << (id->page_order)) - id->entry_size)) @@ -634,7 +739,7 @@ static inline void proceed_active_entry(debug_info_t * id) * - set active area to next in the ring buffer */ -static inline void proceed_active_area(debug_info_t * id) +extern inline void proceed_active_area(debug_info_t * id) { id->active_area++; id->active_area = id->active_area % id->nr_areas; @@ -644,7 +749,7 @@ static inline void proceed_active_area(debug_info_t * id) * get_active_entry: */ -static inline debug_entry_t *get_active_entry(debug_info_t * id) +extern inline debug_entry_t *get_active_entry(debug_info_t * id) { return (debug_entry_t *) ((char *) id->areas[id->active_area] + id->active_entry[id->active_area]); @@ -655,162 +760,126 @@ static inline debug_entry_t *get_active_entry(debug_info_t * id) * - set timestamp, caller address, cpu number etc. */ -static inline debug_entry_t *debug_common(debug_info_t * id) +extern inline debug_entry_t *debug_common(debug_info_t * id, int level, + const void *buf, int len, int exception) { + unsigned long flags; debug_entry_t *active; + spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); STCK(active->id.stck); active->id.fields.cpuid = smp_processor_id(); - active->id.fields.used = 1; active->caller = __builtin_return_address(0); - return active; -} - -/* - * debug_event: - */ - -debug_entry_t *debug_event(debug_info_t * id, int level, void *buf, - int len) -{ - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 0; - memset(active->data, 0, id->buf_size); - memcpy(active->data, buf, MIN(len, id->buf_size)); + active->id.fields.exception = exception; + active->id.fields.level = level; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); proceed_active_entry(id); + if(exception) + proceed_active_area(id); spin_unlock_irqrestore(&id->lock, flags); - out: + return active; } /* - * debug_int_event: + * debug_event_common: + * - write debug entry with given size */ -debug_entry_t *debug_int_event(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf, + int len) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 0; - memset(active->data, 0, id->buf_size); - memcpy(active->data, &tag, MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + return debug_common(id, level, buf, len, 0); } /* - * debug_text_event: + * debug_exception_common: + * - write debug entry with given size and switch to next debug area */ -debug_entry_t *debug_text_event(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_exception_common(debug_info_t * id, int level, + const void *buf, int len) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - memset(active->data, 0, id->buf_size); - strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); - ASCEBC(active->data, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 0; - proceed_active_entry(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; - + return debug_common(id, level, buf, len, 1); } /* - * debug_exception: + * counts arguments in format string for sprintf view */ -debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, - int len) +extern inline int debug_count_numargs(char *string) { - long flags; - debug_entry_t *active = NULL; + int numargs=0; - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(active->data, 0, id->buf_size); - memcpy(active->data, buf, MIN(len, id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + while(*string) { + if(*string++=='%') + numargs++; + } + return(numargs); } /* - * debug_int_exception: + * debug_sprintf_event: */ -debug_entry_t *debug_int_exception(debug_info_t * id, int level, - unsigned int tag) +debug_entry_t *debug_sprintf_event(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - active->id.fields.exception = 1; - memset(active->data, 0, id->buf_size); - memcpy(active->data, &tag, - MIN(sizeof(unsigned int), id->buf_size)); - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idxargs[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,0); + va_end(ap); + } + return retval; + } } /* - * debug_text_exception: + * debug_sprintf_exception: */ -debug_entry_t *debug_text_exception(debug_info_t * id, int level, - const char *txt) +debug_entry_t *debug_sprintf_exception(debug_info_t* id, + int level,char *string,...) { - long flags; - debug_entry_t *active = NULL; - - if ((!id) || (level < id->level)) - goto out; - spin_lock_irqsave(&id->lock, flags); - active = debug_common(id); - memset(active->data, 0, id->buf_size); - strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); - ASCEBC(active->data, MIN(strlen(txt), id->buf_size)); - active->id.fields.exception = 1; - proceed_active_entry(id); - proceed_active_area(id); - spin_unlock_irqrestore(&id->lock, flags); - out: - return active; + va_list ap; + int numargs,alloc_size,idx; + debug_sprintf_entry *curr_event; + debug_entry_t *retval = NULL; + if((!id) || (level > id->level)) + return NULL; + else { + numargs=debug_count_numargs(string); + alloc_size=offsetof(debug_sprintf_entry,args[numargs]); + curr_event=alloca(alloc_size); + + if(curr_event){ + va_start(ap,string); + curr_event->string=string; + for(idx=0;idxargs[idx]=va_arg(ap,long); + retval=debug_common(id,level, curr_event,alloc_size,1); + va_end(ap); + } + return retval; + } } /* @@ -821,7 +890,6 @@ debug_entry_t *debug_text_exception(debug_info_t * id, int level, int debug_init(void) { int rc = 0; - int i; down(&debug_lock); if (!initialized) { @@ -830,15 +898,7 @@ int debug_init(void) S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP, NULL, NULL); - for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) { - *(debug_info_t **) (&debug_areas[i]) = - (debug_info_t *) (&debug_areas[i + 1]); - } - *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL; - free_area = &(debug_areas[0]); - printk(KERN_INFO - "debug: %d areas reserved for debugging information\n", - DEBUG_MAX_AREAS); + printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; } up(&debug_lock); @@ -854,7 +914,7 @@ int debug_register_view(debug_info_t * id, struct debug_view *view) { int rc = 0; int i; - long flags; + unsigned long flags; mode_t mode = S_IFREG; if (!id) @@ -897,7 +957,7 @@ int debug_unregister_view(debug_info_t * id, struct debug_view *view) { int rc = 0; int i; - long flags; + unsigned long flags; if (!id) goto out; @@ -933,12 +993,8 @@ static int debug_prolog_level_fn(debug_info_t * id, { int rc = 0; - if (out_buf == NULL) { - rc = 2; - goto out; - } - rc = sprintf(out_buf, "%i\n", id->level); - out: + if(id->level == -1) rc = sprintf(out_buf,"-\n"); + else rc = sprintf(out_buf, "%i\n", id->level); return rc; } @@ -955,20 +1011,15 @@ static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, if (*offset != 0) goto out; - if ((rc = copy_from_user(input_buf, user_buf, 1))) + if (copy_from_user(input_buf, user_buf, 1)){ + rc = -EFAULT; goto out; + } if (isdigit(input_buf[0])) { int new_level = ((int) input_buf[0] - (int) '0'); - if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { - printk(KERN_INFO - "debug: level %i is out of range (%i - %i)\n", - new_level, 0, DEBUG_MAX_LEVEL); - } else { - id->level = new_level; - printk(KERN_INFO - "debug: set new level %i for %s\n", - id->level, id->name); - } + debug_set_level(id, new_level); + } else if(input_buf[0] == '-') { + debug_set_level(id, DEBUG_OFF_LEVEL); } else { printk(KERN_INFO "debug: level `%c` is not valid\n", input_buf[0]); @@ -979,72 +1030,55 @@ static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, } /* - * prints debug data in hex format + * prints debug header in raw format */ -static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf) +int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) { - int i, rc = 0; + int rc; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size * 3; - goto out; - } - for (i = 0; i < id->buf_size; i++) { - rc += sprintf(out_buf + rc, "%02x ", - ((unsigned char *) in_buf)[i]); - } - out: - return rc; + rc = sizeof(debug_entry_t); + memcpy(out_buf,entry,sizeof(debug_entry_t)); + return rc; } /* - * prints debug data in ascii format + * prints debug data in raw format */ -static int debug_ascii_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf) +static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) { - int i, rc = 0; + int rc; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size; - goto out; - } - for (i = 0; i < id->buf_size; i++) { - unsigned char c = in_buf[i]; - if (!isprint(c)) - rc += sprintf(out_buf + rc, "."); - else - rc += sprintf(out_buf + rc, "%c", c); - } - out: + rc = id->buf_size; + memcpy(out_buf, in_buf, id->buf_size); return rc; } /* - * prints debug data in ebcdic format + * prints debug data in hex/ascii format */ -static int debug_ebcdic_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf) +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) { int i, rc = 0; - if (out_buf == NULL || in_buf == NULL) { - rc = id->buf_size; - goto out; - } + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + rc += sprintf(out_buf + rc, "| "); for (i = 0; i < id->buf_size; i++) { unsigned char c = in_buf[i]; - EBCASC(&c, 1); if (!isprint(c)) rc += sprintf(out_buf + rc, "."); else rc += sprintf(out_buf + rc, "%c", c); } - out: + rc += sprintf(out_buf + rc, "\n"); return rc; } @@ -1060,12 +1094,9 @@ int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, char *except_str; unsigned long caller; int rc = 0; + unsigned int level; - if (out_buf == NULL) { - rc = DEBUG_PROC_HEADER_SIZE; - goto out; - } - + level = entry->id.fields.level; time = entry->id.stck; /* adjust todclock to 1970 */ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); @@ -1076,14 +1107,61 @@ int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, else except_str = "-"; caller = (unsigned long) entry->caller; -#if defined(CONFIG_ARCH_S390) +#if defined(CONFIG_ARCH_S390X) + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); +#else caller &= 0x7fffffff; - rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ", - area, time_val.tv_sec, - time_val.tv_usec, except_str, - entry->id.fields.cpuid, caller); + rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx ", + area, time_val.tv_sec, time_val.tv_usec, level, + except_str, entry->id.fields.cpuid, caller); #endif - out: + return rc; +} + +/* + * prints debug data sprintf-formated: + * debug_sprinf_event/exception calls must be used together with this view + */ + +#define DEBUG_SPRINTF_MAX_ARGS 10 + +int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry *curr_event) +{ + int num_longs, num_used_args = 0,i, rc = 0; + int index[DEBUG_SPRINTF_MAX_ARGS]; + + /* count of longs fit into one entry */ + num_longs = id->buf_size / sizeof(long); + + if(num_longs < 1) + goto out; /* bufsize of entry too small */ + if(num_longs == 1) { + /* no args, we use only the string */ + strcpy(out_buf, curr_event->string); + rc = strlen(curr_event->string); + goto out; + } + + /* number of arguments used for sprintf (without the format string) */ + num_used_args = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1)); + + memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int)); + + for(i = 0; i < num_used_args; i++) + index[i] = i; + + rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]], + curr_event->args[index[1]], curr_event->args[index[2]], + curr_event->args[index[3]], curr_event->args[index[4]], + curr_event->args[index[5]], curr_event->args[index[6]], + curr_event->args[index[7]], curr_event->args[index[8]], + curr_event->args[index[9]]); + +out: + return rc; } @@ -1118,3 +1196,17 @@ void cleanup_module(void) } #endif /* MODULE */ + +EXPORT_SYMBOL(debug_register); +EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_set_level); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); +EXPORT_SYMBOL(debug_event_common); +EXPORT_SYMBOL(debug_exception_common); +EXPORT_SYMBOL(debug_hex_ascii_view); +EXPORT_SYMBOL(debug_raw_view); +EXPORT_SYMBOL(debug_dflt_header_fn); +EXPORT_SYMBOL(debug_sprintf_view); +EXPORT_SYMBOL(debug_sprintf_exception); +EXPORT_SYMBOL(debug_sprintf_event); diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c index fc774064918d..52d5a78b5708 100644 --- a/arch/s390/kernel/ebcdic.c +++ b/arch/s390/kernel/ebcdic.c @@ -9,6 +9,7 @@ * Martin Peschke */ +#include #include /* @@ -389,3 +390,11 @@ __u8 _ebc_toupper[256] = 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + +EXPORT_SYMBOL_NOVERS(_ascebc_500); +EXPORT_SYMBOL_NOVERS(_ebcasc_500); +EXPORT_SYMBOL_NOVERS(_ascebc); +EXPORT_SYMBOL_NOVERS(_ebcasc); +EXPORT_SYMBOL_NOVERS(_ebc_tolower); +EXPORT_SYMBOL_NOVERS(_ebc_toupper); + diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index a5b125e4e7e1..5bc1af0f163b 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -148,11 +148,11 @@ sysc_dn: xc 0(4,%r15),0(%r15) ; /* clear back chain */ #define RESTORE_ALL \ - mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ + mvc __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ - ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \ - lpsw __LC_RETURN_PSW /* back to caller */ + lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ + ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ + lpsw __LC_RETURN_PSW /* back to caller */ #define GET_CURRENT /* load pointer to task_struct to R9 */ \ lr %r9,%r15 ; \ diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 10693f696e8d..296163b52494 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -5,7 +5,7 @@ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com), - * Rob van der Heij + * Rob van der Heij (rvdhei@iae.nl) * * There are 5 different IPL methods * 1) load the image directly into ram at address 0 and do an PSW restart @@ -13,11 +13,18 @@ * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated) * 3) generate the tape ipl header, store the generated image on a tape * and ipl from it + * In case of SL tape you need to IPL 5 times to get past VOL1 etc * 4) generate the vm reader ipl header, move the generated image to the * VM reader (use option NOH!) and do a ipl from reader (VM only) * 5) direct call of start by the SALIPL loader * We use the cpuid to distinguish between VM and native ipl * params for kernel are pushed to 0x10400 (see setup.h) + + Changes: + Okt 25 2000 + added code to skip HDR and EOF to allow SL tape IPL (5 retries) + changed first CCW from rewind to backspace block + */ #include @@ -32,7 +39,7 @@ #define IPL_BS 1024 .org 0 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded - .long 0x07000000,0x60000001 # by ipl to addresses 0-23. + .long 0x27000000,0x60000001 # by ipl to addresses 0-23. .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs). .long 0x00000000,0x00000000 # external old psw .long 0x00000000,0x00000000 # svc old psw @@ -140,7 +147,7 @@ .Lcrash:.long 0x000a0000,0x00000000 .Lldret:.long 0 .Lsnsret: .long 0 -#endif /* CONFIG_IPL_NONE */ +#endif /* CONFIG_IPL_TAPE */ #ifdef CONFIG_IPL_VM #define IPL_BS 0x730 @@ -260,6 +267,7 @@ iplstart: # # load parameter file from ipl device # +.Lagain1: l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp bas %r14,.Lloader # load parameter file ltr %r2,%r2 # got anything ? @@ -269,6 +277,10 @@ iplstart: la %r2,895 .Lnotrunc: l %r4,INITRD_START-PARMAREA(%r12) + clc 0(3,%r4),.L_hdr # if it is HDRx + bz .Lagain1 # skip dataset header + clc 0(3,%r4),.L_eof # if it is EOFx + bz .Lagain1 # skip dateset trailer la %r5,0(%r4,%r2) lr %r3,%r2 .Lidebc: @@ -306,6 +318,7 @@ iplstart: # # load ramdisk from ipl device # +.Lagain2: l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk bas %r14,.Lloader # load ramdisk st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk @@ -313,6 +326,12 @@ iplstart: bnz .Lrdcont st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it .Lrdcont: + l %r2,INITRD_START-PARMAREA(%r12) + + clc 0(3,%r2),.L_hdr # skip HDRx and EOFx + bz .Lagain2 + clc 0(3,%r2),.L_eof + bz .Lagain2 #ifdef CONFIG_IPL_VM # @@ -340,7 +359,8 @@ iplstart: .Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" - +.L_eof: .long 0xc5d6c600 /* C'EOF' */ +.L_hdr: .long 0xc8c4d900 /* C'HDR' */ #endif /* CONFIG_IPL */ # @@ -375,7 +395,7 @@ start: .long 0x83300060 # diag 3,0,x'0060' - storage size b .done .test: - mvc 0x68(8,0),.pgmnw # set up pgm check handler + mvc 0x68(8),.pgmnw # set up pgm check handler l %r2,.fourmeg lr %r3,%r2 bctr %r3,%r0 # 4M-1 @@ -443,7 +463,7 @@ startup:basr %r13,0 # get base # # find out memory size. # - mvc 104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler slr %r1,%r1 lhi %r2,1 sll %r2,20 @@ -507,7 +527,7 @@ startup:basr %r13,0 # get base # # find out if we have an IEEE fpu # - mvc 104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0 ldr %f2,%f0 adbr %f0,%f2 # test IEEE add instruction @@ -517,7 +537,7 @@ startup:basr %r13,0 # get base # # find out if we have the CSP instruction # - mvc 104(8,0),.Lpccsp-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler la %r0,0 lr %r1,%r0 la %r2,.Lflt0-.LPG1(%r13) diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 283257441e97..f523c12bfc25 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -11,6 +11,7 @@ * S/390 I/O interrupt processing and I/O request processing is * implemented in arch/s390/kernel/s390io.c */ +#include #include #include #include @@ -426,3 +427,12 @@ int request_irq( unsigned int irq, } +#ifdef CONFIG_SMP +EXPORT_SYMBOL(s390_bh_lock); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(synchronize_bh); +#endif diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 896355ce8da4..c30fe433c42f 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -16,7 +16,7 @@ do_reipl: basr %r13,0 ni .Lctlsave-.Lpg0(%r13),0xef lctl %c0,%c0,.Lctlsave-.Lpg0(%r13) lr %r1,%r2 - mvc __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13) + mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13) stsch .Lschib-.Lpg0(%r13) oi .Lschib+5-.Lpg0(%r13),0x84 .Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 @@ -24,9 +24,9 @@ do_reipl: basr %r13,0 ssch .Liplorb-.Lpg0(%r13) jz .L001 bas %r14,.Ldisab-.Lpg0(%r13) -.L001: mvc __LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13) +.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13) .Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13) -.Lcont: c %r1,__LC_SUBCHANNEL_ID(%r0) +.Lcont: c %r1,__LC_SUBCHANNEL_ID jnz .Ltpi clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13) jnz .Ltpi @@ -38,7 +38,7 @@ do_reipl: basr %r13,0 jz .L003 bas %r14,.Ldisab-.Lpg0(%r13) .L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID(%r0) + st %r1,__LC_SUBCHANNEL_ID lpsw 0 sigp 0,0,0(6) .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index 8f2ae4d6f0b0..16a0c3e9b63a 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -74,4 +75,6 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) { return 0; } +EXPORT_SYMBOL(register_external_interrupt); +EXPORT_SYMBOL(unregister_external_interrupt); diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 410cd597b094..0090d5150a23 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -3,72 +3,14 @@ * * S390 version */ -#include #include -#include -#include #include -#include -#include -#include #include -#include -#include -#include -#include #include #if CONFIG_IP_MULTICAST #include #endif -/* - * I/O subsystem - */ -EXPORT_SYMBOL(halt_IO); -EXPORT_SYMBOL(clear_IO); -EXPORT_SYMBOL(do_IO); -EXPORT_SYMBOL(resume_IO); -EXPORT_SYMBOL(ioinfo); -EXPORT_SYMBOL(get_dev_info_by_irq); -EXPORT_SYMBOL(get_dev_info_by_devno); -EXPORT_SYMBOL(get_irq_by_devno); -EXPORT_SYMBOL(get_devno_by_irq); -EXPORT_SYMBOL(get_irq_first); -EXPORT_SYMBOL(get_irq_next); -EXPORT_SYMBOL(read_conf_data); -EXPORT_SYMBOL(read_dev_chars); -EXPORT_SYMBOL(s390_request_irq_special); -EXPORT_SYMBOL(s390_device_register); -EXPORT_SYMBOL(s390_device_unregister); - -#ifdef __SMP__ -EXPORT_SYMBOL(s390_bh_lock); -#endif - -EXPORT_SYMBOL(ccw_alloc_request); -EXPORT_SYMBOL(ccw_free_request); - -EXPORT_SYMBOL(register_external_interrupt); -EXPORT_SYMBOL(unregister_external_interrupt); - -/* - * debug feature - */ -EXPORT_SYMBOL(debug_register); -EXPORT_SYMBOL(debug_unregister); -EXPORT_SYMBOL(debug_register_view); -EXPORT_SYMBOL(debug_unregister_view); -EXPORT_SYMBOL(debug_event); -EXPORT_SYMBOL(debug_int_event); -EXPORT_SYMBOL(debug_text_event); -EXPORT_SYMBOL(debug_exception); -EXPORT_SYMBOL(debug_int_exception); -EXPORT_SYMBOL(debug_text_exception); -EXPORT_SYMBOL(debug_hex_view); -EXPORT_SYMBOL(debug_ascii_view); -EXPORT_SYMBOL(debug_ebcdic_view); -EXPORT_SYMBOL(debug_dflt_header_fn); - /* * memory management */ @@ -94,32 +36,12 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL_NOVERS(strstr); -EXPORT_SYMBOL_NOVERS(_ascebc_500); -EXPORT_SYMBOL_NOVERS(_ebcasc_500); -EXPORT_SYMBOL_NOVERS(_ascebc); -EXPORT_SYMBOL_NOVERS(_ebcasc); -EXPORT_SYMBOL_NOVERS(_ebc_tolower); -EXPORT_SYMBOL_NOVERS(_ebc_toupper); - /* * misc. */ EXPORT_SYMBOL(__copy_from_user_fixup); EXPORT_SYMBOL(__copy_to_user_fixup); EXPORT_SYMBOL(__udelay); -#ifdef CONFIG_SMP -#include -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(synchronize_bh); -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(smp_ctl_set_bit); -EXPORT_SYMBOL(smp_ctl_clear_bit); -EXPORT_SYMBOL(smp_do_callback_all); -#endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(genhd_dasd_name); diff --git a/arch/s390/kernel/s390dyn.c b/arch/s390/kernel/s390dyn.c index b40201d3f80d..7ad948a041f2 100644 --- a/arch/s390/kernel/s390dyn.c +++ b/arch/s390/kernel/s390dyn.c @@ -7,6 +7,7 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) */ +#include #include #include @@ -204,3 +205,5 @@ devreg_t * s390_search_devreg( ioinfo_t *ioinfo ) return( pdevreg); } +EXPORT_SYMBOL(s390_device_register); +EXPORT_SYMBOL(s390_device_unregister); diff --git a/arch/s390/kernel/s390io.c b/arch/s390/kernel/s390io.c index f256d03f6ea8..e8cacde4720d 100644 --- a/arch/s390/kernel/s390io.c +++ b/arch/s390/kernel/s390io.c @@ -8,6 +8,7 @@ * Author(s): Ingo Adlung (adlung@de.ibm.com) */ +#include #include #include #include @@ -126,7 +127,7 @@ int s390_request_irq_special( int irq, not_oper_handler_func_t not_oper_handler, unsigned long irqflags, const char *devname, - void *dev_id) + devstat_t *dev_id) { int retval; struct s390_irqaction *action; @@ -204,7 +205,7 @@ int s390_request_irq( unsigned int irq, NULL, irqflags, devname, - dev_id); + (devstat_t *)dev_id); if ( ret == 0 ) { @@ -2041,6 +2042,7 @@ int s390_process_IRQ( unsigned int irq ) int ending_status = 0; int allow4handler = 1; int chnchk = 0; + devstat_t *dp; #if 0 int cpu = smp_processor_id(); @@ -2058,7 +2060,8 @@ int s390_process_IRQ( unsigned int irq ) action = ioinfo[irq]->irq_desc.action; } /* endif */ - + dp = &ioinfo[irq]->devstat; + #ifdef CONFIG_DEBUG_IO /* * It might be possible that a device was not-oper. at the time @@ -2176,8 +2179,22 @@ int s390_process_IRQ( unsigned int irq ) chnchk = 1; } /* endif */ + if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) + && (dp->ii.irb.scsw.eswf == 0 )) + { + issense = 0; + } + else if ( (dp->ii.irb.scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) + && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)) + { + issense = 0; + } + else + { + issense = dp->ii.irb.esw.esw0.erw.cons; - issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons; + } /* endif */ if ( issense ) { @@ -5524,3 +5541,17 @@ reipl ( int sch ) do_reipl( 0x10000 | sch ); } +EXPORT_SYMBOL(halt_IO); +EXPORT_SYMBOL(clear_IO); +EXPORT_SYMBOL(do_IO); +EXPORT_SYMBOL(resume_IO); +EXPORT_SYMBOL(ioinfo); +EXPORT_SYMBOL(get_dev_info_by_irq); +EXPORT_SYMBOL(get_dev_info_by_devno); +EXPORT_SYMBOL(get_irq_by_devno); +EXPORT_SYMBOL(get_devno_by_irq); +EXPORT_SYMBOL(get_irq_first); +EXPORT_SYMBOL(get_irq_next); +EXPORT_SYMBOL(read_conf_data); +EXPORT_SYMBOL(read_dev_chars); +EXPORT_SYMBOL(s390_request_irq_special); diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 121c0155f6a7..af7f4b35336d 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -327,6 +327,11 @@ static void setup_frame(int sig, struct k_sigaction *ka, #endif /* Martin wants this for pthreads */ regs->gprs[3] = (addr_t)&frame->sc; + + /* We forgot to include these in the sigcontext. + To avoid breaking binary compatibility, they are passed as args. */ + regs->gprs[4] = current->tss.trap_no; + regs->gprs[5] = current->tss.prot_addr; return; give_sigsegv: @@ -383,7 +388,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { /* Are we from a system call? */ - if (regs->orig_gpr2 >= 0) { + if (regs->trap == __LC_SVC_OLD_PSW) { /* If so, check system call restarting.. */ switch (regs->gprs[2]) { case -ERESTARTNOHAND: diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2e36f6800e7c..7d4963c2bf48 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -721,3 +722,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs) } } +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_do_callback_all); diff --git a/arch/s390/lib/strcmp.S b/arch/s390/lib/strcmp.S index d3f63942fa71..340edffb5bab 100644 --- a/arch/s390/lib/strcmp.S +++ b/arch/s390/lib/strcmp.S @@ -18,8 +18,8 @@ strcmp: CLST 2,3 JO .-4 JE strcmp_equal - IC 0,0(0,3) - IC 1,0(0,2) + IC 0,0(3) + IC 1,0(2) SR 1,0 strcmp_equal: LR 2,1 diff --git a/arch/s390/lib/strncpy.S b/arch/s390/lib/strncpy.S index 0524cee65f31..c0e27a50db0c 100644 --- a/arch/s390/lib/strncpy.S +++ b/arch/s390/lib/strncpy.S @@ -20,9 +20,9 @@ strncpy: SR 0,0 strncpy_loop: ICM 0,1,0(3) # ICM sets the cc, IC does not - LA 3,1(0,3) - STC 0,0(0,1) - LA 1,1(0,1) + LA 3,1(3) + STC 0,0(1) + LA 1,1(1) JZ strncpy_exit # ICM inserted a 0x00 BRCT 4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0 strncpy_exit: diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 7a3cc5cb6d4e..e885481950c7 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -141,7 +141,7 @@ int do_check_pgt_cache(int low, int high) if(pgtable_cache_size > high) { do { if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; + free_pgd_slow(get_pgd_fast()), freed += 2; if(pmd_quicklist) free_pmd_slow(get_pmd_fast()), freed++; if(pte_quicklist) diff --git a/arch/s390/tools/dasdfmt/dasdfmt.c b/arch/s390/tools/dasdfmt/dasdfmt.c index 3ad43ba2b2f1..3489a49d8a17 100644 --- a/arch/s390/tools/dasdfmt/dasdfmt.c +++ b/arch/s390/tools/dasdfmt/dasdfmt.c @@ -201,7 +201,7 @@ get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode) /* fgets(line,sizeof(line),file); omit first line */ while (fgets(line,sizeof(line),file)!=NULL) { - rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i); + rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i); ma=ma_i; mi=mi_i; if ( (rc==3) && @@ -219,7 +219,8 @@ get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode) fclose(file); ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \ - "filesystem (are you sure to have the right param line?)\n", + "filesystem (are you sure to have the right parameter " \ + "dasd=xxx?)\n", prog_name); } diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index bb1ee3e69ea9..bfa99203c921 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -1792,7 +1792,7 @@ __initfunc(void device_setup(void)) } #ifdef CONFIG_PROC_FS -int get_partition_list(char * page) +int get_partition_list(char *page, char **start, off_t offset, int count) { struct gendisk *p; char buf[MAX_DISKNAME_LEN]; @@ -1801,14 +1801,23 @@ int get_partition_list(char * page) len = sprintf(page, "major minor #blocks name\n\n"); for (p = gendisk_head; p; p = p->next) { for (n=0; n < (p->nr_real << p->minor_shift); n++) { - if (p->part[n].nr_sects && len < PAGE_SIZE - 80) { + if (p->part[n].nr_sects) { len += sprintf(page+len, "%4d %4d %10d %s\n", p->major, n, p->sizes[n], disk_name(p, n, buf)); + if (len < offset) + offset -= len, len = 0; + else if (len >= offset + count) + goto leave_loops; } } } - return len; +leave_loops: + *start = page + offset; + len -= offset; + if (len < 0) + len = 0; + return len > count ? count : len; } #endif diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 71e3a3f527e1..982f93ad78d3 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -16,9 +16,7 @@ bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then bool ' Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX fi - -# CONFIG_X25 is defined only when CONFIG_EXPERIMENTAL=y -if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X25" != "n" ]; then +if [ "$CONFIG_X25" != "n" ]; then bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25 fi @@ -91,9 +89,18 @@ dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN dep_tristate 'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN dep_tristate 'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN -dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN +bool 'Eicon active card support' CONFIG_ISDN_DRV_EICON if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then - bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then + dep_tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN + fi + if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then + dep_tristate ' Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN + if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then + dep_bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI + bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA + fi + fi fi # CAPI subsystem diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index d2663a87d35a..dbcbdf22ddfa 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -32,7 +32,7 @@ obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o # Object files in subdirectories -mod-subdirs := avmb1 +mod-subdirs := avmb1 eicon subdir-$(CONFIG_ISDN_DIVERSION) += divert subdir-$(CONFIG_ISDN_DRV_HISAX) += hisax subdir-$(CONFIG_ISDN_DRV_ICN) += icn diff --git a/drivers/isdn/eicon/Divas_mod.c b/drivers/isdn/eicon/Divas_mod.c new file mode 100644 index 000000000000..14fdef0c498e --- /dev/null +++ b/drivers/isdn/eicon/Divas_mod.c @@ -0,0 +1,151 @@ + +/* + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#include +#include +#undef N_DATA + +#include + +#include +#include +#include +#include +#include + +#include "adapter.h" +#include "uxio.h" + +#include + +#ifdef MODULE +#include "idi.h" +void DIVA_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#endif + +int DivasCardsDiscover(void); + +static int __init +divas_init(void) +{ + printk(KERN_DEBUG "DIVA Server Driver - initialising\n"); + + printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.16\n"); + + +#if !defined(CONFIG_PCI) + printk(KERN_WARNING "CONFIG_PCI is not defined!\n"); + return -ENODEV; +#endif + + if (pci_present()) + { + if (DivasCardsDiscover() < 0) + { + printk(KERN_WARNING "Divas: Not loaded\n"); + return -ENODEV; + } + } + else + { + printk(KERN_WARNING "Divas: No PCI bus present\n"); + return -ENODEV; + } + + return 0; +} + +static void +divas_exit(void) +{ + card_t *pCard; + word wCardIndex; + extern int Divas_major; + + printk(KERN_DEBUG "DIVA Server Driver - unloading\n"); + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + pCard++; + } + + unregister_chrdev(Divas_major, "Divas"); +} + +module_init(divas_init); +module_exit(divas_exit); + diff --git a/drivers/isdn/eicon/Makefile b/drivers/isdn/eicon/Makefile index 41ea25adf251..824de2a3a48a 100644 --- a/drivers/isdn/eicon/Makefile +++ b/drivers/isdn/eicon/Makefile @@ -6,20 +6,37 @@ O_TARGET := vmlinux-obj.o # Objects that export symbols. -export-objs := eicon_mod.o +export-objs := Divas_mod.o eicon_mod.o # Multipart objects. -list-multi := eicon.o -eicon-objs := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o +list-multi := eicon.o divas.o +eicon-objs := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \ + eicon_io.o +divas-objs := common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \ + fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o + +# Optional parts of multipart objects. + +eicon-objs-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \ + xlog.o kprintf.o fpga.o fourbri.o lincfg.o linchr.o \ + linsys.o linio.o + +eicon-objs += $(eicon-objs-y) # Each configuration option enables a list of files. -obj-$(CONFIG_ISDN_DRV_EICON) += eicon.o +obj-$(CONFIG_ISDN_DRV_EICON_OLD) += eicon.o +obj-$(CONFIG_ISDN_DRV_EICON_DIVAS) += divas.o -include $(TOPDIR)/Rules.make +include $(TOPDIR)/drivers/isdn/Rules.make # Link rules for multi-part drivers. eicon.o: $(eicon-objs) $(LD) -r -o $@ $(eicon-objs) + +divas.o: $(divas-objs) + $(LD) -r -o $@ $(divas-objs) + + diff --git a/drivers/isdn/eicon/adapter.h b/drivers/isdn/eicon/adapter.h new file mode 100644 index 000000000000..e8a37498c32d --- /dev/null +++ b/drivers/isdn/eicon/adapter.h @@ -0,0 +1,262 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.7 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Main internal include file for Diva Server driver */ + +#if !defined(ADAPTER_H) +#define ADAPTER_H + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" + +#define XMOREC 0x1f +#define XMOREF 0x20 +#define XBUSY 0x40 +#define RMORE 0x80 + + /* structure for all information we have to keep on a per */ + /* adapater basis */ + +typedef struct adapter_s ADAPTER; + +struct adapter_s { + void * io; + + byte IdTable[256]; + byte ReadyInt; + + byte (* ram_in)(ADAPTER * a, void * adr); + word (* ram_inw)(ADAPTER * a, void * adr); + void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length); + void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e); + + void (* ram_out)(ADAPTER * a, void * adr, byte data); + void (* ram_outw)(ADAPTER * a, void * adr, word data); + void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length); + + void (* ram_inc)(ADAPTER * a, void * adr); +}; + +typedef struct card card_t; + +typedef int card_load_fn_t(card_t *card, dia_load_t *load); +typedef int card_config_fn_t(card_t *card, dia_config_t *config); +typedef int card_start_fn_t(card_t *card, byte *channels); +typedef int card_reset_fn_t(card_t *card); +typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block); + +#define MAX_PENTITIES 256 /* Number of entities primary adapter */ +#define MAX_ENTITIES 16 /* Number of entities standard adapter */ + +typedef struct e_info_s E_INFO; + +struct e_info_s +{ + ENTITY *e; /* entity pointer */ + byte next; /* chaining index */ + word assign_ref; /* assign reference */ +}; + +/* DIVA card info (details hidden from user) */ + +typedef struct ux_diva_card_s ux_diva_card_t; + +/* card info */ + +struct card +{ + ADAPTER a; /* per-adapter information */ + dia_card_t cfg; /* card configuration */ + int state; /* State of the adapter */ + dword serial_no; /* serial number */ + int test_int_pend; /* set for interrupt testing */ + ux_diva_card_t *hw; /* O/S-specific handle */ + card_reset_fn_t *card_reset; /* call this to reset card */ + card_load_fn_t *card_load; /* call this to load card */ + card_config_fn_t *card_config; /* call this to config card */ + card_start_fn_t *card_start; /* call this to start card */ + card_mem_get_fn_t *card_mem_get; /* call this to get card memory */ + E_INFO *e_tbl; /* table of ENTITY pointers */ + byte e_head; /* list of active ENTITIES */ + byte e_tail; /* list of active ENTITIES */ + int e_count; /* # of active ENTITIES */ + int e_max; /* total # of ENTITIES */ + byte assign; /* assign queue entry */ + PBUFFER RBuffer; /* Copy of receive lookahead buffer */ + int log_types; /* bit-mask of active logs */ + word xlog_offset; /* offset to XLOG buffer on card */ + void (*out)(ADAPTER *a); + byte (*dpc)(ADAPTER * a); + byte (*test_int)(ADAPTER * a); + void (*clear_int)(ADAPTER * a); + void (*reset_int)(card_t *c); + int is_live; + + int (*card_isr)(card_t *card); + + int int_pend; /* interrupt pending */ + long interrupt_reentered; + long dpc_reentered; + int set_xlog_request; + +} ; + +/* card information */ + +#define MAX_CARDS 20 /* max number of cards on a system */ + +extern +card_t DivasCards[]; + +extern +int DivasCardNext; + +extern +dia_config_t DivasCardConfigs[]; + +extern +byte DivasFlavourConfig[]; + +/*------------------------------------------------------------------*/ +/* public functions of IDI common code */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a); +byte DivasDpc(ADAPTER * a); +byte DivasTestInt(ADAPTER * a); +void DivasClearInt(ADAPTER * a); + +/*------------------------------------------------------------------*/ +/* public functions of configuration platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasConfigGet(dia_card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of LOG related code */ +/*------------------------------------------------------------------*/ + +void DivasXlogReq(int card_num); +int DivasXlogRetrieve(card_t *card); +void DivasLog(dia_log_t *log); +void DivasLogIdi(card_t *card, ENTITY *e, int request); + +/*------------------------------------------------------------------*/ +/* public functions to initialise cards for each type supported */ +/*------------------------------------------------------------------*/ + +int DivasPriInit(card_t *card, dia_card_t *cfg); + +int DivasBriInit(card_t *card, dia_card_t *cfg); +int Divas4BriInit(card_t *card, dia_card_t *cfg); +void DivasBriPatch(card_t *card); + +/*------------------------------------------------------------------*/ +/* public functions of log common code */ +/*------------------------------------------------------------------*/ + +extern char *DivasLogFifoRead(void); +extern void DivasLogFifoWrite(char *entry, int length); +extern int DivasLogFifoEmpty(void); +extern int DivasLogFifoFull(void); +extern void DivasLogAdd(void *buffer, int length); + +/*------------------------------------------------------------------*/ +/* public functions of misc. platform-specific code */ +/*------------------------------------------------------------------*/ + +int DivasDpcSchedule(void); +void DivasDoDpc(void *); +void DivasDoRequestDpc(void *pData); +int DivasScheduleRequestDpc(void); + +/* table of IDI request functions */ + +extern +IDI_CALL DivasIdiRequest[]; + +/* + * intialisation entry point + */ + +int DivasInit(void); + +/* + * Get information on the number and type of cards present + */ + +extern +int DivasCardsDiscover(void); + +/* + * initialise a new card + */ + +int DivasCardNew(dia_card_t *card); + +/* + * configure specified card + */ + +int DivasCardConfig(dia_config_t *config); + +/* + * load specified binary code onto card + */ + +int DivasCardLoad(dia_load_t *load); + +/* + * start specified card running + */ + +int DivasCardStart(int card_id); + +/* + * ISR for card + * Returns 0 if specified card was interrupting + */ + +int DivasIsr(void *arg); + +/* + * Get number of active cards + */ + +int DivasGetNum(void); + +/* + * Get list of active cards + */ + +int DivasGetList(dia_card_list_t *card_list); + +/* definitions common to several card types */ + +#define DIVAS_SHARED_OFFSET (0x1000) + +#endif /* ADAPTER_H */ diff --git a/drivers/isdn/eicon/bri.c b/drivers/isdn/eicon/bri.c new file mode 100644 index 000000000000..3d2ed85c3649 --- /dev/null +++ b/drivers/isdn/eicon/bri.c @@ -0,0 +1,714 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.8 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_BADDR0 0x10 +#define PCI_BADDR1 0x14 +#define PCI_BADDR2 0x18 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for BRI card */ + +#define PROTCAP_TELINDUS 0x1 +#define PROTCAP_V90D 0x8 + +word GetProtFeatureValue(char *sw_id); +byte io_in(ADAPTER *a, void *adr); +word io_inw(ADAPTER *a, void *adr); +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void io_out(ADAPTER *a, void *adr, byte data); +void io_outw(ADAPTER *a, void *adr, word data); +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void io_inc(ADAPTER *a, void *adr); + +static int diva_server_bri_test_int(card_t *card); +static int bri_ISR (card_t* card); + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +#define REG_DATA 0x00 +#define REG_ADDRLO 0x04 +#define REG_ADDRHI 0x0C +#define REG_IOCTRL 0x10 + +#define M_PCI_RESET 0x10 + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg); + +static +int diva_server_bri_reset(card_t *card) +{ + byte *DivasIOBase; + word i; + dword dwWait; + + UxCardLog(0); + + DPRINTF(("divas: resetting BRI adapter")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0); + + for (i=0; i < 50000; i++) + ; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000); + + for (i=0; i<0x8000; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0); + } + + for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++) + ; + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +void diva_server_bri_reset_int(card_t *card) +{ + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +int diva_server_bri_start(card_t *card, byte *channels) +{ + byte *DivasIOBase, *PLXIOBase; + word wSig = 0; + word i; + dword dwSerialNum; + byte bPLX9060 = FALSE; + + DPRINTF(("divas: starting Diva Server BRI card")); + + card->is_live = FALSE; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08); + + /* wait for signature to indicate card has started */ + for (i = 0; i < 300; i++) + { + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E); + wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + if (wSig == DIVAS_SIGNATURE) + { + DPRINTF(("divas: card started after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if (wSig != DIVAS_SIGNATURE) + { + DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig)); + UxCardMemDetach(card->hw, DivasIOBase); + return -1; + } + + card->is_live = TRUE; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6); + *channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA); + + UxCardMemDetach(card->hw, DivasIOBase); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x22)); + DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum)); + } + else + { + dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) | + (UxCardPortIoInW(card->hw, PLXIOBase, 0x26)); + DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum)); + } + + UxCardMemDetach(card->hw, PLXIOBase); + + card->serial_no = dwSerialNum; + + diva_server_bri_test_int(card); + + return 0; +} + +static +int diva_server_bri_load(card_t *card, dia_load_t *load) +{ + byte *DivasIOBase; + dword r3000_base; + dword dwAddr, dwLength, i; + word wTest, aWord; + + DPRINTF(("divas: loading Diva Server BRI card")); + + switch (load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: loading RISC %s", &load->code[0x80])); + + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + DPRINTF(("divas: features 0x%x", card->hw->features)); + if (card->hw->features == 0xFFFF) + { + DPRINTF(("divas: invalid feature string failed load\n")); + return -1; + } + + r3000_base = 0; + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code \"%s\"", load->code)); + + if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS))) + { + DPRINTF(("divas: only Telindus style binaries supported")); + return -1; + } + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: V.90 DSP binary")); + r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + else + { + DPRINTF(("divas: non-V.90 DSP binary")); + r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC)); + } + DPRINTF(("divas: loading at 0x%x", r3000_base)); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000 + sizeof(dword); + } + else + { + r3000_base = 0xBF7A0000 + sizeof(dword); + } + + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + r3000_base = 0xBF790000; + } + else + { + r3000_base = 0xBF7A0000; + } + break; + + default: + DPRINTF(("divas: unknown code type %d", load->code_type)); + return -1; + break; + } + + DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + DPRINTF(("divas: Attached to 0x%04X", DivasIOBase)); + + dwLength = load->length; + + for (i=0; i < dwLength; i++) + { + dwAddr = r3000_base + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]); + } + + DPRINTF(("divas: Verifying")); + + for (i=0; ihw, DivasIOBase, REG_ADDRHI, dwAddr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr); + + wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + + aWord = load->code[i]; + + if (wTest != aWord) + { + DPRINTF(("divas: load verify failed on byte %d", i)); + DPRINTF(("divas: RAM 0x%x File 0x%x",wTest,aWord)); + + UxCardMemDetach(card->hw, DivasIOBase); + + return -1; + } + } + + DPRINTF(("divas: Loaded and verified. Detaching from adapter")); + + UxCardMemDetach(card->hw, DivasIOBase); + + UxCardLog(0); + + return 0; +} + +static +int diva_server_bri_config(card_t *card, dia_config_t *config) +{ + byte *DivasIOBase, i; + + DPRINTF(("divas: configuring Diva Server BRI card")); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->sig_flags); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4); + } + else + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + } + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21); + + for (i=0; i<32; i++) + { + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]); + + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]); + + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +void DivasBriPatch(card_t *card) +{ + dword PLXIOBase = 0; + dword DivasIOBase = 0; + + PLXIOBase = card->cfg.reset_base; + DivasIOBase = card->cfg.io_base; + + if(card->hw == NULL) + { + DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null")); + return; + } + + if (PLXIOBase == 0) + { + DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may")); + DPRINTF(("Divas: not function properly. If you do encounter problems,")); + DPRINTF(("Divas: ensure that your machine is using the latest BIOS.")); + return; + } + + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + + if (PLXIOBase & 0x80) + { + dword dwSize, dwSerialNum, dwCmd; + boolean_t bPLX9060; + word wSerHi, wSerLo; + + DPRINTF(("Divas: Patch required")); + dwCmd = 0; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + PLXIOBase &= ~0x80; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase); + + dwSize = 0xFFFFFFFF; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize); + UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize); + + dwSize = (~ (dwSize & ~7)) + 1; + + DivasIOBase = PLXIOBase + dwSize; + + card->cfg.reset_base = PLXIOBase; + card->cfg.io_base = DivasIOBase; + UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base); + UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base); + + dwCmd = 5; + UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + UxCardLog(0); + } + } + else + { + word wSerHi, wSerLo; + boolean_t bPLX9060; + dword dwSerialNum; + + DPRINTF(("divas: No patch required")); + + bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | + UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E); + + if (bPLX9060) + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + else + { + wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22); + wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26); + dwSerialNum = (wSerHi << 16) | wSerLo; + } + } + DPRINTF(("Divas: After patching:")); + DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase)); + DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase)); + +} + +#define TEST_INT_DIVAS_BRI 0x12 +static +int diva_server_bri_test_int(card_t *card) +{ + boolean_t bPLX9060 = FALSE; + byte *PLXIOBase = NULL, *DivasIOBase = NULL; + + DPRINTF(("divas: test interrupt for Diva Server BRI card")); + + PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE); + + bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E); + + if (bPLX9060) + { /* PLX9060 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09); + } + else + { /* PLX9050 */ + UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41); + } + + card->test_int_pend = TEST_INT_DIVAS_BRI; + + UxCardMemDetach(card->hw, PLXIOBase); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89); + + UxCardMemDetach(card->hw, DivasIOBase); + + return 0; +} + +static +int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block) +{ + dword user_addr = mem_block->addr; + word length = 0; + dword addr; + word i; + byte *DivasIOBase; + + DPRINTF(("divas: Retrieving memory from 0x%x", user_addr)); + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + addr = user_addr; + + for (i=0; i < (16 * 8); i++) + { + addr = user_addr + i; + + UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16); + UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr); + + mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA); + length++; + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return length; +} + +int DivasBriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server BRI card")); + + if (DivasBRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_bri_reset; + card->card_start = diva_server_bri_start; + card->card_load = diva_server_bri_load; + card->card_config = diva_server_bri_config; + card->reset_int = diva_server_bri_reset_int; + card->card_mem_get = diva_server_bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = bri_ISR; + + card->a.ram_out = io_out; + card->a.ram_outw = io_outw; + card->a.ram_out_buffer = io_out_buffer; + card->a.ram_inc = io_inc; + + card->a.ram_in = io_in; + card->a.ram_inw = io_inw; + card->a.ram_in_buffer = io_in_buffer; + card->a.ram_look_ahead = io_look_ahead; + + return 0; +} + +word GetProtFeatureValue(char *sw_id) +{ + word features = 0; + + while ((*sw_id) && (sw_id[0] != '[')) + sw_id++; + + if (sw_id == NULL) + { + DPRINTF(("divas: no feature string present")); + features = -1; + } + else + { + byte i, shifter; + + sw_id += 3; + + for (i=0, shifter=12; i<4; i++, shifter-=4) + { + if ((sw_id[i] >= '0') && (sw_id[i] <= '9')) + { + features |= (sw_id[i] - '0') << shifter; + } + else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f')) + { + features |= (sw_id[i] - 'a' + 10) << shifter; + } + else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F')) + { + features |= (sw_id[i] - 'A' + 10) << shifter; + } + else + { + DPRINTF(("divas: invalid feature string")); + return -1; + } + } + } + + return features; +} + + +int bri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +} + + diff --git a/drivers/isdn/eicon/common.c b/drivers/isdn/eicon/common.c new file mode 100644 index 000000000000..a5a35f3c8b29 --- /dev/null +++ b/drivers/isdn/eicon/common.c @@ -0,0 +1,896 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.15 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" + +#include "uxio.h" +#include + +#define MAX_ADDR_LEN + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_LATENCY 0x0D +#define PCI_INTERRUPT 0x3C + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_SIGNATURE 0x4447 + +#define MP_PROTOCOL_ADDR 0xA0011000 + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +int DivasCardNext; +card_t DivasCards[MAX_CARDS]; + +dia_config_t *DivasConfig(card_t *, dia_config_t *); + +static +DESCRIPTOR DIDD_Table[32]; + +void DIVA_DIDD_Read( DESCRIPTOR *table, int tablelength ) +{ + bzero(table, tablelength); + + if (tablelength > sizeof(DIDD_Table)) + tablelength = sizeof(DIDD_Table); + + if(tablelength % sizeof(DESCRIPTOR)) { + tablelength /= sizeof(DESCRIPTOR); + tablelength *= sizeof(DESCRIPTOR); + } + + if (tablelength > 0) + bcopy((caddr_t)DIDD_Table, (caddr_t)table, tablelength); + + return; +} + +void DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength) +{ + if (tablelength > sizeof(DIDD_Table)) + tablelength = sizeof(DIDD_Table); + + bcopy((caddr_t)table, (caddr_t)DIDD_Table, tablelength); + + return; +} + +static +void init_idi_tab(void) +{ + DESCRIPTOR d[32]; + + bzero(d, sizeof(d)); + + d[0].type = IDI_DIMAINT; /* identify the DIMAINT entry */ + d[0].channels = 0; /* zero channels associated with dimaint*/ + d[0].features = 0; /* no features associated with dimaint */ + d[0].request = (IDI_CALL) DivasPrintf; + + DIVA_DIDD_Write(d, sizeof(d)); + + return; +} + +/* + * I/O routines for memory mapped cards + */ + +byte mem_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + byte value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemIn(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +word mem_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + unsigned char *b, *m; + word value; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + + UxCardMemDetach(card->hw, b); + + return value; +} + +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemInBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (dword) &RBuffer->length; + card->RBuffer.length = UxCardMemInW(card->hw, m); + + m = b; + m += (dword) &RBuffer->P; + UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOut(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutW(card->hw, m, data); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + UxCardMemOutBuffer(card->hw, m, P, length); + + UxCardMemDetach(card->hw, b); + + return; +} + +void mem_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + unsigned char *b, *m; + + m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + m += (unsigned int) adr; + + value = UxCardMemInW(card->hw, m); + value++; + UxCardMemOutW(card->hw, m, value); + + UxCardMemDetach(card->hw, b); + + return; +} + +/* + * I/O routines for I/O mapped cards + */ + +byte io_in(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + byte value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoIn(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +word io_inw(ADAPTER *a, void *adr) +{ + card_t *card = a->io; + word value; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + UxCardMemDetach(card->hw, DivasIOBase); + + return value; +} + +void io_in_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer); + + UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length); + + UxCardMemDetach(card->hw, DivasIOBase); + + e->RBuffer = (DBUFFER *) &card->RBuffer; + + return; +} + +void io_out(ADAPTER *a, void *adr, byte data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOut(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_outw(ADAPTER *a, void *adr, word data) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutW(card->hw, DivasIOBase, adr, data); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_out_buffer(ADAPTER *a, void *adr, void *P, word length) +{ + card_t *card = a->io; + byte *DivasIOBase = NULL; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +void io_inc(ADAPTER *a, void *adr) +{ + word value; + card_t *card = a->io; + byte *DivasIOBase; + + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + value = UxCardIoInW(card->hw, DivasIOBase, adr); + + value++; + + UxCardIoOutW(card->hw, DivasIOBase, adr, value); + + UxCardMemDetach(card->hw, DivasIOBase); + + return; +} + +static +void test_int(card_t *card) + +{ + byte *shared, *DivasIOBase; + + switch (card->test_int_pend) + { + case TEST_INT_DIVAS: + DPRINTF(("divas: test interrupt pending")); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + if (UxCardMemIn(card->hw, &shared[0x3FE])) + { + UxCardMemOut(card->hw, + &(((struct pr_ram *)shared)->RcOutput), 0); + UxCardMemDetach(card->hw, shared); + (*card->reset_int)(card); + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + DPRINTF(("divas: test interrupt cleared")); + } + + UxCardMemDetach(card->hw, shared); + + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_BRI: + DPRINTF(("divas: BRI test interrupt pending")); + (*card->reset_int)(card); + DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0); + UxCardMemDetach(card->hw, DivasIOBase); + DPRINTF(("divas: test interrupt cleared")); + card->test_int_pend = 0; + break; + + case TEST_INT_DIVAS_Q: + DPRINTF(("divas: 4BRI test interrupt pending")); + (*card->reset_int)(card); + card->test_int_pend = 0; + break; + + default: + DPRINTF(("divas: unknown test interrupt pending")); + return; + } + return; +} + +void card_isr (void *dev_id) +{ + card_t *card = (card_t *) dev_id; + ADAPTER *a = &card->a; + int ipl; + + if (card->test_int_pend) + { + ipl = UxCardLock(card->hw); + card->int_pend=0; + test_int(card); + UxCardUnlock(card->hw,ipl); + return; + } + + if(card->card_isr) + { + (*(card->card_isr))(card); + } + else + { + ipl = UxCardLock(card->hw); + + if ((card->test_int)(a)) + { + (card->reset_int)(card); + } + + UxCardUnlock(card->hw,ipl); + + } + +} + +int DivasCardNew(dia_card_t *card_info) +{ + card_t *card; + byte b; + static boolean_t first_call = TRUE; + boolean_t NeedISRandReset = FALSE; + + DPRINTF(("divas: new card ")); + + if (first_call) + { + first_call = FALSE; + init_idi_tab(); + } + + DivasConfigGet(card_info); + + if (DivasCardNext == DIM(DivasCards)) + { + KDPRINTF((KERN_WARNING "Divas: no space available for new card")); + return -1; + } + + card = &DivasCards[DivasCardNext]; + + card->state = DIA_UNKNOWN; + + card->cfg = *card_info; + + card->a.io = card; + + if (UxCardHandleGet(&card->hw, card_info)) + { + KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card")); + return -1; + } + + if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + DivasBriPatch(card); + card_info->io_base = card->cfg.io_base; + } + + switch (card_info->card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + if (DivasPriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + if (DivasBriInit(card, card_info)) + { + return -1; + } + NeedISRandReset = TRUE; + break; + + case DIA_CARD_TYPE_DIVA_SERVER_Q: + if (Divas4BriInit(card, card_info)) + { + return -1; + } + + if (card_info->name[6] == '0') + { + NeedISRandReset = TRUE; + } + else // Need to set paramater for ISR anyway + { + card->hw->user_isr_arg = card; + card->hw->user_isr = card_isr; + } + break; + + default: + KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type)); + return -1; + } + + if (NeedISRandReset) + { + if (UxIsrInstall(card->hw, card_isr, card)) + { + KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq)); + UxCardHandleFree(card->hw); + return -1; + } + + b = card->cfg.irq; + + UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b); + + if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q) + { + if ((*card->card_reset)(card)) + { + KDPRINTF((KERN_WARNING "Divas: Adapter reset failed")); + return -1; + } + card->state = DIA_RESET; + } + + NeedISRandReset = FALSE; + } + + DivasCardNext++; + + return 0; +} + +void *get_card(int card_id) +{ + int i; + + for (i=0; i < DivasCardNext; i++) + { + if (DivasCards[i].cfg.card_id == card_id) + { + return(&DivasCards[i]); + } + } + + DPRINTF(("divas: get_card() : no such card id (%d)", card_id)); + + return NULL; +} + +int DivasCardConfig(dia_config_t *config) +{ + card_t *card; + int status; + + DPRINTF(("divas: configuring card")); + + card = get_card(config->card_id); + if (!card) + { + return -1; + } + + config = DivasConfig(card, config); + + status = (*card->card_config)(card, config); + + if (!status) + { + card->state = DIA_CONFIGURED; + } + return status; +} + +int DivasCardLoad(dia_load_t *load) +{ + card_t *card; + int status; + + card = get_card(load->card_id); + if (!card) + { + return -1; + } + + if (card->state == DIA_RUNNING) + { + (*card->card_reset)(card); + } + + status = (*card->card_load)(card, load); + if (!status) + { + card->state = DIA_LOADED; + } + return status; +} + +static int idi_register(card_t *card, byte channels) +{ + DESCRIPTOR d[32]; + int length, num_entities; + + DPRINTF(("divas: registering card with IDI")); + + num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES; + card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities); + + if (!card->e_tbl) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available")); + return -1; + } + + bzero(card->e_tbl, sizeof(E_INFO) * num_entities); + card->e_max = num_entities; + + DIVA_DIDD_Read(d, sizeof(d)); + + for(length=0; length < DIM(d); length++) + if (d[length].type == 0) break; + + if (length >= DIM(d)) + { + KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full")); + return -1; + } + + switch (card->cfg.card_type) + { + case DIA_CARD_TYPE_DIVA_SERVER: + d[length].type = IDI_ADAPTER_PR; + /* d[length].serial = card->serial_no; */ + break; + + case DIA_CARD_TYPE_DIVA_SERVER_B: + d[length].type = IDI_ADAPTER_MAESTRA; + /* d[length].serial = card->serial_no; */ + break; + + // 4BRI is treated as 4 BRI adapters + case DIA_CARD_TYPE_DIVA_SERVER_Q: + d[length].type = IDI_ADAPTER_MAESTRA; + /* d[length].serial = card->cfg.serial; */ + } + + d[length].features = 0; + d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120; + + if ( card->hw->features & PROTCAP_MANIF ) + { + d[length].features |= DI_MANAGE ; + } + if ( card->hw->features & PROTCAP_V_42 ) + { + d[length].features |= DI_V_42 ; + } + if ( card->hw->features & PROTCAP_EXTD_FAX ) + { + d[length].features |= DI_EXTD_FAX ; + } + + d[length].channels = channels; + d[length].request = DivasIdiRequest[card - DivasCards]; + + length++; + + DIVA_DIDD_Write(d, sizeof(d)); + + return 0; +} + +int DivasCardStart(int card_id) +{ + card_t *card; + byte channels; + int status; + + DPRINTF(("divas: starting card")); + + card = get_card(card_id); + if (!card) + { + return -1; + } + + status = (*card->card_start)(card, &channels); + if (status) + { + return status; + } + + /* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */ + if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + int i; + card_t *FourBRISlave; + + for (i=3; i >= 0; i--) + { + FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */ + if (FourBRISlave) + { + idi_register(FourBRISlave, 2); + FourBRISlave->state = DIA_RUNNING; + } + } + card->serial_no = card->cfg.serial; + + DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", + card_id - 3, card->serial_no, (int) channels)); + } + else + { + status = idi_register(card, channels); + if (!status) + { + card->state = DIA_RUNNING; + DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", + card_id, card->serial_no, (int) channels)); + } + } + + return status; +} + +int DivasGetMem(mem_block_t *mem_block) +{ + card_t *card; + word card_id = mem_block->card_id; + + card = get_card(card_id); + if (!card) + { + return 0; + } + + return (*card->card_mem_get)(card, mem_block); +} + + +/* + * Deleyed Procedure Call for handling interrupts from card + */ + +void DivaDoCardDpc(card_t *card) +{ + ADAPTER *a; + + a = &card->a; + + if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1) + { + return; + } + + do{ + if((*(card->test_int))(a)) + { + (*(card->dpc))(a); + (*(card->clear_int))(a); + } + (*(card->out))(a); + }while(UxInterlockedDecrement(card->hw, &card->dpc_reentered)); + +} + +void DivasDoDpc(void *pData) +{ + card_t *card = DivasCards; + int i = DivasCardNext; + + while(i--) + { + DivaDoCardDpc(card++); + } +} + +void DivasDoRequestDpc(void *pData) +{ + DivasDoDpc(pData); +} + +/* + * DivasGetNum + * Returns the number of active adapters + */ + +int DivasGetNum(void) +{ + return(DivasCardNext); +} + +/* + * DivasGetList + * Returns a list of active adapters + */ +int DivasGetList(dia_card_list_t *card_list) +{ + int i; + + bzero(card_list, sizeof(dia_card_list_t)); + + for(i = 0; i < DivasCardNext; i++) + { + card_list->card_type = DivasCards[i].cfg.card_type; + card_list->card_slot = DivasCards[i].cfg.slot; + card_list->state = DivasCards[i].state; + card_list++; + } + + return 0; + +} + +/* + * control logging for specified card + */ + +void DivasLog(dia_log_t *log) +{ + card_t *card; + + card = get_card(log->card_id); + if (!card) + { + return; + } + + card->log_types = log->log_types; + + return; +} + diff --git a/drivers/isdn/eicon/constant.h b/drivers/isdn/eicon/constant.h new file mode 100644 index 000000000000..f039fd52a7e2 --- /dev/null +++ b/drivers/isdn/eicon/constant.h @@ -0,0 +1,176 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + + +/*------------------------------------------------------------------*/ +/* Q.931 information elements maximum length */ +/* excluding the identifier, including the length field */ +/*------------------------------------------------------------------*/ + +#define MAX_LEN_BC 13 +#define MAX_LEN_LLC 19 /* ctr3 */ +#define MAX_LEN_HLC 6 /* ctr3 */ +#define MAX_LEN_UUI 200 /* Hicom USBS req */ +#define MAX_LEN_NUM 24 +#define MAX_LEN_DSP 83 /* ctr3 */ +#define MAX_LEN_NI 4 +#define MAX_LEN_PI 5 +#define MAX_LEN_SIN 3 +#define MAX_LEN_CST 4 +#define MAX_LEN_SIG 2 +#define MAX_LEN_SPID 32 +#define MAX_LEN_EID 3 +#define MAX_LEN_CHI 35 /* ctr3 */ +#define MAX_LEN_CAU 33 +#define MAX_LEN_FTY 130 +#define MAX_LEN_KEY 83 /* ctr3 */ +#define MAX_LEN_RSI 4 +#define MAX_LEN_CAI 11 +#define MAX_NUM_SPID 4 +#define MAX_LEN_USERID 9 +#define MAX_LEN_APPLID 5 +#define MAX_LEN_NTTCIF 15 + +/*------------------------------------------------------------------*/ +/* decision return values */ +/*------------------------------------------------------------------*/ + +#define YES 1 +#define NO 0 + + +/*-------------------------------------------------------------------*/ +/* w element coding */ +/*-------------------------------------------------------------------*/ + +#define NTTCIF 0x01 +#define BC 0x04 +#define CAU 0x08 +#define CAD 0x0c +#define CAI 0x10 +#define CST 0x14 +#define CHI 0x18 +#define LLI 0x19 +#define CHA 0x1a +#define FTY 0x1c +#define PI 0x1e +#define NFAC 0x20 +#define TC 0x24 +#define ATT_EID 0x26 +#define NI 0x27 +#define DSP 0x28 +#define DT 0x29 +#define KEY 0x2c +#define KP 0x2c +#define UID 0x2d +#define SIG 0x34 +#define FI 0x39 +#define SPID 0x3a +#define EID 0x3b +#define DSPF 0x3c +#define ECAD 0x4c +#define OAD 0x6c +#define OSA 0x6d +#define DAD 0x70 +#define CPN 0x70 +#define DSA 0x71 +#define RDX 0x73 +#define RAD 0x74 +#define RDN 0x74 +#define RSI 0x79 +#define SCR 0x7A /* internal unscreened CPN */ +#define MIE 0x7a /* internal management info element */ +#define LLC 0x7c +#define HLC 0x7d +#define UUI 0x7e +#define ESC 0x7f + +#define SHIFT 0x90 +#define MORE 0xa0 +#define CL 0xb0 + +/* information elements used on the spid interface */ +#define SPID_CMD 0xc0 +#define SPID_LINK 0x10 +#define SPID_DN 0x70 +#define SPID_BC 0x04 +#define SPID_SWITCH 0x11 + +/*------------------------------------------------------------------*/ +/* global configuration parameters, defined in exec.c */ +/* these parameters are configured with program loading */ +/*------------------------------------------------------------------*/ + +#define PROT_1TR6 0 +#define PROT_ETSI 1 +#define PROT_FRANC 2 +#define PROT_BELG 3 +#define PROT_SWED 4 +#define PROT_NI 5 +#define PROT_5ESS 6 +#define PROT_JAPAN 7 +#define PROT_ATEL 8 +#define PROT_US 9 +#define PROT_ITALY 10 +#define PROT_TWAN 11 +#define PROT_AUSTRAL 12 + +#define INIT_PROT_1TR6 0x80|PROT_1TR6 +#define INIT_PROT_ETSI 0x80|PROT_ETSI +#define INIT_PROT_FRANC 0x80|PROT_FRANC +#define INIT_PROT_BELG 0x80|PROT_BELG +#define INIT_PROT_SWED 0x80|PROT_SWED +#define INIT_PROT_NI 0x80|PROT_NI +#define INIT_PROT_5ESS 0x80|PROT_5ESS +#define INIT_PROT_JAPAN 0x80|PROT_JAPAN +#define INIT_PROT_ATEL 0x80|PROT_ATEL +#define INIT_PROT_ITALY 0x80|PROT_ITALY +#define INIT_PROT_TWAN 0x80|PROT_TWAN +#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL + + +/* -----------------------------------------------------------** +** The PROTOCOL_FEATURE_STRING in feature.h (included ** +** in prstart.sx and astart.sx) defines capabilities and ** +** features of the actual protocol code. It's used as a bit ** +** mask. ** +** The following Bits are defined: ** +** -----------------------------------------------------------*/ + +#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ +#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ +#define PROTCAP_V_42 0x0004 /* V42 implemented */ +#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ +#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ +#define PROTCAP_FREE4 0x0020 /* not used */ +#define PROTCAP_FREE5 0x0040 /* not used */ +#define PROTCAP_FREE6 0x0080 /* not used */ +#define PROTCAP_FREE7 0x0100 /* not used */ +#define PROTCAP_FREE8 0x0200 /* not used */ +#define PROTCAP_FREE9 0x0400 /* not used */ +#define PROTCAP_FREE10 0x0800 /* not used */ +#define PROTCAP_FREE11 0x1000 /* not used */ +#define PROTCAP_FREE12 0x2000 /* not used */ +#define PROTCAP_FREE13 0x4000 /* not used */ +#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ diff --git a/drivers/isdn/eicon/divalog.h b/drivers/isdn/eicon/divalog.h new file mode 100644 index 000000000000..48c0596b944b --- /dev/null +++ b/drivers/isdn/eicon/divalog.h @@ -0,0 +1,54 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Include file for defining the kernel loggger messages + * These definitions are shared between the klog driver and the + * klogd daemon process + */ + +#if !defined(_KLOGMSG_H) +#define _KLOGMSG_H + +/* define a type for a log entry */ + +#define KLOG_TEXT_MSG (0) +#define KLOG_XLOG_MSG (1) +#define KLOG_XTXT_MSG (2) +#define KLOG_IDI_REQ (4) +#define KLOG_IDI_CALLBACK (5) +#define KLOG_CAPI_MSG (6) + +typedef struct +{ + unsigned long time_stamp; /* in ms since last system boot */ + int card; /* card number (-1 for all) */ + unsigned int type; /* type of log message (0 is text) */ + unsigned int length; /* message length (non-text messages only) */ + unsigned short code; /* message code (non-text messages only) */ + char buffer[110];/* text/data to log */ +} klog_t; + +void DivasLogAdd(void *buffer, int length); +#endif /* of _KLOGMSG_H */ diff --git a/drivers/isdn/eicon/divas.h b/drivers/isdn/eicon/divas.h new file mode 100644 index 000000000000..3ea401edcd6e --- /dev/null +++ b/drivers/isdn/eicon/divas.h @@ -0,0 +1,229 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* External Diva Server driver include file */ + +#if !defined(DIVAS_H) +#define DIVAS_H + +#include "sys.h" + + +/* IOCTL commands */ + +#define DIA_IOCTL_INIT (0) +#define DIA_IOCTL_LOAD (1) +#define DIA_IOCTL_CONFIG (2) +#define DIA_IOCTL_START (3) +#define DIA_IOCTL_GET_NUM (4) +#define DIA_IOCTL_GET_LIST (5) +#define DIA_IOCTL_LOG (6) +#define DIA_IOCTL_DETECT (7) +#define DIA_IOCTL_SPACE (8) +#define DIA_IOCTL_GET_MEM (9) +#define DIA_IOCTL_FLAVOUR (10) +#define DIA_IOCTL_XLOG_REQ (11) + +/* Error codes */ + +#define XLOG_ERR_CARD_NUM (13) +#define XLOG_ERR_DONE (14) +#define XLOG_ERR_CMD (15) +#define XLOG_ERR_TIMEOUT (16) +#define XLOG_ERR_CARD_STATE (17) +#define XLOG_ERR_UNKNOWN (18) +#define XLOG_OK (0) + +/* Adapter states */ + +#define DIA_UNKNOWN (0) +#define DIA_RESET (1) +#define DIA_LOADED (2) +#define DIA_CONFIGURED (3) +#define DIA_RUNNING (4) + +/* Stucture for getting card specific information from active cad driver */ + +typedef struct +{ + int card_type; + int card_slot; + int state; +} dia_card_list_t; + +/* use following to select which logging to have active */ + +#define DIVAS_LOG_DEBUG (1 << 0) +#define DIVAS_LOG_XLOG (1 << 1) +#define DIVAS_LOG_IDI (1 << 2) +#define DIVAS_LOG_CAPI (1 << 3) + +/* stucture for DIA_IOCTL_LOG to get information from adapter */ + +typedef struct +{ + int card_id; + int log_types; /* bit mask of log types: use DIVAS_LOG_XXX */ +} dia_log_t; + +/* list of cards supported by this driver */ + +#define DIA_CARD_TYPE_DIVA_SERVER (0) /* Diva Server PRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_B (1) /* Diva Server BRI */ +#define DIA_CARD_TYPE_DIVA_SERVER_Q (2) /* Diva Server 4-BRI */ + +/* bus types */ + +#define DIA_BUS_TYPE_ISA (0) +#define DIA_BUS_TYPE_ISA_PNP (1) +#define DIA_BUS_TYPE_PCI (2) +#define DIA_BUS_TYPE_MCA (3) + +/* types of memory used (index for memory array below) */ + +#define DIVAS_RAM_MEMORY 0 +#define DIVAS_REG_MEMORY 1 +#define DIVAS_CFG_MEMORY 2 +#define DIVAS_SHARED_MEMORY 3 +#define DIVAS_CTL_MEMORY 4 +/* + * card config information + * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card + */ + +typedef struct +{ + int card_id; /* unique id assigned to this card */ + int card_type; /* use DIA_CARD_TYPE_xxx above */ + int bus_type; /* use DIA_BUS_TYPE_xxx above */ + int bus_num; /* bus number (instance number of bus type) */ + int func_num; /* adapter function number (PCI register) */ + int slot; /* slot number in bus */ + unsigned char irq; /* IRQ number */ + int reset_base; /* Reset register for I/O mapped cards */ + int io_base; /* I/O base for I/O mapped cards */ + void *memory[5]; /* memory base addresses for memory mapped cards */ + char name[9]; /* name of adapter */ + int serial; /* serial number */ + unsigned char int_priority; /* Interrupt priority */ +} dia_card_t; + +/* + * protocol configuration information + * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card + */ + +typedef struct +{ + int card_id; /* to identify particular card */ + unsigned char tei; + unsigned char nt2; + unsigned char watchdog; + unsigned char permanent; + unsigned char x_interface; + unsigned char stable_l2; + unsigned char no_order_check; + unsigned char handset_type; + unsigned char sig_flags; + unsigned char low_channel; + unsigned char prot_version; + unsigned char crc4; + struct + { + unsigned char oad[32]; + unsigned char osa[32]; + unsigned char spid[32]; + }terminal[2]; +} dia_config_t; + +/* + * code configuration + * passed as parameter to DIA_IOCTL_LOAD ioctl + * one of these ioctl per code file to load + */ + +typedef struct +{ + int card_id; /* card to load */ + enum + { + DIA_CPU_CODE, /* CPU code */ + DIA_DSP_CODE, /* DSP code */ + DIA_CONT_CODE, /* continuation of code */ + DIA_TABLE_CODE, /* code table */ + DIA_DLOAD_CNT, /* number of downloads*/ + DIA_FPGA_CODE + } code_type; /* code for CPU or DSP ? */ + int length; /* length of code */ + unsigned char *code; /* pointer (in user-space) to code */ +} dia_load_t; + +/* + * start configuration + * passed as parameter to DIA_IOCTL_START ioctl + */ + +typedef struct +{ + int card_id; /* card to start */ +} dia_start_t; + +/* used for retrieving memory from the card */ + +typedef struct { + word card_id; + dword addr; + byte data[16 * 8]; +} mem_block_t; + +/* DIVA Server specific addresses */ + +#define DIVAS_CPU_START_ADDR (0x0) +#define ORG_MAX_PROTOCOL_CODE_SIZE 0x000A0000 +#define ORG_MAX_DSP_CODE_SIZE (0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE) +#define ORG_DSP_CODE_BASE (0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE) +#define DIVAS_DSP_START_ADDR (0xBF7A0000) +#define DIVAS_SHARED_OFFSET (0x1000) +#define MP_DSP_CODE_BASE 0xa03a0000 +#define MQ_PROTCODE_OFFSET 0x100000 +#define MQ_SM_OFFSET 0X0f0000 + +#define V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 +#define V90D_MAX_DSP_CODE_SIZE (0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE) +#define V90D_DSP_CODE_BASE (0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE) + +#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ +#define MQ_ORG_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code */ +#define MQ_ORG_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_ORG_MAX_DSP_CODE_SIZE) +#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE 0x00090000 /* max 576K Protocol-Code */ +#define MQ_V90D_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code if V.90D included */ +#define MQ_MAX_DSP_DOWNLOAD_ADDR 0xa03f0000 +#define MQ_V90D_DSP_CODE_BASE (MQ_MAX_DSP_DOWNLOAD_ADDR \ + - MQ_V90D_MAX_DSP_CODE_SIZE) + + +#define ALIGNMENT_MASK_MAESTRA 0xfffffffc + +#endif /* DIVAS_H */ diff --git a/drivers/isdn/eicon/dsp_defs.h b/drivers/isdn/eicon/dsp_defs.h new file mode 100644 index 000000000000..35ab16e67284 --- /dev/null +++ b/drivers/isdn/eicon/dsp_defs.h @@ -0,0 +1,300 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef DSP_DEFS_H_ +#define DSP_DEFS_H_ + +#ifndef DSPDIDS_H_ +#include "dspdids.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/*---------------------------------------------------------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif +#ifndef TRUE +#define TRUE (0 == 0) +#endif +#ifndef FALSE +#define FALSE (0 != 0) +#endif + + +/*---------------------------------------------------------------------------*/ + +#define DSP_MEMORY_TYPE_EXTERNAL_DM 0 +#define DSP_MEMORY_TYPE_EXTERNAL_PM 1 +#define DSP_MEMORY_TYPE_INTERNAL_DM 2 +#define DSP_MEMORY_TYPE_INTERNAL_PM 3 + +#define DSP_DOWNLOAD_FLAG_BOOTABLE 0x0001 +#define DSP_DOWNLOAD_FLAG_2181 0x0002 +#define DSP_DOWNLOAD_FLAG_TIMECRITICAL 0x0004 +#define DSP_DOWNLOAD_FLAG_COMPAND 0x0008 + +#define DSP_MEMORY_BLOCK_COUNT 16 + +#define DSP_SEGMENT_PM_FLAG 0x0001 +#define DSP_SEGMENT_SHARED_FLAG 0x0002 + +#define DSP_SEGMENT_EXTERNAL_DM DSP_MEMORY_TYPE_EXTERNAL_DM +#define DSP_SEGMENT_EXTERNAL_PM DSP_MEMORY_TYPE_EXTERNAL_PM +#define DSP_SEGMENT_INTERNAL_DM DSP_MEMORY_TYPE_INTERNAL_DM +#define DSP_SEGMENT_INTERNAL_PM DSP_MEMORY_TYPE_INTERNAL_PM +#define DSP_SEGMENT_FIRST_RELOCATABLE 4 + +#define DSP_DATA_BLOCK_PM_FLAG 0x0001 +#define DSP_DATA_BLOCK_DWORD_FLAG 0x0002 +#define DSP_DATA_BLOCK_RESOLVE_FLAG 0x0004 + +#define DSP_RELOC_NONE 0x00 +#define DSP_RELOC_SEGMENT_MASK 0x3f +#define DSP_RELOC_TYPE_MASK 0xc0 +#define DSP_RELOC_TYPE_0 0x00 /* relocation of address in DM word / high part of PM word */ +#define DSP_RELOC_TYPE_1 0x40 /* relocation of address in low part of PM data word */ +#define DSP_RELOC_TYPE_2 0x80 /* relocation of address in standard command */ +#define DSP_RELOC_TYPE_3 0xc0 /* relocation of address in call/jump on flag in */ + +#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 + +#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 + + +typedef struct tag_dsp_combifile_header +{ + char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word header_size; + word combifile_description_size; + word directory_entries; + word directory_size; + word download_count; + word usage_mask_size; +} t_dsp_combifile_header; + +typedef struct tag_dsp_combifile_directory_entry +{ + word card_type_number; + word file_set_number; +} t_dsp_combifile_directory_entry; + +typedef struct tag_dsp_file_header +{ + char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE]; + word format_version_bcd; + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word header_size; + word download_description_size; + word memory_block_table_size; + word memory_block_count; + word segment_table_size; + word segment_count; + word symbol_table_size; + word symbol_count; + word total_data_size_dm; + word data_block_count_dm; + word total_data_size_pm; + word data_block_count_pm; +} t_dsp_file_header; + +typedef struct tag_dsp_memory_block_desc +{ + word alias_memory_block; + word memory_type; + word address; + word size; /* DSP words */ +} t_dsp_memory_block_desc; + +typedef struct tag_dsp_segment_desc +{ + word memory_block; + word attributes; + word base; + word size; + word alignment; /* ==0 -> no other legal start address than base */ +} t_dsp_segment_desc; + +typedef struct tag_dsp_symbol_desc +{ + word symbol_id; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_symbol_desc; + +typedef struct tag_dsp_data_block_header +{ + word attributes; + word segment; + word offset; + word size; /* DSP words */ +} t_dsp_data_block_header; + +typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ +{ + word download_id; + word download_flags; + word required_processing_power; + word interface_channel_count; + word excess_header_size; + word memory_block_count; + word segment_count; + word symbol_count; + word data_block_count_dm; + word data_block_count_pm; + byte *p_excess_header_data; + char *p_download_description; + t_dsp_memory_block_desc *p_memory_block_table; + t_dsp_segment_desc *p_segment_table; + t_dsp_symbol_desc *p_symbol_table; + word *p_data_blocks_dm; + word *p_data_blocks_pm; +} t_dsp_download_desc; + +#define DSP_DOWNLOAD_INDEX_KERNEL 0 +#define DSP30TX_DOWNLOAD_INDEX_KERNEL 1 +#define DSP30RX_DOWNLOAD_INDEX_KERNEL 2 +#define DSP_MAX_DOWNLOAD_COUNT 35 + + +#define DSP_DOWNLOAD_MAX_SEGMENTS 16 + +#define DSP_UDATA_REQUEST_RECONFIGURE 0 +/* +parameters: + reconfigure delay (in 8kHz samples) + reconfigure code + reconfigure hdlc preamble flags +*/ + +#define DSP_RECONFIGURE_TX_FLAG 0x8000 +#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 +#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 +#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 +#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 +#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff +#define DSP_RECONFIGURE_IDLE 0 +#define DSP_RECONFIGURE_V25 1 +#define DSP_RECONFIGURE_V21_CH2 2 +#define DSP_RECONFIGURE_V27_2400 3 +#define DSP_RECONFIGURE_V27_4800 4 +#define DSP_RECONFIGURE_V29_7200 5 +#define DSP_RECONFIGURE_V29_9600 6 +#define DSP_RECONFIGURE_V33_12000 7 +#define DSP_RECONFIGURE_V33_14400 8 +#define DSP_RECONFIGURE_V17_7200 9 +#define DSP_RECONFIGURE_V17_9600 10 +#define DSP_RECONFIGURE_V17_12000 11 +#define DSP_RECONFIGURE_V17_14400 12 + +/* +data indications if transparent framer + data 0 + data 1 + ... + +data indications if HDLC framer + data 0 + data 1 + ... + CRC 0 + CRC 1 + preamble flags +*/ + +#define DSP_UDATA_INDICATION_SYNC 0 +/* +returns: + time of sync (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_OFF 1 +/* +returns: + time of DCD off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_ON 2 +/* +returns: + time of DCD on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s) +*/ + +#define DSP_UDATA_INDICATION_CTS_OFF 3 +/* +returns: + time of CTS off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_CTS_ON 4 +/* +returns: + time of CTS on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s) +*/ + +#define DSP_CONNECTED_NORM_UNSPECIFIED 0 +#define DSP_CONNECTED_NORM_V21 1 +#define DSP_CONNECTED_NORM_V23 2 +#define DSP_CONNECTED_NORM_V22 3 +#define DSP_CONNECTED_NORM_V22_BIS 4 +#define DSP_CONNECTED_NORM_V32_BIS 5 +#define DSP_CONNECTED_NORM_V34 6 +#define DSP_CONNECTED_NORM_V8 7 +#define DSP_CONNECTED_NORM_BELL_212A 8 +#define DSP_CONNECTED_NORM_BELL_103 9 +#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 +#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 +#define DSP_CONNECTED_NORM_TFAST 12 +#define DSP_CONNECTED_NORM_V21_CH2 13 +#define DSP_CONNECTED_NORM_V27_TER 14 +#define DSP_CONNECTED_NORM_V29 15 +#define DSP_CONNECTED_NORM_V33 16 +#define DSP_CONNECTED_NORM_V17 17 + +#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 + + +/*---------------------------------------------------------------------------*/ +#ifdef __cplusplus +} +#endif + +#endif + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/isdn/eicon/dspdids.h b/drivers/isdn/eicon/dspdids.h new file mode 100644 index 000000000000..618fda717c88 --- /dev/null +++ b/drivers/isdn/eicon/dspdids.h @@ -0,0 +1,81 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef DSPDIDS_H_ +#define DSPDIDS_H_ + + +/*---------------------------------------------------------------------------*/ + +#define DSP_DID_INVALID 0 +#define DSP_DID_DIVA 1 +#define DSP_DID_DIVA_PRO 2 +#define DSP_DID_DIVA_PRO_20 3 +#define DSP_DID_DIVA_PRO_PCCARD 4 +#define DSP_DID_DIVA_SERVER_BRI_1M 5 +#define DSP_DID_DIVA_SERVER_BRI_2M 6 +#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7 +#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8 +#define DSP_DID_DIVA_SERVER_PRI_30M 9 +#define DSP_DID_TASK_HSCX 100 +#define DSP_DID_TASK_HSCX_PRI_2M_TX 101 +#define DSP_DID_TASK_HSCX_PRI_2M_RX 102 +#define DSP_DID_TASK_V110KRNL 200 +#define DSP_DID_OVERLAY_V1100 201 +#define DSP_DID_OVERLAY_V1101 202 +#define DSP_DID_OVERLAY_V1102 203 +#define DSP_DID_OVERLAY_V1103 204 +#define DSP_DID_OVERLAY_V1104 205 +#define DSP_DID_OVERLAY_V1105 206 +#define DSP_DID_OVERLAY_V1106 207 +#define DSP_DID_OVERLAY_V1107 208 +#define DSP_DID_OVERLAY_V1108 209 +#define DSP_DID_OVERLAY_V1109 210 +#define DSP_DID_TASK_V110_PRI_2M_TX 220 +#define DSP_DID_TASK_V110_PRI_2M_RX 221 +#define DSP_DID_TASK_MODEM 300 +#define DSP_DID_TASK_FAX05 400 +#define DSP_DID_TASK_VOICE 500 +#define DSP_DID_TASK_TIKRNL81 600 +#define DSP_DID_OVERLAY_DIAL 601 +#define DSP_DID_OVERLAY_V22 602 +#define DSP_DID_OVERLAY_V32 603 +#define DSP_DID_OVERLAY_FSK 604 +#define DSP_DID_OVERLAY_FAX 605 +#define DSP_DID_OVERLAY_VXX 606 +#define DSP_DID_OVERLAY_V8 607 +#define DSP_DID_OVERLAY_INFO 608 +#define DSP_DID_OVERLAY_V34 609 +#define DSP_DID_OVERLAY_DFX 610 +#define DSP_DID_PARTIAL_OVERLAY_DIAL 611 +#define DSP_DID_PARTIAL_OVERLAY_FSK 612 +#define DSP_DID_PARTIAL_OVERLAY_FAX 613 +#define DSP_DID_TASK_TIKRNL05 700 + + +/*---------------------------------------------------------------------------*/ + +#endif + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h index 7e013a71bd2d..33ca39a56bba 100644 --- a/drivers/isdn/eicon/eicon.h +++ b/drivers/isdn/eicon/eicon.h @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,86 +20,6 @@ * along with this program; if not, write to the Free Software * 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. - * - * Revision 1.16 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.15 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.14 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.13 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.12 1999/09/04 06:20:05 keil - * Changes from kernel set_current_state() - * - * Revision 1.11 1999/08/29 17:23:44 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/22 20:26:41 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/18 20:16:57 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:01 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:23 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:24 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/03/29 11:19:41 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:42 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:07 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:04 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ @@ -124,6 +44,8 @@ #define EICON_IOCTL_TEST 98 #define EICON_IOCTL_DEBUGVAR 99 +#define EICON_IOCTL_DIA_OFFSET 100 + /* Bus types */ #define EICON_BUS_ISA 1 #define EICON_BUS_MCA 2 @@ -185,39 +107,10 @@ typedef struct { unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */ } eicon_isa_codebuf; -/* Struct for downloading protocol via ioctl for PCI cards */ -typedef struct { - /* start-up parameters */ - unsigned char tei; - unsigned char nt2; - unsigned char WatchDog; - unsigned char Permanent; - unsigned char XInterface; - unsigned char StableL2; - unsigned char NoOrderCheck; - unsigned char HandsetType; - unsigned char LowChannel; - unsigned char ProtVersion; - unsigned char Crc4; - unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */ - unsigned char Loopback; /* switch card into Loopback mode */ - struct q931_link_s - { - unsigned char oad[32]; - unsigned char osa[32]; - unsigned char spid[32]; - } l[2]; - unsigned long protocol_len; - unsigned int dsp_code_num; - unsigned long dsp_code_len[9]; - unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */ -} eicon_pci_codebuf; - /* Data for downloading protocol via ioctl */ typedef union { eicon_isa_codebuf isa; eicon_isa_codebuf mca; - eicon_pci_codebuf pci; } eicon_codebuf; /* Data for Management interface */ @@ -228,6 +121,7 @@ typedef struct { unsigned char data[700]; } eicon_manifbuf; +#define TRACE_OK (1) #ifdef __KERNEL__ @@ -245,7 +139,7 @@ typedef struct { #include #include #include -#include +#include #include #include #include @@ -257,7 +151,6 @@ typedef struct { #include #include - typedef struct { __u16 length __attribute__ ((packed)); /* length of data/parameter field */ __u8 P[1]; /* data/parameter field */ @@ -265,206 +158,34 @@ typedef struct { #include "eicon_isa.h" +#include "idi.h" + +typedef struct { + __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ + __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ + __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ + __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ + __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ + __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ + __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ + __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ + __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ + __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ + __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ + __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ + __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ + __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ + __u8 B[1]; /* buffer space for Req,Ind and Rc */ +} eicon_pr_ram; + /* Macro for delay via schedule() */ #define SLEEP(j) { \ - current->state = TASK_UNINTERRUPTIBLE; \ + set_current_state(TASK_UNINTERRUPTIBLE); \ schedule_timeout(j); \ } -#endif /* KERNEL */ - -#define DIVAS_SHARED_OFFSET (0x1000) - -#define MIPS_BUFFER_SZ 128 -#define MIPS_MAINT_OFFS 0xff00 - -#define XLOG_ERR_CARD_NUM (13) -#define XLOG_ERR_DONE (14) -#define XLOG_ERR_CMD (15) -#define XLOG_ERR_TIMEOUT (16) -#define XLOG_ERR_CARD_STATE (17) -#define XLOG_ERR_UNKNOWN (18) -#define XLOG_OK (0) - -#define TRACE_OK (1) - -typedef struct { - __u8 Id __attribute__ ((packed)); - __u8 uX __attribute__ ((packed)); - __u8 listen __attribute__ ((packed)); - __u8 active __attribute__ ((packed)); - __u8 sin[3] __attribute__ ((packed)); - __u8 bc[6] __attribute__ ((packed)); - __u8 llc[6] __attribute__ ((packed)); - __u8 hlc[6] __attribute__ ((packed)); - __u8 oad[20] __attribute__ ((packed)); -}DSigStruc; - -typedef struct { - __u32 cx_b1 __attribute__ ((packed)); - __u32 cx_b2 __attribute__ ((packed)); - __u32 cr_b1 __attribute__ ((packed)); - __u32 cr_b2 __attribute__ ((packed)); - __u32 px_b1 __attribute__ ((packed)); - __u32 px_b2 __attribute__ ((packed)); - __u32 pr_b1 __attribute__ ((packed)); - __u32 pr_b2 __attribute__ ((packed)); - __u16 er_b1 __attribute__ ((packed)); - __u16 er_b2 __attribute__ ((packed)); -}BL1Struc; - -typedef struct { - __u32 XTotal __attribute__ ((packed)); - __u32 RTotal __attribute__ ((packed)); - __u16 XError __attribute__ ((packed)); - __u16 RError __attribute__ ((packed)); -}L2Struc; - -typedef struct { - __u16 free_n; -}OSStruc; - -typedef union -{ - DSigStruc DSigStats; - BL1Struc BL1Stats; - L2Struc L2Stats; - OSStruc OSStats; - __u8 b[MIPS_BUFFER_SZ]; - __u16 w[MIPS_BUFFER_SZ>>1]; - __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ - __u32 d[MIPS_BUFFER_SZ>>2]; -} MIPS_BUFFER; - -typedef struct -{ - __u8 req __attribute__ ((packed)); - __u8 rc __attribute__ ((packed)); - __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */ - __u8 *mem __attribute__ ((packed)); - __u16 length __attribute__ ((packed)); /* used to be short */ - __u16 port __attribute__ ((packed)); - __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */ - MIPS_BUFFER data __attribute__ ((packed)); -} mi_pc_maint_t; - -typedef struct -{ - __u16 command; - mi_pc_maint_t pcm; -}xlogreq_t; - -typedef struct{ - __u16 code __attribute__ ((packed)); /* used to be short */ - __u16 timeh __attribute__ ((packed)); - __u16 timel __attribute__ ((packed)); - char buffer[MIPS_BUFFER_SZ - 6]; -}xlog_entry_t; - - -#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 - -#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 -#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 - -typedef struct tag_dsp_combifile_header -{ - char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 combifile_description_size __attribute__ ((packed)); - __u16 directory_entries __attribute__ ((packed)); - __u16 directory_size __attribute__ ((packed)); - __u16 download_count __attribute__ ((packed)); - __u16 usage_mask_size __attribute__ ((packed)); -} t_dsp_combifile_header; - -typedef struct tag_dsp_combifile_directory_entry -{ - __u16 card_type_number __attribute__ ((packed)); - __u16 file_set_number __attribute__ ((packed)); -} t_dsp_combifile_directory_entry; - -typedef struct tag_dsp_file_header -{ - char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); - __u16 format_version_bcd __attribute__ ((packed)); - __u16 download_id __attribute__ ((packed)); - __u16 download_flags __attribute__ ((packed)); - __u16 required_processing_power __attribute__ ((packed)); - __u16 interface_channel_count __attribute__ ((packed)); - __u16 header_size __attribute__ ((packed)); - __u16 download_description_size __attribute__ ((packed)); - __u16 memory_block_table_size __attribute__ ((packed)); - __u16 memory_block_count __attribute__ ((packed)); - __u16 segment_table_size __attribute__ ((packed)); - __u16 segment_count __attribute__ ((packed)); - __u16 symbol_table_size __attribute__ ((packed)); - __u16 symbol_count __attribute__ ((packed)); - __u16 total_data_size_dm __attribute__ ((packed)); - __u16 data_block_count_dm __attribute__ ((packed)); - __u16 total_data_size_pm __attribute__ ((packed)); - __u16 data_block_count_pm __attribute__ ((packed)); -} t_dsp_file_header; - -typedef struct tag_dsp_memory_block_desc -{ - __u16 alias_memory_block; - __u16 memory_type; - __u16 address; - __u16 size; /* DSP words */ -} t_dsp_memory_block_desc; - -typedef struct tag_dsp_segment_desc -{ - __u16 memory_block; - __u16 attributes; - __u16 base; - __u16 size; - __u16 alignment; /* ==0 -> no other legal start address than base */ -} t_dsp_segment_desc; - -typedef struct tag_dsp_symbol_desc -{ - __u16 symbol_id; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_symbol_desc; - -typedef struct tag_dsp_data_block_header -{ - __u16 attributes; - __u16 segment; - __u16 offset; - __u16 size; /* DSP words */ -} t_dsp_data_block_header; - -typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ -{ - __u16 download_id; - __u16 download_flags; - __u16 required_processing_power; - __u16 interface_channel_count; - __u16 excess_header_size; - __u16 memory_block_count; - __u16 segment_count; - __u16 symbol_count; - __u16 data_block_count_dm; - __u16 data_block_count_pm; - __u8 * p_excess_header_data __attribute__ ((packed)); - char * p_download_description __attribute__ ((packed)); - t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed)); - t_dsp_segment_desc *p_segment_table __attribute__ ((packed)); - t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed)); - __u16 * p_data_blocks_dm __attribute__ ((packed)); - __u16 * p_data_blocks_pm __attribute__ ((packed)); -} t_dsp_download_desc; - - -#ifdef __KERNEL__ - typedef struct { __u8 Req; /* pending request */ __u8 Rc; /* return code received */ @@ -508,6 +229,7 @@ typedef struct { unsigned short statectrl; /* State controling bits */ unsigned short eazmask; /* EAZ-Mask for this Channel */ int queued; /* User-Data Bytes in TX queue */ + int pqueued; /* User-Data Packets in TX queue */ int waitq; /* User-Data Bytes in wait queue */ int waitpq; /* User-Data Bytes in packet queue */ struct sk_buff *tskb1; /* temp skb 1 */ @@ -518,7 +240,9 @@ typedef struct { T30_s *fax; /* pointer to fax data in LL */ eicon_ch_fax_buf fax2; /* fax related struct */ #endif - entity e; /* Entity */ + entity e; /* Native Entity */ + ENTITY de; /* Divas D Entity */ + ENTITY be; /* Divas B Entity */ char cpn[32]; /* remember cpn */ char oad[32]; /* remember oad */ char dsa[32]; /* remember dsa */ @@ -542,8 +266,6 @@ typedef struct { #define EICON_FLAGS_MVALID 8 /* Cards membase is valid */ #define EICON_FLAGS_LOADED 8 /* Firmware loaded */ -#define EICON_BCH 2 /* # of channels per card */ - /* D-Channel states */ #define EICON_STATE_NULL 0 #define EICON_STATE_ICALL 1 @@ -565,9 +287,6 @@ typedef struct { #define EICON_MAX_QUEUE 2138 -#define EICON_LOCK_TX 0 -#define EICON_LOCK_RX 1 - typedef union { eicon_isa_card isa; eicon_pci_card pci; @@ -593,17 +312,12 @@ typedef struct { __u8 more; } eicon_indhdr; -typedef struct msn_entry { - char eaz; - char msn[16]; - struct msn_entry * next; -} msn_entry; - /* * Per card driver data */ typedef struct eicon_card { eicon_hwif hwif; /* Hardware dependant interface */ + DESCRIPTOR *d; /* IDI Descriptor */ u_char ptype; /* Protocol type (1TR6 or Euro) */ u_char bus; /* Bustype (ISA, MCA, PCI) */ u_char type; /* Cardtype (EICON_CTYPE_...) */ @@ -621,49 +335,23 @@ typedef struct eicon_card { 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; eicon_chan* IdTable[256]; /* Table to find entity */ __u16 ref_in; __u16 ref_out; int nchannels; /* Number of B-Channels */ int ReadyInt; /* Ready Interrupt */ eicon_chan *bch; /* B-Channel status/control */ - char status_buf[256]; /* Buffer for status messages */ - char *status_buf_read; - char *status_buf_write; - char *status_buf_end; + DBUFFER *dbuf; /* Dbuffer for Diva Server */ + BUFFERS *sbuf; /* Buffer for Diva Server */ + char *sbufp; /* Data Buffer for Diva Server */ isdn_if interface; /* Interface to upper layer */ - char regname[35]; /* Name used for request_region */ + char regname[35]; /* Drivers card name */ #ifdef CONFIG_MCA int mca_slot; /* # of cards MCA slot */ int mca_io; /* MCA cards IO port */ #endif /* CONFIG_MCA */ } eicon_card; -/* -----------------------------------------------------------** -** The PROTOCOL_FEATURE_STRING ** -** defines capabilities and ** -** features of the actual protocol code. It's used as a bit ** -** mask. ** -** The following Bits are defined: ** -** -----------------------------------------------------------*/ -#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ -#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ -#define PROTCAP_V_42 0x0004 /* V42 implemented */ -#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ -#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ -#define PROTCAP_FREE4 0x0020 /* not used */ -#define PROTCAP_FREE5 0x0040 /* not used */ -#define PROTCAP_FREE6 0x0080 /* not used */ -#define PROTCAP_FREE7 0x0100 /* not used */ -#define PROTCAP_FREE8 0x0200 /* not used */ -#define PROTCAP_FREE9 0x0400 /* not used */ -#define PROTCAP_FREE10 0x0800 /* not used */ -#define PROTCAP_FREE11 0x1000 /* not used */ -#define PROTCAP_FREE12 0x2000 /* not used */ -#define PROTCAP_FREE13 0x4000 /* not used */ -#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ - #include "eicon_idi.h" extern eicon_card *cards; @@ -688,13 +376,11 @@ extern __inline__ void eicon_schedule_ack(eicon_card *card) mark_bh(IMMEDIATE_BH); } -extern char *eicon_find_eaz(eicon_card *, char); -extern int eicon_addcard(int, int, int, char *); +extern int eicon_addcard(int, int, int, char *, int); extern void eicon_io_transmit(eicon_card *card); extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs); extern void eicon_io_rcv_dispatch(eicon_card *ccard); extern void eicon_io_ack_dispatch(eicon_card *ccard); -extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq); #ifdef CONFIG_MCA extern int eicon_mca_find_card(int, int, int, char *); extern int eicon_mca_probe(int, int, int, int, char *); @@ -705,6 +391,8 @@ extern ulong DebugVar; extern void eicon_log(eicon_card * card, int level, const char *fmt, ...); extern void eicon_putstatus(eicon_card * card, char * buf); +extern spinlock_t eicon_lock; + #endif /* __KERNEL__ */ #endif /* eicon_h */ diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h index 420d73f6ea8f..1470fa7e6d85 100644 --- a/drivers/isdn/eicon/eicon_dsp.h +++ b/drivers/isdn/eicon/eicon_dsp.h @@ -1,4 +1,4 @@ -/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * DSP definitions @@ -20,75 +20,14 @@ * along with this program; if not, write to the Free Software * 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. - * - * Revision 1.3 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.2 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.1 1999/03/02 12:18:54 armin - * First checkin of DSP defines for audio features. - * * */ #ifndef DSP_H #define DSP_H -#define DSP_UDATA_REQUEST_RECONFIGURE 0 -/* -parameters: - reconfigure delay (in 8kHz samples) - reconfigure code - reconfigure hdlc preamble flags -*/ +#include "dsp_defs.h" -#define DSP_RECONFIGURE_TX_FLAG 0x8000 -#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 -#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 -#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 -#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 -#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff -#define DSP_RECONFIGURE_IDLE 0 -#define DSP_RECONFIGURE_V25 1 -#define DSP_RECONFIGURE_V21_CH2 2 -#define DSP_RECONFIGURE_V27_2400 3 -#define DSP_RECONFIGURE_V27_4800 4 -#define DSP_RECONFIGURE_V29_7200 5 -#define DSP_RECONFIGURE_V29_9600 6 -#define DSP_RECONFIGURE_V33_12000 7 -#define DSP_RECONFIGURE_V33_14400 8 -#define DSP_RECONFIGURE_V17_7200 9 -#define DSP_RECONFIGURE_V17_9600 10 -#define DSP_RECONFIGURE_V17_12000 11 -#define DSP_RECONFIGURE_V17_14400 12 - -/* -data indications if transparent framer - data 0 - data 1 - ... - -data indications if HDLC framer - data 0 - data 1 - ... - CRC 0 - CRC 1 - preamble flags -*/ #define DSP_UDATA_REQUEST_SWITCH_FRAMER 1 /* @@ -122,49 +61,6 @@ parameters: - none - */ - -#define DSP_UDATA_INDICATION_SYNC 0 -/* -returns: - time of sync (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_OFF 1 -/* -returns: - time of DCD off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_DCD_ON 2 -/* -returns: - time of DCD on (sampled from counter at 8kHz) - connected norm - connected options - connected speed (bit/s, max of tx and rx speed) - roundtrip delay (ms) - connected speed tx (bit/s) - connected speed rx (bit/s) -*/ - -#define DSP_UDATA_INDICATION_CTS_OFF 3 -/* -returns: - time of CTS off (sampled from counter at 8kHz) -*/ - -#define DSP_UDATA_INDICATION_CTS_ON 4 -/* -returns: - time of CTS on (sampled from counter at 8kHz) - connected norm - connected options - connected speed (bit/s, max of tx and rx speed) - roundtrip delay (ms) - connected speed tx (bit/s) - connected speed rx (bit/s) -*/ - typedef struct eicon_dsp_ind { __u16 time __attribute__ ((packed)); __u8 norm __attribute__ ((packed)); @@ -175,32 +71,11 @@ typedef struct eicon_dsp_ind { __u32 rxspeed __attribute__ ((packed)); } eicon_dsp_ind; -#define DSP_CONNECTED_NORM_UNSPECIFIED 0 -#define DSP_CONNECTED_NORM_V21 1 -#define DSP_CONNECTED_NORM_V23 2 -#define DSP_CONNECTED_NORM_V22 3 -#define DSP_CONNECTED_NORM_V22_BIS 4 -#define DSP_CONNECTED_NORM_V32_BIS 5 -#define DSP_CONNECTED_NORM_V34 6 -#define DSP_CONNECTED_NORM_V8 7 -#define DSP_CONNECTED_NORM_BELL_212A 8 -#define DSP_CONNECTED_NORM_BELL_103 9 -#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 -#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 -#define DSP_CONNECTED_NORM_V90 12 -#define DSP_CONNECTED_NORM_V21_CH2 13 -#define DSP_CONNECTED_NORM_V27_TER 14 -#define DSP_CONNECTED_NORM_V29 15 -#define DSP_CONNECTED_NORM_V33 16 -#define DSP_CONNECTED_NORM_V17 17 - -#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 #define DSP_CONNECTED_OPTION_V42_TRANS 0x0002 #define DSP_CONNECTED_OPTION_V42_LAPM 0x0004 #define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008 #define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010 - #define DSP_UDATA_INDICATION_DISCONNECT 5 /* returns: @@ -214,7 +89,6 @@ returns: #define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04 #define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05 - #define DSP_UDATA_INDICATION_TX_CONFIRMATION 6 /* returns: diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index 9cef520bc527..9972d535b2eb 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $ +/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,135 +25,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_idi.c,v $ - * Revision 1.33 2000/03/06 15:45:17 armin - * Fixed incomplete number handling with BRI PtP connection. - * - * Revision 1.32 2000/03/04 17:04:21 armin - * Fix of statemachine, B-connect before D-connect, - * thanks to Helmut Adams - * Minor change in send-data packet handling. - * - * Revision 1.31 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * Revision 1.30 2000/02/16 16:08:46 armin - * Fixed virtual channel handling of IDI. - * - * 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. - * - * Revision 1.23 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.22 1999/10/08 22:09:33 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.21 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.20 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.19 1999/09/21 20:06:40 armin - * Added pointer checks. - * - * Revision 1.18 1999/09/07 12:48:05 armin - * Prepared for sub-address usage. - * - * Revision 1.17 1999/09/07 12:35:39 armin - * Better checking and channel Id handling. - * - * Revision 1.16 1999/09/04 13:44:19 armin - * Fix of V.42 analog Modem negotiation handling. - * - * Revision 1.15 1999/08/28 21:32:50 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.14 1999/08/28 20:24:40 armin - * Corrected octet 3/3a in CPN/OAD information element. - * Thanks to John Simpson - * - * Revision 1.13 1999/08/22 20:26:44 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.12 1999/08/18 20:16:59 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.11 1999/07/25 15:12:03 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.10 1999/07/11 17:16:24 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.9 1999/03/29 11:19:42 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.8 1999/03/02 12:37:43 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.7 1999/02/03 18:34:35 armin - * Channel selection for outgoing calls w/o CHI. - * Added channel # in debug messages. - * L2 Transparent should work with 800 byte/packet now. - * - * Revision 1.6 1999/01/26 07:18:59 armin - * Bug with wrong added CPN fixed. - * - * Revision 1.5 1999/01/24 20:14:11 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.4 1999/01/10 18:46:05 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.3 1999/01/05 14:49:34 armin - * Added experimental usage of full BC and HLC for - * speech, 3.1kHz audio, fax gr.2/3 - * - * Revision 1.2 1999/01/04 13:19:29 armin - * Channel status with listen-request wrong - fixed. - * - * Revision 1.1 1999/01/01 18:09:41 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -161,25 +32,14 @@ #include "eicon.h" #include "eicon_idi.h" #include "eicon_dsp.h" +#include "uxio.h" #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.33 $"; +char *eicon_idi_revision = "$Revision: 1.41.6.1 $"; eicon_manifbuf *manbuf; -static char BC_Speech[3] = { 0x80, 0x90, 0xa3 }; -static char BC_31khz[3] = { 0x90, 0x90, 0xa3 }; -static char BC_64k[2] = { 0x88, 0x90 }; -static char BC_video[3] = { 0x91, 0x90, 0xa5 }; - -#ifdef EICON_FULL_SERVICE_OKTETT -/* -static char HLC_telephony[2] = { 0x91, 0x81 }; -*/ -static char HLC_faxg3[2] = { 0x91, 0x84 }; -#endif - int eicon_idi_manage_assign(eicon_card *card); int eicon_idi_manage_remove(eicon_card *card); int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer); @@ -209,7 +69,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0; + reqbuf->ReqId = DSIG_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ } @@ -221,6 +81,9 @@ 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_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; @@ -262,7 +125,7 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0x20; + reqbuf->ReqId = NL_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 1; /* Net Entity */ } @@ -281,6 +144,21 @@ idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch) return(0); } +int +idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan) +{ + reqbuf->Req = SUSPEND; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.P[0] = CAI; + reqbuf->XBuffer.P[1] = 1; + reqbuf->XBuffer.P[2] = chan->No; + reqbuf->XBuffer.P[3] = 0; + reqbuf->XBuffer.length = 4; + reqbuf->Reference = 0; /* Sig Entity */ + return(0); +} + int idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) { @@ -295,7 +173,7 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 32; - reqbuf->XBuffer.P[7] = 3; + reqbuf->XBuffer.P[7] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -391,6 +269,12 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) case HANGUP: idi_put_req(reqbuf, HANGUP, 0, 0); break; + case SUSPEND: + idi_put_suspend_req(reqbuf, chan); + break; + case RESUME: + idi_put_req(reqbuf, RESUME, 0 ,0); + break; case REJECT: idi_put_req(reqbuf, REJECT, 0 ,0); break; @@ -400,17 +284,20 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) case CALL_RES: idi_call_res_req(reqbuf, chan); break; - case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); + case CALL_HOLD: + idi_put_req(reqbuf, CALL_HOLD, 0, 0); break; - case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); + case N_CONNECT|0x700: + idi_put_req(reqbuf, N_CONNECT, 1, 0); break; - case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); + case N_CONNECT_ACK|0x700: + idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0); break; - case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); + case N_DISC|0x700: + idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh); + break; + case N_DISC_ACK|0x700: + idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -492,7 +379,7 @@ idi_hangup(eicon_card *card, eicon_chan *chan) if ((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) { - if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1); + if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1); } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { @@ -507,6 +394,32 @@ idi_hangup(eicon_card *card, eicon_chan *chan) return(0); } +int +capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm) +{ + if ((cm->para[0] != 3) || (cm->para[1] != 0)) + return -1; + if (cm->para[2] < 3) + return -1; + if (cm->para[4] != 0) + return -1; + switch(cm->para[3]) { + case 4: /* Suspend */ + eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No); + if (cm->para[5]) { + idi_do_req(card, chan, SUSPEND, 0); + } else { + idi_do_req(card, chan, CALL_HOLD, 0); + } + break; + case 5: /* Resume */ + eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No); + idi_do_req(card, chan, RESUME, 0); + break; + } + return 0; +} + int idi_connect_res(eicon_card *card, eicon_chan *chan) { @@ -612,7 +525,14 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, reqbuf->XBuffer.P[l++] = *sub++ & 0x7f; } - if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { + if (si2 > 2) { + reqbuf->XBuffer.P[l++] = SHIFT|6; + reqbuf->XBuffer.P[l++] = SIN; + reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = si1; + reqbuf->XBuffer.P[l++] = si2; + } + else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { reqbuf->XBuffer.P[l++] = BC; reqbuf->XBuffer.P[l++] = tmp; for(i=0; iXBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 32; - reqbuf->XBuffer.P[l++] = 3; + reqbuf->XBuffer.P[l++] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: @@ -859,7 +779,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } for(i=0; i < wlen; i++) message->llc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0], + eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0], message->llc[1],message->llc[2],message->llc[3]); break; case HLC: @@ -869,7 +789,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } for(i=0; i < wlen; i++) message->hlc[i] = buffer[pos++]; - eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No, + eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No, message->hlc[0], message->hlc[1], message->hlc[2], message->hlc[3], message->hlc[4]); break; @@ -1061,31 +981,55 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi } void -idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2) +idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2) { - si1[0] = 0; - si2[0] = 0; - if (memcmp(bc, BC_Speech, 3) == 0) { /* Speech */ - si1[0] = 1; + si1[0] = 0; + si2[0] = 0; + + switch (bc[0] & 0x7f) { + case 0x00: /* Speech */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 1; + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_31khz, 3) == 0) { /* 3.1kHz audio */ - si1[0] = 1; + break; + case 0x10: /* 3.1 Khz audio */ + si1[0] = 1; #ifdef EICON_FULL_SERVICE_OKTETT - si2[0] = 2; - if (memcmp(hlc, HLC_faxg3, 2) == 0) { /* Fax Gr.2/3 */ - si1[0] = 2; - } + si1[0] = sin[0]; + si2[0] = sin[1]; #endif - } - if (memcmp(bc, BC_64k, 2) == 0) { /* unrestricted 64 kbits */ - si1[0] = 7; - } - if (memcmp(bc, BC_video, 3) == 0) { /* video */ - si1[0] = 4; - } + break; + case 0x08: /* Unrestricted digital information */ + si1[0] = 7; + si2[0] = sin[1]; + break; + case 0x09: /* Restricted digital information */ + si1[0] = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + si1[0] = 3; + break; + case 0x18: /* Video */ + si1[0] = 4; + break; + } + switch (bc[1] & 0x7f) { + case 0x40: /* packed mode */ + si1[0] = 8; + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + /* moderate = bc[1] & 0x7f; */ + break; + } } /********************* FAX stuff ***************************/ @@ -1225,7 +1169,7 @@ idi_send_edata(eicon_card *card, eicon_chan *chan) reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_EDATA; + reqbuf->Req = N_EDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -1359,7 +1303,7 @@ idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header) eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength); break; } - idi_send_data(card, chan, 0, skb, 0); + idi_send_data(card, chan, 0, skb, 0, 0); } void @@ -1913,7 +1857,7 @@ idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf OutBuf->Len = 0; OutBuf->Next = OutBuf->Data; - return(idi_send_data(ccard, chan, 0, skb, 1)); + return(idi_send_data(ccard, chan, 0, skb, 1, 0)); } int @@ -1958,6 +1902,8 @@ idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb) if (chan->queued + skb->len > 1200) return 0; + if (chan->pqueued > 1) + return 0; InBuf.Data = skb->data; InBuf.Size = skb->len; @@ -2183,6 +2129,7 @@ idi_fax_hangup(eicon_card *ccard, eicon_chan *chan) } if ((chan->fax->code > 1) && (chan->fax->code < 120)) chan->fax->code += 120; + eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code); chan->fax->r_code = ISDN_TTY_FAX_HNG; cmd.driver = ccard->myid; cmd.command = ISDN_STAT_FAXIND; @@ -2224,7 +2171,7 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); - reqbuf->Req = IDI_N_UDATA; + reqbuf->Req = N_UDATA; reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; @@ -2418,12 +2365,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (message.e_cau[0] & 0x7f) { cmd.driver = ccard->myid; cmd.arg = chan->No; @@ -2433,10 +2380,6 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) ccard->interface.statcallb(&cmd); } chan->cause[0] = 0; -#ifdef CONFIG_ISDN_TTY_FAX - if (!chan->e.B2Id) - chan->fax = 0; -#endif if (((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) || ((chan->l2prot == ISDN_PROTO_L2_FAX) && @@ -2446,6 +2389,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) if (chan->e.B2Id) idi_do_req(ccard, chan, REMOVE, 1); chan->statectrl &= ~WAITING_FOR_HANGUP; + chan->statectrl &= ~IN_HOLD; 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; @@ -2463,6 +2407,9 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) cmd.command = ISDN_STAT_DHUP; ccard->interface.statcallb(&cmd); eicon_idi_listen_req(ccard, chan); +#ifdef CONFIG_ISDN_TTY_FAX + chan->fax = 0; +#endif } } break; @@ -2475,7 +2422,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) break; } chan->fsm_state = EICON_STATE_ICALL; - idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2); + idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2); strcpy(chan->cpn, message.cpn + 1); strcpy(chan->oad, message.oad); strcpy(chan->dsa, message.dsa); @@ -2553,12 +2500,15 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case ISDN_PROTO_L2_MODEM: /* do nothing, wait for connect */ break; + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); break; - default: + default:; /* On most incoming calls we use automatic connect */ - /* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */ + /* idi_do_req(ccard, chan, N_CONNECT, 1); */ } } else { if (chan->fsm_state != EICON_STATE_ACTIVE) @@ -2568,33 +2518,50 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) case CALL_CON: eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No); if (chan->fsm_state == EICON_STATE_OCALL) { - chan->fsm_state = EICON_STATE_OBWAIT; - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_DCONN; - cmd.arg = chan->No; - ccard->interface.statcallb(&cmd); - /* check if old NetID has been removed */ if (chan->e.B2Id) { eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n", chan->No, chan->e.B2Id); idi_do_req(ccard, chan, REMOVE, 1); } - - idi_do_req(ccard, chan, ASSIGN, 1); - idi_do_req(ccard, chan, IDI_N_CONNECT, 1); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { - if (chan->fax) + if (chan->fax) { chan->fax->phase = ISDN_FAX_PHASE_A; + } else { + eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n"); + idi_hangup(ccard, chan); + break; + } } #endif + chan->fsm_state = EICON_STATE_OBWAIT; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + + idi_do_req(ccard, chan, ASSIGN, 1); + idi_do_req(ccard, chan, N_CONNECT, 1); } else - idi_hangup(ccard, chan); + idi_hangup(ccard, chan); break; case AOC_IND: eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No); break; + case CALL_HOLD_ACK: + chan->statectrl |= IN_HOLD; + eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No); + break; + case SUSPEND_REJ: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No); + break; + case SUSPEND: + eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No); + break; + case RESUME: + eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No); + break; default: eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind); } @@ -2613,7 +2580,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } else switch(ind->Ind) { - case IDI_N_CONNECT_ACK: + case N_CONNECT_ACK: eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No); if (chan->l2prot == ISDN_PROTO_L2_MODEM) { chan->fsm_state = EICON_STATE_WMCONN; @@ -2634,7 +2601,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } } else { - eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n"); + eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n"); } #endif break; @@ -2646,10 +2613,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_CONNECT: + case N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); chan->e.IndCh = ind->IndCh; - if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); + if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; } @@ -2664,43 +2631,47 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) strcpy(cmd.parm.num, "64000"); ccard->interface.statcallb(&cmd); break; - case IDI_N_DISC: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No); + case N_DISC: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No); if (chan->e.B2Id) { while((skb2 = skb_dequeue(&chan->e.X))) { dev_kfree_skb(skb2); } - idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1); + idi_do_req(ccard, chan, N_DISC_ACK, 1); idi_do_req(ccard, chan, REMOVE, 1); } #ifdef CONFIG_ISDN_TTY_FAX - if (chan->l2prot == ISDN_PROTO_L2_FAX) { + if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){ idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); idi_fax_hangup(ccard, chan); } #endif chan->e.IndCh = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued = 0; + chan->pqueued = 0; chan->waitq = 0; chan->waitpq = 0; - restore_flags(flags); - idi_do_req(ccard, chan, HANGUP, 0); + spin_unlock_irqrestore(&eicon_lock, flags); + if (!(chan->statectrl & IN_HOLD)) { + idi_do_req(ccard, chan, HANGUP, 0); + } if (chan->fsm_state == EICON_STATE_ACTIVE) { cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BHUP; cmd.arg = chan->No; ccard->interface.statcallb(&cmd); chan->fsm_state = EICON_STATE_NULL; - chan->statectrl |= WAITING_FOR_HANGUP; + if (!(chan->statectrl & IN_HOLD)) { + chan->statectrl |= WAITING_FOR_HANGUP; + } } #ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0; #endif break; - case IDI_N_DISC_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No); + case N_DISC_ACK: + eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); @@ -2708,10 +2679,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) } #endif break; - case IDI_N_DATA_ACK: - eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + case N_DATA_ACK: + eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No); break; - case IDI_N_DATA: + case N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len); if (chan->l2prot == ISDN_PROTO_L2_FAX) { @@ -2723,11 +2694,11 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) free_buff = 0; } break; - case IDI_N_UDATA: + case N_UDATA: idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #ifdef CONFIG_ISDN_TTY_FAX - case IDI_N_EDATA: + case N_EDATA: idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); break; #endif @@ -2747,6 +2718,8 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) { ulong flags; isdn_ctrl cmd; + int tqueued = 0; + int twaitpq = 0; if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { /* I dont know why this happens, should not ! */ @@ -2770,16 +2743,15 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); ccard->IdTable[ack->RcId] = NULL; - eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, - ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); if (!chan->e.ReqCh) chan->e.D3Id = 0; else chan->e.B2Id = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, + ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); return 1; } @@ -2790,25 +2762,21 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } else { /* Network layer */ switch(chan->e.Req & 0x0f) { - case IDI_N_CONNECT: + case N_CONNECT: chan->e.IndCh = ack->RcCh; eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); break; - case IDI_N_MDATA: - case IDI_N_DATA: - if ((chan->e.Req & 0x0f) == IDI_N_DATA) { - if (chan->queued) { - cmd.driver = ccard->myid; - cmd.command = ISDN_STAT_BSENT; - cmd.arg = chan->No; - cmd.parm.length = chan->waitpq; - ccard->interface.statcallb(&cmd); - } - save_flags(flags); - cli(); + case N_MDATA: + case N_DATA: + tqueued = chan->queued; + twaitpq = chan->waitpq; + if ((chan->e.Req & 0x0f) == N_DATA) { + spin_lock_irqsave(&eicon_lock, flags); chan->waitpq = 0; - restore_flags(flags); + if(chan->pqueued) + chan->pqueued--; + spin_unlock_irqrestore(&eicon_lock, flags); #ifdef CONFIG_ISDN_TTY_FAX if (chan->l2prot == ISDN_PROTO_L2_FAX) { if (((chan->queued - chan->waitq) < 1) && @@ -2828,11 +2796,17 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) } #endif } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); chan->queued -= chan->waitq; if (chan->queued < 0) chan->queued = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) { + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BSENT; + cmd.arg = chan->No; + cmd.parm.length = twaitpq; + ccard->interface.statcallb(&cmd); + } break; default: eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, @@ -2858,11 +2832,10 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ack->RcId]) != NULL) dCh = chan->No; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); switch (ack->Rc) { case OK_FC: @@ -2890,8 +2863,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n", chan->No, chan->e.D3Id, chan->e.B2Id); } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); for(j = 0; j < ccard->nchannels + 1; j++) { if ((ccard->bch[j].e.ref == ack->Reference) && (ccard->bch[j].e.Req == ASSIGN)) { @@ -2901,12 +2873,12 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) ccard->bch[j].e.B2Id = ack->RcId; ccard->IdTable[ack->RcId] = &ccard->bch[j]; chan = &ccard->bch[j]; - eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, - ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); break; } - } - restore_flags(flags); + } + spin_unlock_irqrestore(&eicon_lock, flags); + eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, + ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); if (j > ccard->nchannels) { eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", ack->Reference, ack->RcId); @@ -2917,6 +2889,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) case UNKNOWN_COMMAND: case WRONG_COMMAND: case WRONG_ID: + case ADAPTER_DEAD: case WRONG_CH: case UNKNOWN_IE: case WRONG_IE: @@ -2949,19 +2922,18 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) ccard->interface.statcallb(&cmd); } } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if (chan) { chan->e.ref = 0; chan->e.busy = 0; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); dev_kfree_skb(skb); eicon_schedule_tx(ccard); } int -idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que) +idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk) { struct sk_buff *xmit_skb; struct sk_buff *skb2; @@ -2985,13 +2957,14 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, return -1; if (!len) return 0; - if (chan->queued + len > EICON_MAX_QUEUE) + + if ((chk) && (chan->pqueued > 1)) return 0; - eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len); + eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n", + chan->No, len, chan->pqueued); - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while(offset < len) { plen = ((len - offset) > 270) ? 270 : len - offset; @@ -3000,7 +2973,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); if ((!xmit_skb) || (!skb2)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No); if (xmit_skb) dev_kfree_skb(skb); @@ -3013,13 +2986,10 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, chan2->ptr = chan; reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); - if (((len - offset) > 270) && - (chan->l2prot != ISDN_PROTO_L2_MODEM) && - (chan->l2prot != ISDN_PROTO_L2_FAX) && - (chan->l2prot != ISDN_PROTO_L2_TRANS)) { - reqbuf->Req = IDI_N_MDATA; + if ((len - offset) > 270) { + reqbuf->Req = N_MDATA; } else { - reqbuf->Req = IDI_N_DATA; + reqbuf->Req = N_DATA; /* if (ack) reqbuf->Req |= N_D_BIT; */ } reqbuf->ReqCh = chan->e.IndCh; @@ -3033,9 +3003,11 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, offset += plen; } - if (que) + if (que) { chan->queued += len; - restore_flags(flags); + chan->pqueued++; + } + spin_unlock_irqrestore(&eicon_lock, flags); eicon_schedule_tx(card); dev_kfree_skb(skb); return len; @@ -3073,7 +3045,7 @@ eicon_idi_manage_assign(eicon_card *card) reqbuf->XBuffer.P[0] = 0; reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; - reqbuf->ReqId = 0xe0; + reqbuf->ReqId = MAN_ID; reqbuf->XBuffer.length = 1; reqbuf->Reference = 2; /* Man Entity */ @@ -3199,7 +3171,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) reqbuf->XBuffer.P[1] = manbuf->length[0] + 1; reqbuf->XBuffer.P[l++] = 0; - reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */ + reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; reqbuf->XBuffer.length = l; diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h index 2fe6167a4347..a11039219312 100644 --- a/drivers/isdn/eicon/eicon_idi.h +++ b/drivers/isdn/eicon/eicon_idi.h @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $ * * ISDN lowlevel-module for the Eicon active cards. * IDI-Interface @@ -20,168 +20,30 @@ * along with this program; if not, write to the Free Software * 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. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:04 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/07/11 17:16:26 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.4 1999/03/29 11:19:44 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:18 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:42 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * * */ -#ifndef IDI_H -#define IDI_H +#ifndef E_IDI_H +#define E_IDI_H #include -#define ASSIGN 0x01 -#define REMOVE 0xff - -#define CALL_REQ 1 /* call request */ -#define CALL_CON 1 /* call confirmation */ -#define CALL_IND 2 /* incoming call connected */ -#define LISTEN_REQ 2 /* listen request */ -#define HANGUP 3 /* hangup request/indication */ -#define SUSPEND 4 /* call suspend request/confirm */ -#define RESUME 5 /* call resume request/confirm */ -#define SUSPEND_REJ 6 /* suspend rejected indication */ -#define USER_DATA 8 /* user data for user to user signaling */ -#define CONGESTION 9 /* network congestion indication */ -#define INDICATE_REQ 10 /* request to indicate an incoming call */ -#define INDICATE_IND 10 /* indicates that there is an incoming call */ -#define CALL_RES 11 /* accept an incoming call */ -#define CALL_ALERT 12 /* send ALERT for incoming call */ -#define INFO_REQ 13 /* INFO request */ -#define INFO_IND 13 /* INFO indication */ -#define REJECT 14 /* reject an incoming call */ -#define RESOURCES 15 /* reserve B-Channel hardware resources */ -#define TEL_CTRL 16 /* Telephone control request/indication */ -#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ -#define FAC_REG_REQ 18 /* connection idependent fac registration */ -#define FAC_REG_ACK 19 /* fac registration acknowledge */ -#define FAC_REG_REJ 20 /* fac registration reject */ -#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ -#define AOC_IND 26/* Advice of Charge */ - -#define IDI_N_MDATA (0x01) -#define IDI_N_CONNECT (0x02) -#define IDI_N_CONNECT_ACK (0x03) -#define IDI_N_DISC (0x04) -#define IDI_N_DISC_ACK (0x05) -#define IDI_N_RESET (0x06) -#define IDI_N_RESET_ACK (0x07) -#define IDI_N_DATA (0x08) -#define IDI_N_EDATA (0x09) -#define IDI_N_UDATA (0x0a) -#define IDI_N_BDATA (0x0b) -#define IDI_N_DATA_ACK (0x0c) -#define IDI_N_EDATA_ACK (0x0d) +#undef N_DATA +#undef ID_MASK -#define N_Q_BIT 0x10 /* Q-bit for req/ind */ -#define N_M_BIT 0x20 /* M-bit for req/ind */ -#define N_D_BIT 0x40 /* D-bit for req/ind */ +#include "pc.h" +#define AOC_IND 26 /* Advice of Charge */ +#define PI 0x1e /* Progress Indicator */ +#define NI 0x27 /* Notification Indicator */ -#define SHIFT 0x90 /* codeset shift */ -#define MORE 0xa0 /* more data */ -#define CL 0xb0 /* congestion level */ - - /* codeset 0 */ - -#define BC 0x04 /* Bearer Capability */ -#define CAU 0x08 /* cause */ -#define CAD 0x0c /* Connected address */ -#define CAI 0x10 /* call identity */ -#define CHI 0x18 /* channel identification */ -#define LLI 0x19 /* logical link id */ -#define CHA 0x1a /* charge advice */ -#define FTY 0x1c -#define PI 0x1e /* Progress Indicator */ -#define NI 0x27 /* Notification Indicator */ -#define DT 0x29 /* ETSI date/time */ -#define KEY 0x2c /* keypad information element */ -#define DSP 0x28 /* display */ -#define OAD 0x6c /* origination address */ -#define OSA 0x6d /* origination sub-address */ -#define CPN 0x70 /* called party number */ -#define DSA 0x71 /* destination sub-address */ -#define RDN 0x74 /* redirecting number */ -#define LLC 0x7c /* low layer compatibility */ -#define HLC 0x7d /* high layer compatibility */ -#define UUI 0x7e /* user user information */ -#define ESC 0x7f /* escape extension */ - -#define DLC 0x20 /* data link layer configuration */ -#define NLC 0x21 /* network layer configuration */ - - /* codeset 6 */ - -#define SIN 0x01 /* service indicator */ -#define CIF 0x02 /* charging information */ -#define DATE 0x03 /* date */ -#define CPS 0x07 /* called party status */ - -/*------------------------------------------------------------------*/ -/* return code coding */ -/*------------------------------------------------------------------*/ - -#define UNKNOWN_COMMAND 0x01 /* unknown command */ -#define WRONG_COMMAND 0x02 /* wrong command */ -#define WRONG_ID 0x03 /* unknown task/entity id */ -#define WRONG_CH 0x04 /* wrong task/entity id */ -#define UNKNOWN_IE 0x05 /* unknown information el. */ -#define WRONG_IE 0x06 /* wrong information el. */ -#define OUT_OF_RESOURCES 0x07 /* card out of res. */ -#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ -#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ -#define ASSIGN_OK 0xef /* ASSIGN OK */ -#define OK_FC 0xfc /* Flow-Control RC */ -#define READY_INT 0xfd /* Ready interrupt */ -#define TIMER_INT 0xfe /* timer interrupt */ -#define OK 0xff /* command accepted */ - -/*------------------------------------------------------------------*/ +#define CALL_HOLD 0x22 +#define CALL_HOLD_ACK 0x24 /* defines for statectrl */ #define WAITING_FOR_HANGUP 0x01 #define HAVE_CONN_REQ 0x02 +#define IN_HOLD 0x04 typedef struct { char cpn[32]; @@ -241,26 +103,6 @@ typedef struct { eicon_PBUFFER RBuffer; } eicon_IND; -typedef struct { - __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ - __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ - __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ - __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ - __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ - __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ - __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ - __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ - __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ - __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ - __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ - __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ - __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ - __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ - __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ - __u8 B[1]; /* buffer space for Req,Ind and Rc */ -} eicon_pr_ram; - typedef struct { __u8 *Data; unsigned int Size; @@ -278,8 +120,9 @@ extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb); extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb); extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb); -extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que); +extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk); extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value); +extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm); #ifdef CONFIG_ISDN_TTY_FAX extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan); extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb); diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c index 4f4180ed6eff..f21a045c247e 100644 --- a/drivers/isdn/eicon/eicon_io.c +++ b/drivers/isdn/eicon/eicon_io.c @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_io.c,v 1.13.6.1 2001/02/16 09:09:50 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. @@ -6,7 +6,7 @@ * Copyright 1999,2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * * This program is free software; you can redistribute it and/or modify @@ -23,52 +23,12 @@ * along with this program; if not, write to the Free Software * 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. - * Changed a few log outputs. - * - * Revision 1.7 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.6 1999/09/21 20:35:43 armin - * added more error checking. - * - * Revision 1.5 1999/08/31 11:20:11 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.4 1999/08/22 20:26:47 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.3 1999/08/18 20:17:01 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.2 1999/07/25 15:12:05 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.1 1999/03/29 11:19:45 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * */ #include #include "eicon.h" +#include "uxio.h" void eicon_io_rcv_dispatch(eicon_card *ccard) { @@ -85,12 +45,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { while((skb = skb_dequeue(&ccard->rcvq))) { ind = (eicon_IND *)skb->data; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + spin_unlock_irqrestore(&eicon_lock, flags); if (DebugVar & 1) { switch(ind->Ind) { - case IDI_N_DISC_ACK: + case N_DISC_ACK: /* doesn't matter if this happens */ break; default: @@ -99,11 +59,10 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } } - restore_flags(flags); dev_kfree_skb(skb); continue; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (chan->e.complete) { /* check for rec-buffer chaining */ if (ind->MLength == ind->RBuffer.length) { @@ -119,12 +78,9 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { } } else { - save_flags(flags); - cli(); if (!(skb2 = skb_dequeue(&chan->e.R))) { chan->e.complete = 1; eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n"); - restore_flags(flags); dev_kfree_skb(skb); continue; } @@ -133,7 +89,6 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { GFP_ATOMIC); if (!skb_new) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n"); - restore_flags(flags); dev_kfree_skb(skb); dev_kfree_skb(skb2); continue; @@ -152,14 +107,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { dev_kfree_skb(skb2); if (ind->MLength == ind->RBuffer.length) { chan->e.complete = 2; - restore_flags(flags); idi_handle_ind(ccard, skb_new); continue; } else { chan->e.complete = 0; skb_queue_tail(&chan->e.R, skb_new); - restore_flags(flags); continue; } } @@ -181,242 +134,120 @@ eicon_io_ack_dispatch(eicon_card *ccard) { /* - * IO-Functions for different card-types + * IO-Functions for ISA cards */ u8 ram_inb(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inb((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readb(addr)); - } - return(0); + return(readb(addr)); } u16 ram_inw(eicon_card *card, void *adr) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - return(inw((u16)pcard->PCIreg + M_DATA)); - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - return(readw(addr)); - } - return(0); + + return(readw(addr)); } void ram_outb(eicon_card *card, void *adr, u8 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outb((u8)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writeb(data, addr); - break; - } + writeb(data, addr); } void ram_outw(eicon_card *card, void *adr , u16 data) { - eicon_pci_card *pcard; - eicon_isa_card *icard; u32 addr = (u32) adr; - pcard = &card->hwif.pci; - icard = &card->hwif.isa; - - switch(card->type) { - case EICON_CTYPE_MAESTRA: - outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); - outw((u16)data, (u16)pcard->PCIreg + M_DATA); - break; - case EICON_CTYPE_MAESTRAP: - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - writew(data, addr); - break; - } + writew(data, addr); } void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - writeb(ram_inb(card, adr + i), adrto + i); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_fromio(adrto, adr, len); - break; - } + memcpy_fromio(adrto, adr, len); } void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { - int i; - switch(card->type) { - case EICON_CTYPE_MAESTRA: - for(i = 0; i < len; i++) { - ram_outb(card, adrto + i, readb(adr + i)); - } - break; - case EICON_CTYPE_MAESTRAP: - memcpy(adrto, adr, len); - break; - case EICON_CTYPE_S2M: - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - memcpy_toio(adrto, adr, len); - break; - } + memcpy_toio(adrto, adr, len); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * XLOG + * IDI-Callback function */ -int -eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq) +void +eicon_idi_callback(ENTITY *de) { - int timeout, i; - int divas_shared_offset = 0; + eicon_card *ccard = (eicon_card *)de->R; + struct sk_buff *skb; + eicon_RC *ack; + eicon_IND *ind; int len = 0; - int stype = 0; - __u32 time = 0; - mi_pc_maint_t *pcm = &xlogreq->pcm; - eicon_pci_card *pci_card = &card->hwif.pci; - eicon_isa_card *isa_card = &card->hwif.isa; - eicon_pr_ram *prram = 0; - char *ram; - switch(card->type) { - case EICON_CTYPE_MAESTRAP: - ram = (char *)pci_card->PCIram; - prram = (eicon_pr_ram *)ram; - divas_shared_offset = DIVAS_SHARED_OFFSET; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_MAESTRA: - prram = 0; - divas_shared_offset = 0; - len = sizeof(mi_pc_maint_t); - break; - case EICON_CTYPE_S: - case EICON_CTYPE_SX: - case EICON_CTYPE_SCOM: - case EICON_CTYPE_QUADRO: - case EICON_CTYPE_S2M: - prram = (eicon_pr_ram *)isa_card->shmem; - divas_shared_offset = 0xfb80; - len = sizeof(mi_pc_maint_t) - 78; - stype = 1; - break; - default: - return -ENODEV; - } - - memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t)); - - xlogreq->pcm.rc = 0; - xlogreq->pcm.req = 1; /* DO_LOG */ - - ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset; - - ram_outb(card, ram+1, pcm->rc); - ram_outb(card, ram+0, pcm->req); - - timeout = jiffies + 50; - while (timeout > jiffies) { - pcm->rc = ram_inb(card, ram+1); - pcm->req = ram_inb(card, ram+0); - if (!pcm->req) break; - SLEEP(10); - } - - if (pcm->req) { - return XLOG_ERR_TIMEOUT; - } - - if (pcm->rc != OK) { - return XLOG_ERR_DONE; - } - - ram_copyfromcard(card, pcm, ram, len); - - if (stype) { - for (i=0; i<8; i++) - ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i]; - time = (__u32)pcm->data.w[2] * 3600 * 1000 + - (__u32)pcm->data.w[1] * 1000 + - (__u32)pcm->data.b[1] * 20 + - (__u32)pcm->data.b[0] ; - pcm->data.w[1] = (__u16) (time >> 16); - pcm->data.w[2] = (__u16) (time & 0x0000ffff); - pcm->data.w[0] = 2; + if (de->complete == 255) { + /* Return Code */ + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = de->Rc; + if (de->Rc == ASSIGN_OK) { + ack->RcId = de->Id; + de->user[1] = de->Id; + } else { + ack->RcId = de->user[1]; + } + ack->RcCh = de->RcCh; + ack->Reference = de->user[0]; + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Rc, ack->RcId, de->RLength, de->complete); + } + } else { + /* Indication */ + if (de->complete) { + len = de->RLength; + } else { + len = 270; + if (de->RLength <= 270) + eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n"); + } + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + if (!skb) { + eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = de->Ind; + ind->IndId = de->user[1]; + ind->IndCh = de->IndCh; + ind->MInd = de->Ind; + ind->RBuffer.length = len; + ind->MLength = de->RLength; + memcpy(&ind->RBuffer.P, &de->RBuffer->P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n", + de->user[0], de->Ind, ind->IndId, de->RLength, de->complete); + } } - return XLOG_OK; + de->RNum = 0; + de->RNR = 0; + de->Rc = 0; + de->Ind = 0; } +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ /* * Transmit-Function */ void eicon_io_transmit(eicon_card *ccard) { - eicon_pci_card *pci_card; eicon_isa_card *isa_card; struct sk_buff *skb; struct sk_buff *skb2; unsigned long flags; - char *ram, *reg, *cfg; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_REQ *ReqOut = 0; @@ -426,10 +257,11 @@ eicon_io_transmit(eicon_card *ccard) { int ReqCount; int scom = 0; int tmp = 0; + int tmpid = 0; int quloop = 1; int dlev = 0; + ENTITY *ep = 0; - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; if (!ccard) { @@ -451,20 +283,17 @@ eicon_io_transmit(eicon_card *ccard) { prram = (eicon_pr_ram *)isa_card->shmem; break; #endif +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = (eicon_pr_ram *)ram; + scom = 2; + break; + case EICON_CTYPE_MAESTRAQ: + scom = 2; break; case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - prram = 0; + scom = 2; break; +#endif default: eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n"); return; @@ -474,69 +303,91 @@ eicon_io_transmit(eicon_card *ccard) { if (!(skb2 = skb_dequeue(&ccard->sndq))) quloop = 0; while(quloop) { - save_flags(flags); - cli(); - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + switch (scom) { + case 1: if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) { if (!ccard->ReadyInt) { tmp = ram_inb(ccard, &com->ReadyInt) + 1; ram_outb(ccard, &com->ReadyInt, tmp); ccard->ReadyInt++; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } - } else { + break; + case 0: if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } + break; } - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); + chan2 = (eicon_chan_ptr *)skb2->data; chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { - save_flags(flags); - cli(); + reqbuf = (eicon_REQ *)skb->data; if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); } else { - if (scom) { + spin_lock_irqsave(&eicon_lock, flags); + + switch (scom) { + case 1: ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh); - - } else { + break; + case 0: /* get address of next available request buffer */ ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)]; ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh); ram_outb(ccard, &ReqOut->Req, reqbuf->Req); + break; } + dlev = 160; + if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ - if (scom) + switch (scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.D3Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); - + break; + case 2: + ep = &chan->de; + break; + } + tmpid = chan->e.D3Id; chan->e.ReqCh = 0; } else { /* Net Layer */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, chan->e.B2Id); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); - + break; + case 2: + ep = &chan->be; + break; + } + tmpid = chan->e.B2Id; chan->e.ReqCh = 1; if (((reqbuf->Req & 0x0f) == 0x08) || ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ @@ -548,51 +399,106 @@ eicon_io_transmit(eicon_card *ccard) { } else { /* It is an ASSIGN */ - if (scom) + switch(scom) { + case 1: ram_outb(ccard, &com->ReqId, reqbuf->ReqId); - else + break; + case 0: ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); + break; + case 2: + if (!reqbuf->Reference) + ep = &chan->de; + else + ep = &chan->be; + ep->Id = reqbuf->ReqId; + break; + } + tmpid = reqbuf->ReqId; if (!reqbuf->Reference) chan->e.ReqCh = 0; else chan->e.ReqCh = 1; } - if (scom) + + switch(scom) { + case 1: chan->e.ref = ccard->ref_out++; - else + break; + case 0: chan->e.ref = ram_inw(ccard, &ReqOut->Reference); + break; + case 2: + chan->e.ref = chan->No; + break; + } chan->e.Req = reqbuf->Req; ReqCount++; - if (scom) + + switch (scom) { + case 1: ram_outb(ccard, &com->Req, reqbuf->Req); - else + break; + case 0: ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); + break; + case 2: +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (!ep) break; + ep->callback = eicon_idi_callback; + ep->R = (BUFFERS *)ccard; + ep->user[0] = (word)chan->No; + ep->user[1] = (word)tmpid; + ep->XNum = 1; + ep->RNum = 0; + ep->RNR = 0; + ep->Rc = 0; + ep->Ind = 0; + ep->X->PLength = reqbuf->XBuffer.length; + memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); + ep->ReqCh = reqbuf->ReqCh; + ep->Req = reqbuf->Req; +#endif + break; + } chan->e.busy = 1; + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", - reqbuf->Req, - (scom) ? ram_inb(ccard, &com->ReqId) : - ram_inb(ccard, &ReqOut->ReqId), + reqbuf->Req, tmpid, reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (scom == 2) { + if (ep) { + ccard->d->request(ep); + if (ep->Rc) + eicon_idi_callback(ep); + } + } +#endif } - restore_flags(flags); dev_kfree_skb(skb); } dev_kfree_skb(skb2); } else { - skb_queue_tail(&ccard->sackq, skb2); - eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); + skb_queue_tail(&ccard->sackq, skb2); + eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); } - if (scom) - quloop = 0; - else - if (!(skb2 = skb_dequeue(&ccard->sndq))) + switch(scom) { + case 1: quloop = 0; + break; + case 0: + case 2: + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + break; + } } if (!scom) @@ -603,18 +509,14 @@ eicon_io_transmit(eicon_card *ccard) { } } - +#ifdef CONFIG_ISDN_DRV_EICON_ISA /* * IRQ handler */ void eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { eicon_card *ccard = (eicon_card *)dev_id; - eicon_pci_card *pci_card; eicon_isa_card *isa_card; - char *ram = 0; - char *reg = 0; - char *cfg = 0; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_RC *RcIn; @@ -646,11 +548,9 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { } } - pci_card = &ccard->hwif.pci; isa_card = &ccard->hwif.isa; switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -664,23 +564,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { prram = (eicon_pr_ram *)isa_card->shmem; irqprobe = &isa_card->irqprobe; break; -#endif - case EICON_CTYPE_MAESTRAP: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = (eicon_pr_ram *)ram; - break; - case EICON_CTYPE_MAESTRA: - scom = 0; - ram = (char *)pci_card->PCIram; - reg = (char *)pci_card->PCIreg; - cfg = (char *)pci_card->PCIcfg; - irqprobe = &pci_card->irqprobe; - prram = 0; - break; default: eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n"); return; @@ -688,7 +571,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { if (*irqprobe) { switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -706,26 +588,11 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { } (*irqprobe)++; break; -#endif - case EICON_CTYPE_MAESTRAP: - if (readb(&ram[0x3fe])) { - writeb(0, &prram->RcOutput); - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - } - *irqprobe = 0; - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - *irqprobe = 0; - break; } return; } switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -736,20 +603,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { return; } break; -#endif - case EICON_CTYPE_MAESTRAP: - if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; - case EICON_CTYPE_MAESTRA: - outw(0x3fe, pci_card->PCIreg + M_ADDR); - if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */ - eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n"); - return; - } - break; } if (scom) { @@ -891,7 +744,6 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { /* clear interrupt */ switch(ccard->type) { -#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_QUADRO: writeb(0, isa_card->intack); writeb(0, &com[0x401]); @@ -902,19 +754,8 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { case EICON_CTYPE_S2M: writeb(0, isa_card->intack); break; -#endif - case EICON_CTYPE_MAESTRAP: - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - writeb(0, &ram[0x3fe]); - break; - case EICON_CTYPE_MAESTRA: - outb(0x08, pci_card->PCIreg + M_RESET); - outw(0x3fe, pci_card->PCIreg + M_ADDR); - outb(0, pci_card->PCIreg + M_DATA); - break; } return; } - +#endif diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index 8a7f0d099feb..e33d0414e5fc 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -21,62 +21,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_isa.c,v $ - * Revision 1.14 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * 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 (exrz73@ibm.net). - * - * Revision 1.8 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.7 1999/08/22 20:26:48 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/07/25 15:12:06 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.5 1999/04/01 12:48:33 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:46 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:45 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:19 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:43 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -87,7 +31,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.14 $"; +char *eicon_isa_revision = "$Revision: 1.16 $"; #undef EICON_MCA_DEBUG @@ -354,7 +298,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, card->physmem, card->irq, - ((eicon_card *)card->card)->regname); + ((eicon_card *)card->card)->regname, 0); printk(KERN_INFO "Eicon: %d adapters added\n", tmp); } return 0; diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h index b53adfcbf66a..1c8034f77786 100644 --- a/drivers/isdn/eicon/eicon_isa.h +++ b/drivers/isdn/eicon/eicon_isa.h @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -20,38 +20,6 @@ * along with this program; if not, write to the Free Software * 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 - * - * Revision 1.5 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber. - * - * Revision 1.4 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.3 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.2 1999/03/02 12:37:46 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_isa_h @@ -138,7 +106,6 @@ typedef struct { unsigned char mvalid; /* Flag: Memory is valid */ unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card ist Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_isa_card; /* Offsets for special locations on standard cards */ diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index 37cb64be4183..f932762d66ac 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $ +/* $Id: eicon_mod.c,v 1.37.6.4 2001/02/16 09:09:50 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -6,11 +6,9 @@ * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax * capabilities with Diva Server cards. @@ -30,105 +28,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: eicon_mod.c,v $ - * Revision 1.25 2000/02/22 16:26:40 armin - * Fixed membase error message. - * Fixed missing log buffer struct. - * - * 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 - * - * Revision 1.18 1999/10/11 18:13:25 armin - * Added fax capabilities for Eicon Diva Server cards. - * - * Revision 1.17 1999/10/08 22:09:34 armin - * Some fixes of cards interface handling. - * Bugfix of NULL pointer occurence. - * Changed a few log outputs. - * - * Revision 1.16 1999/09/26 14:17:53 armin - * Improved debug and log via readstat() - * - * Revision 1.15 1999/09/08 20:17:31 armin - * Added microchannel patch from Erik Weber (exrz73@ibm.net). - * - * Revision 1.14 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.13 1999/09/04 17:37:59 armin - * Removed not used define, did not work and caused error - * in 2.3.16 - * - * Revision 1.12 1999/08/31 11:20:14 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.11 1999/08/29 17:23:45 armin - * New setup compat. - * Bugfix if compile as not module. - * - * Revision 1.10 1999/08/28 21:32:53 armin - * Prepared for fax related functions. - * Now compilable without errors/warnings. - * - * Revision 1.9 1999/08/18 20:17:02 armin - * Added XLOG function for all cards. - * Bugfix of alloc_skb NULL pointer. - * - * Revision 1.8 1999/07/25 15:12:08 armin - * fix of some debug logs. - * enabled ISA-cards option. - * - * Revision 1.7 1999/07/11 17:16:27 armin - * Bugfixes in queue handling. - * Added DSP-DTMF decoder functions. - * Reorganized ack_handler. - * - * Revision 1.6 1999/06/09 19:31:26 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.5 1999/04/01 12:48:35 armin - * Changed some log outputs. - * - * Revision 1.4 1999/03/29 11:19:47 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.3 1999/03/02 12:37:47 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.2 1999/01/24 20:14:21 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.1 1999/01/01 18:09:44 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ -#define DRIVERPATCH "" +#define DRIVERNAME "Eicon active ISDN driver" +#define DRIVERRELEASE "2.0" +#define DRIVERPATCH ".16" + #include #include @@ -139,17 +44,27 @@ #include "eicon.h" +#include "../avmb1/capicmd.h" /* this should be moved in a common place */ + +#undef N_DATA +#include "adapter.h" +#include "uxio.h" + #define INCLUDE_INLINE_FUNCS static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.25 $"; +static char *eicon_revision = "$Revision: 1.37.6.4 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; extern char *eicon_idi_revision; +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern void eicon_pci_init_conf(eicon_card *card); + #ifdef MODULE #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) #endif @@ -158,6 +73,10 @@ extern char *eicon_idi_revision; ulong DebugVar; +spinlock_t eicon_lock; + +DESCRIPTOR idi_d[32]; + /* Parameters to be set by insmod */ #ifdef CONFIG_ISDN_DRV_EICON_ISA static int membase = -1; @@ -189,23 +108,6 @@ char *eicon_ctype_name[] = { "DIVA Server PRI/PCI" }; -static int -getrel(char *p) -{ - int v = 0; - char *tmp = 0; - - if ((tmp = strchr(p, '.'))) - p = tmp + 1; - while (p[0] >= '0' && p[0] <= '9') { - v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0'); - p++; - } - return v; - - -} - static char * eicon_getrev(const char *revision) { @@ -229,68 +131,26 @@ find_channel(eicon_card *card, int channel) return NULL; } +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI /* - * Free MSN list + * Find pcicard with given card number */ -static void -eicon_clear_msn(eicon_card *card) +static inline eicon_card * +eicon_findnpcicard(int driverid) { - struct msn_entry *p = card->msn_list; - struct msn_entry *q; - unsigned long flags; + eicon_card *p = cards; - save_flags(flags); - cli(); - card->msn_list = NULL; - restore_flags(flags); while (p) { - q = p->next; - kfree(p); - p = q; + if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) && + (p->bus == EICON_BUS_PCI)) + return p; + p = p->next; } + return (eicon_card *) 0; } - -/* - * Find an MSN entry in the list. - * If ia5 != 0, return IA5-encoded EAZ, else - * return a bitmask with corresponding bit set. - */ -static __u16 -eicon_find_msn(eicon_card *card, char *msn, int ia5) -{ - struct msn_entry *p = card->msn_list; - __u8 eaz = '0'; - - while (p) { - if (!strcmp(p->msn, msn)) { - eaz = p->eaz; - break; - } - p = p->next; - } - if (!ia5) - return (1 << (eaz - '0')); - else - return eaz; -} - -/* - * Find an EAZ entry in the list. - * return a string with corresponding msn. - */ -char * -eicon_find_eaz(eicon_card *card, char eaz) -{ - struct msn_entry *p = card->msn_list; - - while (p) { - if (p->eaz == eaz) - return(p->msn); - p = p->next; - } - return("\0"); -} - +#endif +#endif /* CONFIG_PCI */ static void eicon_rcv_dispatch(struct eicon_card *card) @@ -337,39 +197,19 @@ eicon_transmit(struct eicon_card *card) } } -static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq) -{ - xlogreq_t *xlr; - int ret_val; - - if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) { - eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n"); - return -ENOMEM; - } - if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - - ret_val = eicon_get_xlog(card, xlr); - - if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) { - kfree(xlr); - return -EFAULT; - } - kfree(xlr); - - return ret_val; -} - static int eicon_command(eicon_card * card, isdn_ctrl * c) { ulong a; eicon_chan *chan; eicon_cdef cdef; +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + dia_start_t dstart; + int idi_length = 0; +#endif +#endif isdn_ctrl cmd; - char tmp[17]; int ret = 0; unsigned long flags; @@ -383,16 +223,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_IOCTL_GETVER: return(EICON_CTRL_VERSION); case EICON_IOCTL_GETTYPE: + if (card->bus == EICON_BUS_PCI) { + copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int)); + } return(card->type); case EICON_IOCTL_GETMMIO: switch (card->bus) { case EICON_BUS_ISA: case EICON_BUS_MCA: return (int)card->hwif.isa.shmem; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.PCIram; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -433,10 +272,6 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_BUS_ISA: case EICON_BUS_MCA: return card->hwif.isa.irq; -#if CONFIG_PCI - case EICON_BUS_PCI: - return card->hwif.pci.irq; -#endif default: eicon_log(card, 1, "eicon: Illegal BUS type %d\n", @@ -514,7 +349,9 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case EICON_IOCTL_MANIF: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - if (!card->Feature & PROTCAP_MANIF) + if (!card->d) + return -ENODEV; + if (!card->d->features & DI_MANAGE) return -ENODEV; ret = eicon_idi_manage( card, @@ -522,49 +359,12 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return ret; case EICON_IOCTL_GETXLOG: - if (!card->flags & EICON_FLAGS_RUNNING) - return XLOG_ERR_CARD_STATE; - ret = eicon_xlog(card, (xlogreq_t *)a); - return ret; -#if CONFIG_PCI - case EICON_IOCTL_LOADPCI: - if (card->flags & EICON_FLAGS_RUNNING) - return -EBUSY; - if (card->bus == EICON_BUS_PCI) { - switch(card->type) { - case EICON_CTYPE_MAESTRA: - ret = eicon_pci_load_bri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - - case EICON_CTYPE_MAESTRAP: - ret = eicon_pci_load_pri( - &(card->hwif.pci), - &(((eicon_codebuf *)a)->pci)); - break; - } - if (!ret) { - card->flags |= EICON_FLAGS_LOADED; - card->flags |= EICON_FLAGS_RUNNING; - if (card->hwif.pci.channels > 1) { - cmd.command = ISDN_STAT_ADDCH; - cmd.driver = card->myid; - cmd.arg = card->hwif.pci.channels - 1; - card->interface.statcallb(&cmd); - } - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - return ret; - } else return -ENODEV; -#endif + return -ENODEV; + case EICON_IOCTL_ADDCARD: if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef)))) return -EFAULT; - if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id))) + if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0))) return -EIO; return 0; case EICON_IOCTL_DEBUGVAR: @@ -577,8 +377,87 @@ eicon_command(eicon_card * card, isdn_ctrl * c) MOD_INC_USE_COUNT; return 0; #endif - default: + case EICON_IOCTL_LOADPCI: + eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n"); + eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n"); + eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n"); + return -EINVAL; + default: +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + if (c->arg < EICON_IOCTL_DIA_OFFSET) + return -EINVAL; + if (copy_from_user(&dstart, (char *)a, sizeof(dstart))) + return -1; + if (!(card = eicon_findnpcicard(dstart.card_id))) + return -EINVAL; + ret = do_ioctl(NULL, NULL, + c->arg - EICON_IOCTL_DIA_OFFSET, + (unsigned long) a); + if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) { + if (card->type != EICON_CTYPE_MAESTRAQ) { + DIVA_DIDD_Read(idi_d, sizeof(idi_d)); + for(idi_length = 0; idi_length < 32; idi_length++) { + if (idi_d[idi_length].type == 0) break; + } + if ((idi_length < 1) || (idi_length >= 32)) { + eicon_log(card, 1, "eicon: invalid idi table length.\n"); + break; + } + card->d = &idi_d[idi_length - 1]; + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x)\n", + (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI", + card->d->channels, card->d->features); + } else { + int i; + DIVA_DIDD_Read(idi_d, sizeof(idi_d)); + for(idi_length = 0; idi_length < 32; idi_length++) + if (idi_d[idi_length].type == 0) break; + if ((idi_length < 1) || (idi_length >= 32)) { + eicon_log(card, 1, "eicon: invalid idi table length.\n"); + break; + } + for(i = 3; i >= 0; i--) { + if (!(card = eicon_findnpcicard(dstart.card_id - i))) + return -EINVAL; + + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + card->d = &idi_d[idi_length - (i+1)]; + eicon_pci_init_conf(card); + if (card->d->channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->d->channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x)\n", + 4-i, card->d->channels, card->d->features); + } + } + } + return ret; +#else return -EINVAL; +#endif +#endif /* CONFIG_PCI */ } break; case ISDN_CMD_DIAL: @@ -586,20 +465,15 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); eicon_log(card, 1, "Dial on channel %d with state %d\n", chan->No, chan->fsm_state); return -EBUSY; } - if (card->ptype == ISDN_PTYPE_EURO) - tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1); - else - tmp[0] = c->parm.setup.eazmsn[0]; chan->fsm_state = EICON_STATE_OCALL; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); ret = idi_connect_req(card, chan, c->parm.setup.phone, c->parm.setup.eazmsn, @@ -637,19 +511,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x1f))) break; - if (strlen(c->parm.num)) { - if (card->ptype == ISDN_PTYPE_EURO) { - chan->eazmask = eicon_find_msn(card, c->parm.num, 0); - } - if (card->ptype == ISDN_PTYPE_1TR6) { - int i; - chan->eazmask = 0; - for (i = 0; i < strlen(c->parm.num); i++) - if (isdigit(c->parm.num[i])) - chan->eazmask |= (1 << (c->parm.num[i] - '0')); - } - } else - chan->eazmask = 0x3ff; + chan->eazmask = 0x3ff; eicon_idi_listen_req(card, chan); return 0; case ISDN_CMD_CLREAZ: @@ -680,8 +542,10 @@ 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_FCLASS2) + if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) { chan->fax = c->parm.fax; + eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax); + } #endif return 0; case ISDN_CMD_GETL3: @@ -729,6 +593,23 @@ eicon_command(eicon_card * card, isdn_ctrl * c) break; idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); return 0; + case CAPI_PUT_MESSAGE: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (c->parm.cmsg.Length < 8) + break; + switch(c->parm.cmsg.Command) { + case CAPI_FACILITY: + if (c->parm.cmsg.Subcommand == CAPI_REQ) + return(capipmsg(card, chan, &c->parm.cmsg)); + break; + case CAPI_MANUFACTURER: + default: + break; + } + return 0; } return -EINVAL; @@ -787,8 +668,7 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel) if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); while((skb = skb_dequeue(&card->statq))) { if ((skb->len + count) > len) @@ -811,12 +691,12 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel) } else { skb_pull(skb, cnt); skb_queue_head(&card->statq, skb); - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } } card->statq_entries = 0; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); return count; } printk(KERN_ERR @@ -848,7 +728,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) } else #endif - ret = idi_send_data(card, chan, ack, skb, 1); + ret = idi_send_data(card, chan, ack, skb, 1, 1); return (ret); } else { return -ENODEV; @@ -895,12 +775,11 @@ eicon_putstatus(eicon_card * card, char * buf) return; } - save_flags(flags); - cli(); + spin_lock_irqsave(&eicon_lock, flags); count = strlen(buf); skb = alloc_skb(count, GFP_ATOMIC); if (!skb) { - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); printk(KERN_ERR "eicon: could not alloc skb in putstatus\n"); return; } @@ -918,7 +797,7 @@ eicon_putstatus(eicon_card * card, char * buf) } else card->statq_entries++; - restore_flags(flags); + spin_unlock_irqrestore(&eicon_lock, flags); if (count) { cmd.command = ISDN_STAT_STAVAIL; cmd.driver = card->myid; @@ -967,7 +846,7 @@ eicon_log(eicon_card * card, int level, const char *fmt, ...) * link it into cards-list. */ static void -eicon_alloccard(int Type, int membase, int irq, char *id) +eicon_alloccard(int Type, int membase, int irq, char *id, int card_id) { int i; int j; @@ -976,9 +855,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id) char qid[5]; #endif eicon_card *card; -#if CONFIG_PCI - eicon_pci_card *pcic; -#endif qloop = (Type == EICON_CTYPE_QUADRO)?2:0; for (i = 0; i <= qloop; i++) { @@ -1088,9 +964,9 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->interface.channels = 1; break; #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRA: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1101,11 +977,26 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L3_TRANSDSP | ISDN_FEATURE_L3_FCLASS2; card->hwif.pci.card = (void *)card; - card->hwif.pci.PCIreg = pcic->PCIreg; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; + card->hwif.pci.irq = irq; + card->hwif.pci.type = Type; + card->flags = 0; + card->nchannels = 2; + card->interface.channels = 1; + break; + + case EICON_CTYPE_MAESTRAQ: + card->bus = EICON_BUS_PCI; + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_TRANSDSP | + ISDN_FEATURE_L3_FCLASS2; + card->hwif.pci.card = (void *)card; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1114,7 +1005,6 @@ eicon_alloccard(int Type, int membase, int irq, char *id) break; case EICON_CTYPE_MAESTRAP: - (eicon_pci_card *)pcic = (eicon_pci_card *)membase; card->bus = EICON_BUS_PCI; card->interface.features |= ISDN_FEATURE_L2_V11096 | @@ -1125,13 +1015,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) ISDN_FEATURE_L3_TRANSDSP | 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; - card->hwif.pci.PCIram = pcic->PCIram; - card->hwif.pci.PCIcfg = pcic->PCIcfg; - card->hwif.pci.master = 1; - card->hwif.pci.mvalid = pcic->mvalid; - card->hwif.pci.ivalid = 0; + card->hwif.pci.master = card_id; card->hwif.pci.irq = irq; card->hwif.pci.type = Type; card->flags = 0; @@ -1139,6 +1023,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id) card->interface.channels = 1; break; #endif +#endif #ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_ISABRI: if (membase == -1) @@ -1197,6 +1082,53 @@ eicon_alloccard(int Type, int membase, int irq, char *id) skb_queue_head_init(&card->bch[j].e.X); skb_queue_head_init(&card->bch[j].e.R); } + +#ifdef CONFIG_ISDN_DRV_EICON_PCI + /* *** Diva Server *** */ + if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2 + , GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate DBUFFER-struct.\n", id); + kfree(card); + kfree(card->bch); + return; + } + if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERS-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + return; + } + if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) { + eicon_log(card, 1, + "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id); + kfree(card); + kfree(card->bch); + kfree(card->dbuf); + kfree(card->sbuf); + return; + } + for (j=0; j< (card->nchannels + 1); j++) { + memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER)); + card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j]; + memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS)); + card->bch[j].de.X = (BUFFERS *)&card->sbuf[j]; + memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS)); + card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)]; + + memset((char *)&card->sbufp[j], 0, 270); + card->bch[j].de.X->P = (char *)&card->sbufp[j * 270]; + memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270); + card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270]; + } + /* *** */ +#endif /* CONFIG_ISDN_DRV_EICON_PCI */ + card->next = cards; cards = card; } @@ -1220,10 +1152,7 @@ eicon_registercard(eicon_card * card) #endif /* CONFIG_MCA */ #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_printpar(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon_registercard: Illegal BUS type %d\n", @@ -1241,8 +1170,7 @@ eicon_registercard(eicon_card * card) return 0; } -#ifdef MODULE -static void +static void unregister_card(eicon_card * card) { isdn_ctrl cmd; @@ -1260,10 +1188,7 @@ unregister_card(eicon_card * card) break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI - eicon_pci_release(&card->hwif.pci); break; -#endif default: eicon_log(card, 1, "eicon: Invalid BUS type %d\n", @@ -1271,7 +1196,6 @@ unregister_card(eicon_card * card) break; } } -#endif /* MODULE */ static void eicon_freecard(eicon_card *card) { @@ -1295,13 +1219,17 @@ eicon_freecard(eicon_card *card) { while((skb = skb_dequeue(&card->statq))) dev_kfree_skb(skb); - eicon_clear_msn(card); +#ifdef CONFIG_ISDN_DRV_EICON_PCI + kfree(card->sbufp); + kfree(card->sbuf); + kfree(card->dbuf); +#endif kfree(card->bch); kfree(card); } int -eicon_addcard(int Type, int membase, int irq, char *id) +eicon_addcard(int Type, int membase, int irq, char *id, int card_id) { eicon_card *p; eicon_card *q = NULL; @@ -1314,7 +1242,7 @@ eicon_addcard(int Type, int membase, int irq, char *id) if ((Type = eicon_isa_find_card(membase, irq, id)) < 0) return 0; #endif - eicon_alloccard(Type, membase, irq, id); + eicon_alloccard(Type, membase, irq, id, card_id); p = cards; while (p) { registered = 0; @@ -1333,11 +1261,13 @@ eicon_addcard(int Type, int membase, int irq, char *id) break; #endif case EICON_BUS_PCI: -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI if (eicon_registercard(p)) break; registered = 1; break; +#endif #endif default: printk(KERN_ERR @@ -1371,46 +1301,35 @@ eicon_addcard(int Type, int membase, int irq, char *id) return (added - failed); } -#define DRIVERNAME "Eicon active ISDN driver" -#define DRIVERRELEASE "1" -#ifdef MODULE -#define eicon_init init_module -#endif - -int +static int __init eicon_init(void) { int card_count = 0; - int release = 0; char tmprev[50]; DebugVar = 1; + eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED; printk(KERN_INFO "%s Rev: ", DRIVERNAME); strcpy(tmprev, eicon_revision); printk("%s/", eicon_getrev(tmprev)); - release += getrel(tmprev); strcpy(tmprev, eicon_pci_revision); -#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_isa_revision); #ifdef CONFIG_ISDN_DRV_EICON_ISA printk("%s/", eicon_getrev(tmprev)); #else printk("---/"); #endif - release += getrel(tmprev); strcpy(tmprev, eicon_idi_revision); printk("%s\n", eicon_getrev(tmprev)); - release += getrel(tmprev); - sprintf(tmprev,"%d", release); - printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME, - DRIVERRELEASE, tmprev, DRIVERPATCH); + printk(KERN_INFO "%s Release: %s%s\n", DRIVERNAME, + DRIVERRELEASE, DRIVERPATCH); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1427,18 +1346,23 @@ eicon_init(void) card_count++; }; #else - card_count = eicon_addcard(0, membase, irq, id); + card_count = eicon_addcard(0, membase, irq, id, 0); #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ -#if CONFIG_PCI +#ifdef CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + DivasCardsDiscover(); card_count += eicon_pci_find_card(id); #endif +#endif + if (!cards) { #ifdef MODULE -#ifndef CONFIG_PCI +#ifndef CONFIG_ISDN_DRV_EICON_PCI #ifndef CONFIG_ISDN_DRV_EICON_ISA printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n"); + printk(KERN_INFO "Eicon: Driver not loaded !\n"); #else printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n"); #endif @@ -1451,17 +1375,34 @@ eicon_init(void) } else printk(KERN_INFO "Eicon: %d card%s added\n", card_count, (card_count>1)?"s":""); - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; return 0; } -#ifdef MODULE -void -cleanup_module(void) +#ifdef CONFIG_ISDN_DRV_EICON_PCI +void DIVA_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write); +EXPORT_SYMBOL_NOVERS(DivasPrintf); +#else +int DivasCardNext; +card_t DivasCards[1]; +#endif + +static void +eicon_exit(void) { +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + card_t *pCard; + word wCardIndex; + extern int Divas_major; + int iTmp = 0; +#endif +#endif + eicon_card *card = cards; eicon_card *last; + while (card) { #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1481,10 +1422,58 @@ cleanup_module(void) card = card->next; eicon_freecard(last); } + +#if CONFIG_PCI +#ifdef CONFIG_ISDN_DRV_EICON_PCI + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) + { + if ((pCard->hw) && (pCard->hw->in_use)) + { + (*pCard->card_reset)(pCard); + + UxIsrRemove(pCard->hw, pCard); + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + + if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + release_region(pCard->hw->io_base,0x20); + release_region(pCard->hw->reset_base,0x80); + } + + // If this is a 4BRI ... + if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + // Skip over the next 3 virtual adapters + wCardIndex += 3; + + // But free their handles + for (iTmp = 0; iTmp < 3; iTmp++) + { + pCard++; + UxCardHandleFree(pCard->hw); + + if(pCard->e_tbl != NULL) + { + kfree(pCard->e_tbl); + } + } + } + } + pCard++; + } + unregister_chrdev(Divas_major, "Divas"); +#endif +#endif /* CONFIG_PCI */ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } -#else /* no module */ +#ifndef MODULE void eicon_setup(char *str, int *ints) @@ -1669,7 +1658,7 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ return ENODEV; }; /* matching membase & irq */ - if ( 1 == eicon_addcard(type, membase, irq, id)) { + if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name); mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards); @@ -1691,3 +1680,5 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ +module_init(eicon_init); +module_exit(eicon_exit); diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c index c9bbb8048c5b..8d5b60f98b78 100644 --- a/drivers/isdn/eicon/eicon_pci.c +++ b/drivers/isdn/eicon/eicon_pci.c @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.c,v 1.15.6.2 2001/02/16 09:09:50 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -6,11 +6,9 @@ * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * - * Deutsche Telekom AG for S2M support. - * * 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) @@ -25,53 +23,6 @@ * along with this program; if not, write to the Free Software * 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. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/08/11 21:01:11 keil - * new PCI codefix - * - * Revision 1.8 1999/08/10 16:02:20 calle - * struct pci_dev changed in 2.3.13. Made the necessary changes. - * - * Revision 1.7 1999/06/09 19:31:29 armin - * Wrong PLX size for request_region() corrected. - * Added first MCA code from Erik Weber. - * - * Revision 1.6 1999/04/01 12:48:37 armin - * Changed some log outputs. - * - * Revision 1.5 1999/03/29 11:19:49 armin - * I/O stuff now in seperate file (eicon_io.c) - * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. - * - * Revision 1.4 1999/03/02 12:37:48 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.3 1999/01/24 20:14:24 armin - * Changed and added debug stuff. - * Better data sending. (still problems with tty's flip buffer) - * - * Revision 1.2 1999/01/10 18:46:06 armin - * Bug with wrong values in HLC fixed. - * Bytes to send are counted and limited now. - * - * Revision 1.1 1999/01/01 18:09:45 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #include @@ -80,894 +31,90 @@ #include "eicon.h" #include "eicon_pci.h" +#undef N_DATA +#include "adapter.h" +#include "uxio.h" -char *eicon_pci_revision = "$Revision: 1.11 $"; +char *eicon_pci_revision = "$Revision: 1.15.6.2 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ - -#undef EICON_PCI_DEBUG +#ifdef CONFIG_ISDN_DRV_EICON_PCI int eicon_pci_find_card(char *ID) { - if (pci_present()) { - struct pci_dev *pdev = NULL; - int pci_nextindex=0, pci_cards=0, pci_akt=0; - int pci_type = PCI_MAESTRA; - int NoMorePCICards = FALSE; - char *ram, *reg, *cfg; - unsigned int pram=0, preg=0, pcfg=0; - char did[12]; - eicon_pci_card *aparms; - - if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) { - printk(KERN_WARNING - "eicon_pci: Could not allocate card-struct.\n"); - return 0; - } - - for (pci_cards = 0; pci_cards < 0x0f; pci_cards++) - { - do { - if ((pdev = pci_find_device(PCI_VENDOR_EICON, - pci_type, - pdev))) + int pci_cards = 0; + int card_id = 0; + int had_q = 0; + int ctype = 0; + char did[20]; + card_t *pCard; + word wCardIndex; + + pCard = DivasCards; + for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) { - pci_nextindex++; - break; - } - else { - pci_nextindex = 0; - switch (pci_type) /* switch to next card type */ - { - case PCI_MAESTRA: - pci_type = PCI_MAESTRAQ; break; - case PCI_MAESTRAQ: - pci_type = PCI_MAESTRAQ_U; break; - case PCI_MAESTRAQ_U: - pci_type = PCI_MAESTRAP; break; - default: - case PCI_MAESTRAP: - NoMorePCICards = TRUE; - } - } - } - while (!NoMorePCICards); - if (NoMorePCICards) - { - if (pci_cards < 1) { - printk(KERN_INFO "Eicon: No supported PCI cards found.\n"); - kfree(aparms); - return 0; - } - else - { - printk(KERN_INFO "Eicon: %d PCI card%s registered.\n", - pci_cards, (pci_cards > 1) ? "s":""); - kfree(aparms); - return (pci_cards); - } - } - - pci_akt = 0; - switch(pci_type) - { - case PCI_MAESTRA: - printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRA; - - aparms->irq = pdev->irq; - preg = pdev->base_address[ 2] & 0xfffffffc; - pcfg = pdev->base_address[ 1] & 0xffffff80; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg); -#endif - pci_akt = 1; - break; - - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n"); - pci_cards--; - pci_akt = 0; - break; - - case PCI_MAESTRAP: - printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n"); - aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/ - aparms->irq = pdev->irq; - pram = pdev->base_address[ 0] & 0xfffff000; - preg = pdev->base_address[ 2] & 0xfffff000; - pcfg = pdev->base_address[ 4] & 0xfffff000; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); - printk(KERN_DEBUG "eicon_pci: ram=0x%x\n", - (pram)); - printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", - (preg)); - printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", - (pcfg)); -#endif - pci_akt = 1; - break; - default: - printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n"); - pci_cards--; - pci_akt = 0; - break; - } - - if (pci_akt) { - /* remapping memory */ - switch(pci_type) + if ((pCard->hw) && (pCard->hw->in_use)) { - case PCI_MAESTRA: - aparms->PCIreg = (unsigned int) preg; - aparms->PCIcfg = (unsigned int) pcfg; - if (check_region((aparms->PCIreg), 0x20)) { - printk(KERN_WARNING "eicon_pci: reg port already in use !\n"); - aparms->PCIreg = 0; - break; - } else { - request_region(aparms->PCIreg, 0x20, "eicon reg"); - } - if (check_region((aparms->PCIcfg), 0x80)) { - printk(KERN_WARNING "eicon_pci: cfg port already in use !\n"); - aparms->PCIcfg = 0; - release_region(aparms->PCIreg, 0x20); - break; - } else { - request_region(aparms->PCIcfg, 0x80, "eicon cfg"); + switch(pCard->hw->card_type) { + case DIA_CARD_TYPE_DIVA_SERVER: + ctype = EICON_CTYPE_MAESTRAP; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_B: + ctype = EICON_CTYPE_MAESTRA; + card_id++; + had_q = 0; + break; + case DIA_CARD_TYPE_DIVA_SERVER_Q: + ctype = EICON_CTYPE_MAESTRAQ; + if (!had_q) + card_id++; + if (++had_q >=4) + had_q = 0; + break; + default: + printk(KERN_ERR "eicon_pci: unknown card type %d !\n", + pCard->hw->card_type); + goto err; } - break; - case PCI_MAESTRAQ: - case PCI_MAESTRAQ_U: - case PCI_MAESTRAP: - aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000); - ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET); - reg = ioremap(preg, 0x4000); - cfg = ioremap(pcfg, 0x1000); - aparms->PCIram = (unsigned int) ram; - aparms->PCIreg = (unsigned int) reg; - aparms->PCIcfg = (unsigned int) cfg; - break; - } - if ((!aparms->PCIreg) || (!aparms->PCIcfg)) { - printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; - } else { - aparms->mvalid = 1; - sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards); - - printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did); - - if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) { + if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) { printk(KERN_ERR "eicon_pci: Card could not be added !\n"); - pci_cards--; + } else { + pci_cards++; + printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n", + eicon_ctype_name[ctype], did, card_id); } +err:; } + pCard++; } - - } - } else - printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n"); - return 0; -} - -/* - * Checks protocol file id for "F#xxxx" string fragment to - * extract the features, supported by this protocol version. - * binary representation of the feature string value is returned - * in *value. The function returns 0 if feature string was not - * found or has a wrong format, else 1. - */ -static int GetProtFeatureValue(char *sw_id, int *value) -{ - __u8 i, offset; - - while (*sw_id) - { - if ((sw_id[0] == 'F') && (sw_id[1] == '#')) - { - sw_id = &sw_id[2]; - for (i=0, *value=0; i<4; i++, sw_id++) - { - if ((*sw_id >= '0') && (*sw_id <= '9')) - { - offset = '0'; - } - else if ((*sw_id >= 'A') && (*sw_id <= 'F')) - { - offset = 'A' + 10; - } - else if ((*sw_id >= 'a') && (*sw_id <= 'f')) - { - offset = 'a' + 10; - } - else - { - return 0; - } - *value |= (*sw_id - offset) << (4*(3-i)); - } - return 1; - } - else - { - sw_id++; - } - } - return 0; + return pci_cards; } - void -eicon_pci_printpar(eicon_pci_card *card) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->PCIreg, - (unsigned int)card->PCIcfg, - card->irq); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - printk(KERN_INFO "%s at 0x%x, irq %d\n", - eicon_ctype_name[card->type], - (unsigned int)card->shmem, - card->irq); -#ifdef EICON_PCI_DEBUG - printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram); - printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg); - printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); -#endif - break; - } -} - - -static void -eicon_pci_release_shmem(eicon_pci_card *card) { - if (!card->master) - return; - if (card->mvalid) { - switch (card->type) { - case EICON_CTYPE_MAESTRA: - /* reset board */ - outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */ - outb(0, card->PCIreg + M_RESET); - SLEEP(20); - outb(0, card->PCIreg + M_ADDRH); - outw(0, card->PCIreg + M_ADDR); - outw(0, card->PCIreg + M_DATA); - - release_region(card->PCIreg, 0x20); - release_region(card->PCIcfg, 0x80); - break; - case EICON_CTYPE_MAESTRAQ: - case EICON_CTYPE_MAESTRAQ_U: - case EICON_CTYPE_MAESTRAP: - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - iounmap((void *)card->shmem); - iounmap((void *)card->PCIreg); - iounmap((void *)card->PCIcfg); - break; - } - } - card->mvalid = 0; -} - -static void -eicon_pci_release_irq(eicon_pci_card *card) { - if (!card->master) - return; - if (card->ivalid) - free_irq(card->irq, card); - card->ivalid = 0; -} - -void -eicon_pci_release(eicon_pci_card *card) { - eicon_pci_release_irq(card); - eicon_pci_release_shmem(card); -} - -/* - * Upload buffer content to adapters shared memory - * on verify error, 1 is returned and a message is printed on screen - * else 0 is returned - * Can serve IO-Type and Memory type adapters - */ -int eicon_upload(t_dsp_download_space *p_para, - __u16 length, /* byte count */ - __u8 *buffer, - int verify) +eicon_pci_init_conf(eicon_card *card) { - __u32 i, dwdata = 0, val = 0, timeout; - __u16 data; - eicon_pci_boot *boot = 0; - - switch (p_para->type) /* actions depend on type of union */ - { - case DL_PARA_IO_TYPE: - for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */ - outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); - } - if (verify) /* check written block */ - { - for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); - outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); - data = inw(p_para->dat.io.ioDATA); - if (data != *(u16 *)&buffer[i]) - { - p_para->dat.io.r3addr += i; - p_para->dat.io.BadData = data; - p_para->dat.io.GoodData = *(u16 *)&buffer[i]; - return 1; - } - } - } - break; - - case DL_PARA_MEM_TYPE: - boot = p_para->dat.mem.boot; - writel(p_para->dat.mem.r3addr, &boot->addr); - for (i=0; i> 2], &boot->data[i]); - } - if (verify) /* check written block */ - { - for (i=0; idata[i]); - if (((u32 *)buffer)[i >> 2] != dwdata) - { - p_para->dat.mem.r3addr += i; - p_para->dat.mem.BadData = dwdata; - p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2]; - return 1; - } - } - } - writel(((length + 3) / 4), &boot->len); /* len in dwords */ - writel(2, &boot->cmd); - - timeout = jiffies + 20; - while (timeout > jiffies) { - val = readl(&boot->cmd); - if (!val) break; - SLEEP(2); + int j; + + /* initializing some variables */ + card->ReadyInt = 0; + + for(j = 0; j < 256; j++) + card->IdTable[j] = NULL; + + for(j = 0; j < (card->d->channels + 1); j++) { + card->bch[j].e.busy = 0; + card->bch[j].e.D3Id = 0; + card->bch[j].e.B2Id = 0; + card->bch[j].e.ref = 0; + card->bch[j].e.Req = 0; + card->bch[j].e.complete = 1; + card->bch[j].fsm_state = EICON_STATE_NULL; } - if (val) - { - p_para->dat.mem.timeout = 1; - return 1; - } - break; - } - return 0; } - -/* show header information of code file */ -static -int eicon_pci_print_hdr(unsigned char *code, int offset) -{ - unsigned char hdr[80]; - int i, fvalue = 0; - - i = 0; - while ((i < (sizeof(hdr) -1)) - && (code[offset + i] != '\0') - && (code[offset + i] != '\r') - && (code[offset + i] != '\n')) - { - hdr[i] = code[offset + i]; - i++; - } - hdr[i] = '\0'; - printk(KERN_DEBUG "Eicon: loading %s\n", hdr); - if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue); - else return(0); -} - - -/* - * Configure a card, download code into BRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - int i,j; - int timeout; - unsigned int offset, offp=0, size, length; - int signature = 0; - int FeatureValue = 0; - eicon_pci_codebuf cbuf; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - unsigned char *code; - unsigned int reg; - unsigned int cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - reg = card->PCIreg; - cfg = card->PCIcfg; - - /* reset board */ - outb(0, reg + M_RESET); - SLEEP(10); - outb(0, reg + M_ADDRH); - outw(0, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card\n"); -#endif - - /* clear shared memory */ - outb(0xff, reg + M_ADDRH); - outw(0, reg + M_ADDR); - for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA); - SLEEP(10); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: clear shared memory\n"); #endif - - /* download protocol and dsp file */ - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_IO_TYPE; - dl_para.dat.io.ioADDR = reg + M_ADDR; - dl_para.dat.io.ioADDRH = reg + M_ADDRH; - dl_para.dat.io.ioDATA = reg + M_DATA; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j == 0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - offset = 0; - - if (j == 0) dl_para.dat.io.r3addr = 0; - if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32); - - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - kfree(code); - return -EIO; - } - /* move onto next block */ - offset += length; - dl_para.dat.io.r3addr += length; - } while (offset < size); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* clear signature */ - outb(0xff, reg + M_ADDRH); - outw(0x1e, reg + M_ADDR); - outw(0, reg + M_DATA); - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* copy configuration data into shared memory */ - outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA); - outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA); - outw(10,reg + M_ADDR); outb(0, reg + M_DATA); - outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA); - outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA); - outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */ - outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA); - outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA); - outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */ - outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */ - outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA); - outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA); - outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA); - outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA); - - for (i=0;i<32;i++) - { - outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA); - outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA); - outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA); - outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA); - outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA); - outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA); - } - -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: starting CPU...\n"); -#endif - /* let the CPU run */ - outw(0x08, reg + M_RESET); - - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - outw(0x1e, reg + M_ADDR); - signature = inw(reg + M_DATA); - if (signature == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if (signature != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - outb(0xff, reg + M_ADDRH); - outw(0x3f6, reg + M_ADDR); - card->channels = inw(reg + M_DATA); - card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - /* Trigger an interrupt and check if it is delivered */ - outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */ - outb(0x89, reg + M_RESET); /* place int request */ - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(5); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; -} - - -/* - * Configure a card, download code into PRI card, - * check if we get interrupts and return 0 on succes. - * Return -ERRNO on failure. - */ -int -eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) { - eicon_pci_boot *boot; - eicon_pr_ram *prram; - int i,j; - int timeout; - int FeatureValue = 0; - unsigned int offset, offp=0, size, length; - unsigned long int signature = 0; - t_dsp_download_space dl_para; - t_dsp_download_desc dsp_download_table; - eicon_pci_codebuf cbuf; - unsigned char *code; - unsigned char req_int; - char *ram, *reg, *cfg; - - if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) - return -EFAULT; - - boot = &card->shmem->boot; - ram = (char *)card->PCIram; - reg = (char *)card->PCIreg; - cfg = (char *)card->PCIcfg; - prram = (eicon_pr_ram *)ram; - - /* reset board */ - writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); - SLEEP(20); - writeb(0, card->PCIreg + MP_RESET); - SLEEP(20); - - /* set command count to 0 */ - writel(0, &boot->reserved); - - /* check if CPU increments the life word */ - i = readw(&boot->live); - SLEEP(20); - if (i == readw(&boot->live)) { - printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n"); -#endif - - /* download firmware : DSP and Protocol */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); -#endif - - /* Allocate code-buffer */ - if (!(code = kmalloc(400, GFP_KERNEL))) { - printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); - return -ENOMEM; - } - - /* prepare protocol upload */ - dl_para.type = DL_PARA_MEM_TYPE; - dl_para.dat.mem.boot = boot; - - for (j = 0; j <= cbuf.dsp_code_num; j++) - { - if (j==0) size = cbuf.protocol_len; - else size = cbuf.dsp_code_len[j]; - - if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */ - - if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR; - if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + - ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); - if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE; - if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32); - - offset = 0; - do /* download block of up to 400 bytes */ - { - length = ((size - offset) >= 400) ? 400 : (size - offset); - - if (copy_from_user(code, (&cb->code) + offp + offset, length)) { - kfree(code); - return -EFAULT; - } - - if ((offset == 0) && (j < 2)) { - FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); -#ifdef EICON_PCI_DEBUG - if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue); -#endif - if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { - printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); - kfree(code); - return -EFAULT; - } - ((eicon_card *)card->card)->Feature = FeatureValue; - } - - if (eicon_upload(&dl_para, length, code, 1)) - { - if (dl_para.dat.mem.timeout == 0) - printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); - else - printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n"); - kfree(code); - return -EIO; - } - - /* move onto next block */ - offset += length; - dl_para.dat.mem.r3addr += length; - } while (offset < size); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset); -#endif - offp += size; - } - kfree(code); - - /* initialize the adapter data structure */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); -#endif - /* clear out config space */ - for (i = 0; i < 256; i++) writeb(0, &ram[i]); - - /* copy configuration down to the card */ - writeb(cbuf.tei, &ram[8]); - writeb(cbuf.nt2, &ram[9]); - writeb(0, &ram[10]); - writeb(cbuf.WatchDog, &ram[11]); - writeb(cbuf.Permanent, &ram[12]); - writeb(cbuf.XInterface, &ram[13]); - writeb(cbuf.StableL2, &ram[14]); - writeb(cbuf.NoOrderCheck, &ram[15]); - writeb(cbuf.HandsetType, &ram[16]); - writeb(0, &ram[17]); - writeb(cbuf.LowChannel, &ram[18]); - writeb(cbuf.ProtVersion, &ram[19]); - writeb(cbuf.Crc4, &ram[20]); - for (i = 0; i < 32; i++) - { - writeb(cbuf.l[0].oad[i], &ram[32 + i]); - writeb(cbuf.l[0].osa[i], &ram[64 + i]); - writeb(cbuf.l[0].spid[i], &ram[96 + i]); - writeb(cbuf.l[1].oad[i], &ram[128 + i]); - writeb(cbuf.l[1].osa[i], &ram[160 + i]); - writeb(cbuf.l[1].spid[i], &ram[192 + i]); - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: configured card OK\n"); -#endif - - /* start adapter */ -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: tell card to start...\n"); -#endif - writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */ - writel(3, &boot->cmd); /* DIVAS_START_CMD */ - - /* wait till card ACKs */ - timeout = jiffies + (5*HZ); - while (timeout > jiffies) { - signature = readl(&boot->signature); - if ((signature >> 16) == DIVAS_SIGNATURE) break; - SLEEP(2); - } - if ((signature >> 16) != DIVAS_SIGNATURE) - { -#ifdef EICON_PCI_DEBUG - printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE); -#endif - printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n"); - return -EIO; - } -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); -#endif - - /* get serial number and number of channels supported by card */ - card->channels = readb(&ram[0x3f6]); - card->serial = readl(&ram[0x3f0]); - printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); - printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); - - /* test interrupt */ - readb(&ram[0x3fe]); - writeb(0, &ram[0x3fe]); /* reset any pending interrupt */ - readb(&ram[0x3fe]); - - writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); - writew(0, &cfg[MP_IRQ_RESET + 2]); - - card->irqprobe = 1; - - if (!card->ivalid) { - if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) - { - printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); - return -EIO; - } - } - card->ivalid = 1; - - req_int = readb(&prram->ReadyInt); -#ifdef EICON_PCI_DEBUG - printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); -#endif - req_int++; - /* Trigger an interrupt and check if it is delivered */ - writeb(req_int, &prram->ReadyInt); - - timeout = jiffies + 20; - while (timeout > jiffies) { - if (card->irqprobe != 1) break; - SLEEP(2); - } - if (card->irqprobe == 1) { - free_irq(card->irq, card); - card->ivalid = 0; - printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); - return -EIO; - } - - /* initializing some variables */ - ((eicon_card *)card->card)->ReadyInt = 0; - for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; - for(j=0; j< (card->channels + 1); j++) { - ((eicon_card *)card->card)->bch[j].e.busy = 0; - ((eicon_card *)card->card)->bch[j].e.D3Id = 0; - ((eicon_card *)card->card)->bch[j].e.B2Id = 0; - ((eicon_card *)card->card)->bch[j].e.ref = 0; - ((eicon_card *)card->card)->bch[j].e.Req = 0; - ((eicon_card *)card->card)->bch[j].e.complete = 1; - ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; - } - - printk(KERN_INFO "Eicon: Card successfully started\n"); - - return 0; -} - #endif /* CONFIG_PCI */ diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h index 384cc422c536..17fd4183a7a9 100644 --- a/drivers/isdn/eicon/eicon_pci.h +++ b/drivers/isdn/eicon/eicon_pci.h @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards (PCI part). * @@ -19,26 +19,6 @@ * along with this program; if not, write to the Free Software * 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. - * - * Revision 1.2 1999/03/02 12:37:50 armin - * Added some important checks. - * Analog Modem with DSP. - * Channels will be added to Link-Level after loading firmware. - * - * Revision 1.1 1999/01/01 18:09:46 armin - * First checkin of new eicon driver. - * DIVA-Server BRI/PCI and PRI/PCI are supported. - * Old diehl code is obsolete. - * - * */ #ifndef eicon_pci_h @@ -46,147 +26,20 @@ #ifdef __KERNEL__ - -#define PCI_VENDOR_EICON 0x1133 -#define PCI_DIVA_PRO20 0xe001 /* Not supported */ -#define PCI_DIVA20 0xe002 /* Not supported */ -#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */ -#define PCI_DIVA20_U 0xe004 /* Not supported */ -#define PCI_MAESTRA 0xe010 -#define PCI_MAESTRAQ 0xe012 -#define PCI_MAESTRAQ_U 0xe013 -#define PCI_MAESTRAP 0xe014 - -#define DIVA_PRO20 1 -#define DIVA20 2 -#define DIVA_PRO20_U 3 -#define DIVA20_U 4 -#define MAESTRA 5 -#define MAESTRAQ 6 -#define MAESTRAQ_U 7 -#define MAESTRAP 8 - -#define TRUE 1 -#define FALSE 0 - -#define DIVAS_SIGNATURE 0x4447 - - -/* MAESTRA BRI PCI */ - -#define M_RESET 0x10 /* offset of reset register */ -#define M_DATA 0x00 /* offset of data register */ -#define M_ADDR 0x04 /* offset of address register */ -#define M_ADDRH 0x0c /* offset of high address register */ - -#define M_DSP_CODE_LEN 0xbf7d0000 -#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */ -#define M_DSP_CODE_BASE 0xbf7a0000 -#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */ - - - -/* MAESTRA PRI PCI */ - -#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */ - -#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */ -#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */ - -#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */ -#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */ -#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ -#define MP_DSP_CODE_BASE 0xa03a0000 -#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */ - -#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */ - -/* RESET register bits */ -#define _MP_S2M_RESET 0x10 /* active lo */ -#define _MP_LED2 0x08 /* 1 = on */ -#define _MP_LED1 0x04 /* 1 = on */ -#define _MP_DSP_RESET 0x02 /* active lo */ -#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */ - -/* boot interface structure */ -typedef struct { - __u32 cmd __attribute__ ((packed)); - __u32 addr __attribute__ ((packed)); - __u32 len __attribute__ ((packed)); - __u32 err __attribute__ ((packed)); - __u32 live __attribute__ ((packed)); - __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed)); - __u32 signature __attribute__ ((packed)); - __u8 data[1]; /* real interface description */ -} eicon_pci_boot; - - -#define DL_PARA_IO_TYPE 0 -#define DL_PARA_MEM_TYPE 1 - -typedef struct tag_dsp_download_space -{ - __u16 type; /* see definitions above to differ union elements */ - union - { - struct - { - __u32 r3addr; - __u16 ioADDR; - __u16 ioADDRH; - __u16 ioDATA; - __u16 BadData; /* in case of verify error */ - __u16 GoodData; - } io; /* for io based adapters */ - struct - { - __u32 r3addr; - eicon_pci_boot *boot; - __u32 BadData; /* in case of verify error */ - __u32 GoodData; - __u16 timeout; - } mem; /* for memory based adapters */ - } dat; -} t_dsp_download_space; - - -/* Shared memory */ -typedef union { - eicon_pci_boot boot; -} eicon_pci_shmem; - /* * card's description */ typedef struct { - int ramsize; int irq; /* IRQ */ - unsigned int PCIram; - unsigned int PCIreg; - unsigned int PCIcfg; - long int serial; /* Serial No. */ int channels; /* No. of supported channels */ void* card; - eicon_pci_shmem* shmem; /* Shared-memory area */ - unsigned char* intack; /* Int-Acknowledge */ - unsigned char* stopcpu; /* Writing here stops CPU */ - unsigned char* startcpu; /* Writing here starts CPU */ unsigned char type; /* card type */ - unsigned char irqprobe; /* Flag: IRQ-probing */ - unsigned char mvalid; /* Flag: Memory is valid */ - unsigned char ivalid; /* Flag: IRQ is valid */ unsigned char master; /* Flag: Card is Quadro 1/4 */ - void* generic; /* Ptr to generic card struct */ } eicon_pci_card; - - -extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb); -extern void eicon_pci_release(eicon_pci_card *card); -extern void eicon_pci_printpar(eicon_pci_card *card); extern int eicon_pci_find_card(char *ID); #endif /* __KERNEL__ */ #endif /* eicon_pci_h */ + diff --git a/drivers/isdn/eicon/fourbri.c b/drivers/isdn/eicon/fourbri.c new file mode 100644 index 000000000000..0efb16fed1d4 --- /dev/null +++ b/drivers/isdn/eicon/fourbri.c @@ -0,0 +1,573 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.7 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Diva Server 4BRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" +#include "constant.h" +#include "adapter.h" +#include "uxio.h" + +#define TEST_INT_DIVAS_Q 0x13 + +#define DIVAS_MAINT_OFFSET 0xff00 /* value for 4BRI card */ +#define MQ_BOARD_DSP_OFFSET 0x00a00000 +#define MQ_DSP1_ADDR_OFFSET 0x00000008 +#define MQ_DSP_JUNK_OFFSET 0x00000400 +#define MQ_DSP1_DATA_OFFSET 0x00000000 +#define MQ_BOARD_ISAC_DSP_RESET 0x00800028 +#define MQ_BREG_RISC 0x1200 /* RISC Reset */ +#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */ +#define MQ_RISC_COLD_RESET_MASK 0x0001 /* RISC Cold reset */ +#define MQ_RISC_WARM_RESET_MASK 0x0002 /* RISC Warm reset */ +#define MQ_IRQ_REQ_ON 0x1 +#define MQ_IRQ_REQ_OFF 0x0 +#define MQ_BREG_IRQ_TEST 0x0608 +#define PLX9054_INTCSR 0x69 +#define PLX9054_INT_ENA 0x09 + +#define DIVAS_IOBASE 0x01 +#define M_PCI_RESET 0x10 + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg); +static int fourbri_ISR (card_t* card); + +int FPGA_Download(word, dword, byte *, byte *, int); +extern byte FPGA_Bytes[]; +extern void *get_card(int); + +byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte); +word GetProtFeatureValue(char *sw_id); + +void memcp(byte *dst, byte *src, dword dwLen); +int memcm(byte *dst, byte *src, dword dwLen); + +static int diva_server_4bri_reset(card_t *card) +{ + byte *ctl; + + DPRINTF(("divas: reset Diva Server 4BRI")); + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + /* stop RISC, DSP's and ISAC */ + UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0); + UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0); + + UxCardMemDetach(card->hw, ctl); + + return 0; +} + +static int diva_server_4bri_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server 4BRI")); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], config->sig_flags); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + DPRINTF(("divas: Signifying V.90")); + UxCardMemOut(card->hw, &shared[22], 4); + } + else + { + UxCardMemOut(card->hw, &shared[22], 0); + } + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_4bri_reset_int(card_t *card) +{ + byte *ctl; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + + UxCardMemDetach(card->hw, ctl); + + return; +} + + +static int diva_server_4bri_test_int(card_t *card) +{ + byte *ctl, i; + byte *reg; + + DPRINTF(("divas: test interrupt for Diva Server 4BRI")); + + /* We get the last (dummy) adapter in so we need to go back to the first */ + + card = get_card(card->cfg.card_id - 3); + + /* Enable interrupts on PLX chip */ + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA); + + UxCardMemDetach(card->hw, reg); + + /* Set the test interrupt flag */ + card->test_int_pend = TEST_INT_DIVAS_Q; + + /* Now to trigger the interrupt */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON); + + UxCardMemDetach(card->hw, ctl); + + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + if (card->test_int_pend) + { + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_4bri_load(card_t *card, dia_load_t *load) +{ + byte *pRAM=NULL; + int download_offset=0; + card_t *FirstCard; + byte sw_id[80]; + + DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id)); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]); + download_offset = 0; // Protocol code written to offset 0 + pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC); + + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword); + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword); + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + FirstCard = get_card(load->card_id - 3); + if ((card->hw->features) && (card->hw->features & PROTCAP_V90D)) + { + download_offset = MQ_V90D_DSP_CODE_BASE; + } + else + { + download_offset = MQ_ORG_DSP_CODE_BASE; + } + pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY); + break; + + case DIA_FPGA_CODE: + DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length)); + if (FPGA_Download(IDI_ADAPTER_MAESTRAQ, + card->hw->io_base, + sw_id, + load->code, + load->length + ) == -1) + { + DPRINTF(("divas: FPGA download failed")); + return -1; + } + + /* NOW reset the 4BRI */ + diva_server_4bri_reset(card); + return 0; // No need for anything further loading + + default: + DPRINTF(("divas: unknown code type")); + return -1; + } + + memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length); + + { + int mism_off; + if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length))) + { + DPRINTF(("divas: memory mismatch at offset %d", mism_off)); + UxCardMemDetach(card->hw, pRAM); + return -1; + } + } + + UxCardMemDetach(card->hw, pRAM); + + return 0; +} + +static int diva_server_4bri_start(card_t *card, byte *channels) +{ + byte *ctl; + byte *shared, i; + int adapter_num; + + DPRINTF(("divas: start Diva Server 4BRI")); + *channels = 0; + card->is_live = FALSE; + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK); + + UxPause(2); + + UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK); + + UxPause(10); + + UxCardMemDetach(card->hw, ctl); + + shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + for ( i = 0 ; i < 300 ; ++i ) + { + UxPause (10) ; + + if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 ) + { + DPRINTF(("divas: Protocol startup time %d.%02d seconds", + (i / 100), (i % 100) )); + + break; + } + } + + if (i==300) + { + DPRINTF(("divas: Timeout starting card")); + DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E]))); + + UxCardMemDetach(card->hw, shared); + return -1; + } + + UxCardMemDetach(card->hw, shared); + + for (adapter_num=3; adapter_num >= 0; adapter_num--) + { + card_t *qbri_card; + + qbri_card = get_card(card->cfg.card_id - adapter_num); + + if (qbri_card) + { + qbri_card->is_live = TRUE; + shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY); + *channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]); + UxCardMemDetach(qbri_card->hw, shared); + } + else + { + DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id)); + } + } + + diva_server_4bri_test_int(card); + + return 0; +} + +static +int diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise 4BRI specific entry points + */ + +int Divas4BriInit(card_t *card, dia_card_t *cfg) +{ +// byte sw_id[80]; +// extern int FPGA_Done; + + DPRINTF(("divas: initialise Diva Server 4BRI")); + + if (Divas4BRIInitPCI(card, cfg) == -1) + { + return -1; + } + + /* Need to download the FPGA */ +/* if (!FPGA_Done) + { + int retVal; + + retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ, + cfg->io_base, + sw_id, + FPGA_Bytes + ); + if(retVal==-1) + { + + DPRINTF(("divas: FPGA Download Failed")); + return -1; + + } + FPGA_Done = 1; + } */ + + card->card_reset = diva_server_4bri_reset; + card->card_load = diva_server_4bri_load; + card->card_config = diva_server_4bri_config; + card->card_start = diva_server_4bri_start; + card->reset_int = diva_server_4bri_reset_int; + card->card_mem_get = diva_server_4bri_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = fourbri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + +void memcp(byte *dst, byte *src, dword dwLen) +{ + while (dwLen) + { + *dst = *src; + dst++; src++; + dwLen--; + } +} + +int memcm(byte *dst, byte *src, dword dwLen) +{ + int offset = 0; + + while (offset < dwLen) + { + if(*dst != *src) + return (offset+1); + + offset++; + src++; + dst++; + } + + return 0; +} + + + +/*int fourbri_ISR (card_t* card) +{ + int served = 0; + byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); + + + if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); + UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08); + } + + UxCardMemDetach(card->hw, DivasIOBase); + + return (served != 0); +}*/ + + +static int fourbri_ISR (card_t* card) +{ + byte *ctl; + + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + UxCardMemDetach(card->hw, ctl); + + return (1); +} diff --git a/drivers/isdn/eicon/fpga.c b/drivers/isdn/eicon/fpga.c new file mode 100644 index 000000000000..dda2f1ae07eb --- /dev/null +++ b/drivers/isdn/eicon/fpga.c @@ -0,0 +1,155 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include "sys.h" +#include "idi.h" +#include "uxio.h" + +#define FPGA_PORT 0x6E +#define FPGA_DLOAD_BUFLEN 256 +#define NAME_OFFSET 0x10 +#define NAME_MAXLEN 12 +#define DATE_OFFSET 0x2c +#define DATE_MAXLEN 10 + +word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset); +void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); +void UxPause(long int); + +/*-------------------------------------------------------------------------*/ +/* Loads the FPGA configuration file onto the hardware. */ +/* Function returns 0 on success, else an error number. */ +/* On success, an identifier string is returned in the buffer */ +/* */ +/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream */ +/* file and a file read function has to be provided by the operating */ +/* system part. */ +/* ----------------------------------------------------------------------- */ +int FPGA_Download( word cardtype, + dword RegBase, + byte *strbuf, + byte FPGA_SRC[], + int FPGA_LEN + ) +{ + word i, j, k; + word baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN; + dword addr; + byte *pFPGA; + + //--- check for legal cardtype + switch (cardtype) + { + case IDI_ADAPTER_MAESTRAQ: + addr = RegBase ; // address where to access FPGA + Mask_PROGRAM = 0x0001; // FPGA pins at address + Mask_DONE = 0x0002; + Mask_CCLK = 0x0100; + Mask_DIN = 0x0400; + baseval = 0x000d; // PROGRAM hi, CCLK lo, DIN lo by default + break; + + default: + + DPRINTF(("divas: FPGA Download ,Illegal Card")); + return -1; // illegal card + } + + //--- generate id string from file content + for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k++] = ' '; + for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date + { + if (!FPGA_SRC[j]) break; + strbuf[k] = FPGA_SRC[j]; + } + strbuf[k] = 0; + + DPRINTF(("divas: FPGA Download - %s", strbuf)); + + //--- prepare download, Pulse PROGRAM pin down. + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM); // PROGRAM low pulse + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // release + UxPause(50); // wait until FPGA finised internal memory clear + + //--- check done pin, must be low + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL")); + return -1; + } + + pFPGA = FPGA_SRC; + + i = 0; + /* Move past the header */ + while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN)) + { + i++; + } + + // We've hit the 0xFF so move on to the next byte + // i++; + DPRINTF(("divas: FPGA Code starts at offset %d", i)); + + //--- put data onto the FPGA + for (;i>j)) baseval |= Mask_DIN; // write a hi + else baseval &=~Mask_DIN; // write a lo + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + } + + //--- add some additional startup clock cycles and check done pin + for (i=0; i<5; i++) + { + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK); // set CCLK hi + UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval); // set CCLK lo + } + + UxPause(100); + + if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) + { + DPRINTF(("divas: FPGA download successful")); + } + else + { + DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT))); + return -1; + } + +return 0; +} + diff --git a/drivers/isdn/eicon/idi.c b/drivers/isdn/eicon/idi.c new file mode 100644 index 000000000000..1bb57a77924a --- /dev/null +++ b/drivers/isdn/eicon/idi.c @@ -0,0 +1,867 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.8 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Core driver for Diva Server cards + * Implements the IDI interface + */ + +#include "idi.h" +#include "adapter.h" +#include "pc.h" +#include "pr_pc.h" +#include "sys.h" +#include "uxio.h" + +/* IDI request functions */ + +static void request(card_t *card, ENTITY *e); + +static void req_0(ENTITY *e) { request(&DivasCards[ 0], e); } +static void req_1(ENTITY *e) { request(&DivasCards[ 1], e); } +static void req_2(ENTITY *e) { request(&DivasCards[ 2], e); } +static void req_3(ENTITY *e) { request(&DivasCards[ 3], e); } +static void req_4(ENTITY *e) { request(&DivasCards[ 4], e); } +static void req_5(ENTITY *e) { request(&DivasCards[ 5], e); } +static void req_6(ENTITY *e) { request(&DivasCards[ 6], e); } +static void req_7(ENTITY *e) { request(&DivasCards[ 7], e); } +static void req_8(ENTITY *e) { request(&DivasCards[ 8], e); } +static void req_9(ENTITY *e) { request(&DivasCards[ 9], e); } +static void req_10(ENTITY *e) { request(&DivasCards[10], e); } +static void req_11(ENTITY *e) { request(&DivasCards[11], e); } +static void req_12(ENTITY *e) { request(&DivasCards[12], e); } +static void req_13(ENTITY *e) { request(&DivasCards[13], e); } +static void req_14(ENTITY *e) { request(&DivasCards[14], e); } +static void req_15(ENTITY *e) { request(&DivasCards[15], e); } + +IDI_CALL DivasIdiRequest[16] = +{ + &req_0, &req_1, &req_2, &req_3, + &req_4, &req_5, &req_6, &req_7, + &req_8, &req_9, &req_10, &req_11, + &req_12, &req_13, &req_14, &req_15 +}; + +#define PR_RAM ((struct pr_ram *)0) +#define RAM ((struct dual *)0) + +/*------------------------------------------------------------------*/ +/* local function prototypes */ +/*------------------------------------------------------------------*/ + +static byte isdn_rc(ADAPTER *, byte, byte, byte, word); +static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word); + +/* + * IDI related functions + */ + +static +ENTITY *entity_ptr(ADAPTER *a, byte e_no) +{ + card_t *card; + + card = a->io; + + return card->e_tbl[e_no].e; +} + +static +void CALLBACK(ADAPTER *a, ENTITY *e) +{ + card_t *card = a->io; + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, FALSE); + } + + (*e->callback)(e); +} + +static +void *PTR_P(ADAPTER *a, ENTITY *e, void *P) +{ + return(P); +} + +static +void *PTR_R(ADAPTER *a, ENTITY *e) +{ + return((void*)e->R); +} + +static +void *PTR_X(ADAPTER *a, ENTITY *e) +{ + return((void*)e->X); +} + +static +void free_entity(ADAPTER *a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].e = NULL; + card->e_count--; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +void assign_queue(ADAPTER * a, byte e_no, word ref) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].assign_ref = ref; + card->e_tbl[e_no].next = card->assign; + card->assign = e_no; + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte get_assign(ADAPTER *a, word ref) +{ + card_t *card; + byte e_no; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + e_no = (byte)card->assign; + while (e_no) + { + if (card->e_tbl[e_no].assign_ref == ref) + { + break; + } + e_no = card->e_tbl[e_no].next; + } + + UxCardUnlock(card->hw, ipl); + + return e_no; +} + +static +void req_queue(ADAPTER * a, byte e_no) +{ + card_t *card; + int ipl; + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_tbl[e_no].next = 0; + + if (card->e_head) + { + card->e_tbl[card->e_tail].next = e_no; + card->e_tail = e_no; + } + else + { + card->e_head = e_no; + card->e_tail = e_no; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + +static +byte look_req(ADAPTER * a) +{ + card_t *card; + + card = a->io; + + return(card->e_head); +} + +static +void next_req(ADAPTER * a) +{ + card_t *card; + int ipl; + + + card = a->io; + + ipl = UxCardLock(card->hw); + + card->e_head = card->e_tbl[card->e_head].next; + if (!card->e_head) + { + card->e_tail = 0; + } + + UxCardUnlock(card->hw, ipl); + + return; +} + + +/* + * IDI request function for active cards + */ +static +void request(card_t *card, ENTITY *e) +{ + word *special_req; + int i; + int ipl; + + + if (card->log_types & DIVAS_LOG_IDI) + { + DivasLogIdi(card, e, TRUE); + } + + if (!e->Req) + { + special_req = (word *) e; + + switch (*special_req) + { + case REQ_REMOVE: + return; + + case REQ_NAME: + for (i=0; i < DIM(card->cfg.name); i++) + { + ((struct get_name_s *) e)->name[i] = card->cfg.name[i]; + } + return; + + case REQ_SERIAL: + case REQ_XLOG: + DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG")); + return; + + default: + return; + } + } + + ipl = UxCardLock(card->hw); + + if (!(e->Id & 0x1f)) + { + DPRINTF(("IDI: ASSIGN req")); + + for (i = 1; i < card->e_max; i++) + { + if (!card->e_tbl[i].e) + { + break; + } + } + + if (i == card->e_max) + { + DPRINTF(("IDI: request all ids in use (IDI req ignored)")); + UxCardUnlock(card->hw, ipl); + e->Rc = OUT_OF_RESOURCES; + return; + } + + card->e_tbl[i].e = e; + card->e_count++; + + e->No = (byte) i; + e->More = 0; + e->RCurrent = 0xff; + } + else + { + i = e->No; + } + + if (e->More & XBUSY) + { + DPRINTF(("IDI: request - entity is busy")); + UxCardUnlock(card->hw, ipl); + return; + } + + e->More |= XBUSY; + e->More &= ~ XMOREF; + e->XCurrent = 0; + e->XOffset = 0; + + card->e_tbl[i].next = 0; + + if(card->e_head) + { + card->e_tbl[card->e_tail].next = i; + card->e_tail = i; + } + else + { + card->e_head = i; + card->e_tail = i; + } + + UxCardUnlock(card->hw, ipl); + + DivasScheduleRequestDpc(); + + return; +} + +static byte pr_ready(ADAPTER * a) +{ + byte ReadyCount; + + ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) - + a->ram_in(a, &PR_RAM->ReqInput)); + + if(!ReadyCount) { + if(!a->ReadyInt) { + a->ram_inc(a, &PR_RAM->ReadyInt); + a->ReadyInt++; + } + } + return ReadyCount; +} + +/*------------------------------------------------------------------*/ +/* output function */ +/*------------------------------------------------------------------*/ + +void DivasOut(ADAPTER * a) +{ + byte e_no; + ENTITY * this = NULL; + BUFFERS *X; + word length; + word i; + word clength; + REQ * ReqOut; + byte more; + byte ReadyCount; + byte ReqCount; + byte Id; + + /* while a request is pending ... */ + e_no = look_req(a); + if(!e_no) + { + return; + } + + ReadyCount = pr_ready(a); + if(!ReadyCount) + { + DPRINTF(("IDI: card not ready for next request")); + return; + } + + ReqCount = 0; + while(e_no && ReadyCount) { + + next_req(a); + + this = entity_ptr(a, e_no); + +#ifdef USE_EXTENDED_DEBUGS + if ( !this ) + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum)) + e_no = look_req(a) ; + ReadyCount-- ; + continue ; + } + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req)) + } +#else + DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh)); +#endif + + /* get address of next available request buffer */ + ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)]; + + /* now copy the data from the current data buffer into the */ + /* adapters request buffer */ + length = 0; + i = this->XCurrent; + X = PTR_X(a,this); + while(iXNum && length<270) { + clength = MIN((word)(270-length),X[i].PLength-this->XOffset); + a->ram_out_buffer(a, + &ReqOut->XBuffer.P[length], + PTR_P(a,this,&X[i].P[this->XOffset]), + clength); + + length +=clength; + this->XOffset +=clength; + if(this->XOffset==X[i].PLength) { + this->XCurrent = (byte)++i; + this->XOffset = 0; + } + } + + a->ram_outw(a, &ReqOut->XBuffer.length, length); + a->ram_out(a, &ReqOut->ReqId, this->Id); + a->ram_out(a, &ReqOut->ReqCh, this->ReqCh); + + /* if its a specific request (no ASSIGN) ... */ + + if(this->Id &0x1f) { + + /* if buffers are left in the list of data buffers do */ + /* do chaining (LL_MDATA, N_MDATA) */ + + this->More++; + if(iXNum && this->MInd) { + a->ram_out(a, &ReqOut->Req, this->MInd); + more = TRUE; + } + else { + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + more = FALSE; + } + + /* if we did chaining, this entity is put back into the */ + /* request queue */ + + if(more) { + req_queue(a,this->No); + } + } + + /* else it's a ASSIGN */ + + else { + + /* save the request code used for buffer chaining */ + + this->MInd = 0; + if (this->Id==BLLC_ID) this->MInd = LL_MDATA; + if (this->Id==NL_ID || + this->Id==TASK_ID || + this->Id==MAN_ID + ) this->MInd = N_MDATA; + + /* send the ASSIGN */ + + this->More |=XMOREF; + a->ram_out(a, &ReqOut->Req, this->Req); + + /* save the reference of the ASSIGN */ + + assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference)); + } + a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next)); + ReadyCount--; + ReqCount++; + + e_no = look_req(a); + } + + /* send the filled request buffers to the ISDN adapter */ + + a->ram_out(a, &PR_RAM->ReqInput, + (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount)); + + /* if it is a 'unreturncoded' UREMOVE request, remove the */ + /* Id from our table after sending the request */ + if(this->Req==UREMOVE && this->Id) { + Id = this->Id; + e_no = a->IdTable[Id]; + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + +} + +/*------------------------------------------------------------------*/ +/* isdn interrupt handler */ +/*------------------------------------------------------------------*/ + +byte DivasDpc(ADAPTER * a) +{ + byte Count; + RC * RcIn; + IND * IndIn; + byte c; + byte RNRId; + byte Rc; + byte Ind; + + /* if return codes are available ... */ + if((Count = a->ram_in(a, &PR_RAM->RcOutput))) { + + DPRINTF(("IDI: #Rc=%x",Count)); + + /* get the buffer address of the first return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)]; + + /* for all return codes do ... */ + while(Count--) { + + if((Rc=a->ram_in(a, &RcIn->Rc))) { + + /* call return code handler, if it is not our return code */ + /* the handler returns 2 */ + /* for all return codes we process, we clear the Rc field */ + isdn_rc(a, + Rc, + a->ram_in(a, &RcIn->RcId), + a->ram_in(a, &RcIn->RcCh), + a->ram_inw(a, &RcIn->Reference)); + + a->ram_out(a, &RcIn->Rc, 0); + } + + /* get buffer address of next return code */ + RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)]; + } + + /* clear all return codes (no chaining!) */ + a->ram_out(a, &PR_RAM->RcOutput ,0); + + /* call output function */ + DivasOut(a); + } + + /* clear RNR flag */ + RNRId = 0; + + /* if indications are available ... */ + if((Count = a->ram_in(a, &PR_RAM->IndOutput))) { + + DPRINTF(("IDI: #Ind=%x",Count)); + + /* get the buffer address of the first indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)]; + + /* for all indications do ... */ + while(Count--) { + + /* if the application marks an indication as RNR, all */ + /* indications from the same Id delivered in this interrupt */ + /* are marked RNR */ + if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) { + a->ram_out(a, &IndIn->Ind, 0); + a->ram_out(a, &IndIn->RNR, TRUE); + } + else { + Ind = a->ram_in(a, &IndIn->Ind); + if(Ind) { + RNRId = 0; + + /* call indication handler, a return value of 2 means chain */ + /* a return value of 1 means RNR */ + /* for all indications we process, we clear the Ind field */ + c = isdn_ind(a, + Ind, + a->ram_in(a, &IndIn->IndId), + a->ram_in(a, &IndIn->IndCh), + &IndIn->RBuffer, + a->ram_in(a, &IndIn->MInd), + a->ram_inw(a, &IndIn->MLength)); + + if(c==1) { + DPRINTF(("IDI: RNR")); + a->ram_out(a, &IndIn->Ind, 0); + RNRId = a->ram_in(a, &IndIn->IndId); + a->ram_out(a, &IndIn->RNR, TRUE); + } + } + } + + /* get buffer address of next indication */ + IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)]; + } + + a->ram_out(a, &PR_RAM->IndOutput, 0); + } + return FALSE; +} + +byte DivasTestInt(ADAPTER * a) +{ + return a->ram_in(a,(void *)0x3fe); +} + +void DivasClearInt(ADAPTER * a) +{ + a->ram_out(a,(void *)0x3fe,0); +} + +/*------------------------------------------------------------------*/ +/* return code handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_rc(ADAPTER * a, + byte Rc, + byte Id, + byte Ch, + word Ref) +{ + ENTITY * this; + byte e_no; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: ANum, Id, Rc)) + } +#else + DPRINTF(("IDI: ReadyInt) { + a->ReadyInt--; + return 0; + } + return 2; + } + + /* if we know this Id ... */ + e_no = a->IdTable[Id]; + if(e_no) { + + this = entity_ptr(a,e_no); + + this->RcCh = Ch; + + /* if it is a return code to a REMOVE request, remove the */ + /* Id from our table */ + if(this->Req==REMOVE && Rc==OK) { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; +/**************************************************************/ + if ((this->More & XMOREC) > 1) { + this->More &= ~XMOREC; + this->More |= 1; + DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id)); + } + } + + if (Rc==OK_FC) { + this->Rc = Rc; + this->More = (this->More & (~XBUSY | XMOREC)) | 1; + this->complete = 0xFF; + CALLBACK(a, this); + return 0; + } + if(this->More &XMOREC) + this->More--; + + /* call the application callback function */ + if(this->More &XMOREF && !(this->More &XMOREC)) { + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + } + return 0; + } + + /* if it's an ASSIGN return code check if it's a return */ + /* code to an ASSIGN request from us */ + if((Rc &0xf0)==ASSIGN_RC) { + + e_no = get_assign(a, Ref); + + if(e_no) { + + this = entity_ptr(a,e_no); + + this->Id = Id; + + /* call the application callback function */ + this->Rc = Rc; + this->More &=~XBUSY; + this->complete=0xff; + CALLBACK(a, this); + + if(Rc==ASSIGN_OK) { + a->IdTable[Id] = e_no; + } + else + { + free_entity(a, e_no); + a->IdTable[Id] = 0; + this->Id = 0; + } + return 1; + } + } + return 2; +} + +/*------------------------------------------------------------------*/ +/* indication handler */ +/*------------------------------------------------------------------*/ + +static +byte isdn_ind(ADAPTER * a, + byte Ind, + byte Id, + byte Ch, + PBUFFER * RBuffer, + byte MInd, + word MLength) +{ + ENTITY * this; + word clength; + word offset; + BUFFERS *R; + +#ifdef USE_EXTENDED_DEBUGS + { + ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ; + DPRINTF(("IDI: ANum, Id, Ind)) + } +#else + DPRINTF(("IDI: IdTable[Id]) { + + this = entity_ptr(a,a->IdTable[Id]); + + this->IndCh = Ch; + + /* if the Receive More flag is not yet set, this is the */ + /* first buffer of the packet */ + if(this->RCurrent==0xff) { + + /* check for receive buffer chaining */ + if(Ind==this->MInd) { + this->complete = 0; + this->Ind = MInd; + } + else { + this->complete = 1; + this->Ind = Ind; + } + + /* call the application callback function for the receive */ + /* look ahead */ + this->RLength = MLength; + + a->ram_look_ahead(a, RBuffer, this); + + this->RNum = 0; + CALLBACK(a, this); + + /* map entity ptr, selector could be re-mapped by call to */ + /* IDI from within callback */ + this = entity_ptr(a,a->IdTable[Id]); + + /* check for RNR */ + if(this->RNR==1) { + this->RNR = 0; + return 1; + } + + /* if no buffers are provided by the application, the */ + /* application want to copy the data itself including */ + /* N_MDATA/LL_MDATA chaining */ + if(!this->RNR && !this->RNum) { + return 0; + } + + /* if there is no RNR, set the More flag */ + this->RCurrent = 0; + this->ROffset = 0; + } + + if(this->RNR==2) { + if(Ind!=this->MInd) { + this->RCurrent = 0xff; + this->RNR = 0; + } + return 0; + } + /* if we have received buffers from the application, copy */ + /* the data into these buffers */ + offset = 0; + R = PTR_R(a,this); + do { + if(this->ROffset==R[this->RCurrent].PLength) { + this->ROffset = 0; + this->RCurrent++; + } + clength = MIN(a->ram_inw(a, &RBuffer->length)-offset, + R[this->RCurrent].PLength-this->ROffset); + if(R[this->RCurrent].P) { + a->ram_in_buffer(a, + &RBuffer->P[offset], + PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]), + clength); + } + offset +=clength; + this->ROffset +=clength; + } while(offset<(a->ram_inw(a, &RBuffer->length))); + + /* if it's the last buffer of the packet, call the */ + /* application callback function for the receive complete */ + /* call */ + if(Ind!=this->MInd) { + R[this->RCurrent].PLength = this->ROffset; + if(this->ROffset) this->RCurrent++; + this->RNum = this->RCurrent; + this->RCurrent = 0xff; + this->Ind = Ind; + this->complete = 2; + CALLBACK(a, this); + } + return 0; + } + return 2; +} diff --git a/drivers/isdn/eicon/idi.h b/drivers/isdn/eicon/idi.h new file mode 100644 index 000000000000..ac94d9a5bb1f --- /dev/null +++ b/drivers/isdn/eicon/idi.h @@ -0,0 +1,143 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* External IDI interface */ + +#if !defined(IDI_H) +#define IDI_H + +#include "sys.h" + +/* typedefs for our data structures */ + +typedef struct get_name_s GET_NAME; +typedef struct entity_s ENTITY; +typedef struct buffers_s BUFFERS; + +/* IDI request/callback function pointer */ + +typedef void (* IDI_CALL)(ENTITY *); + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} DBUFFER; + +#define REQ_NAME 0x0100 +#define BOARD_NAME_LENGTH 9 +struct get_name_s { + word command; /* command = 0x0100 */ + byte name[BOARD_NAME_LENGTH]; +}; + +#define REQ_REMOVE 0x0000 /* pointer to word which is 0 */ +#define REQ_SERIAL 0x0200 +struct get_serial_s { + word command; /* command = 0x0200 */ + dword serial; /* serial number */ +}; + +#define REQ_POSTCALL 0x0300 +struct postcall_s { + word command; /* command = 0x0300 */ + word dummy; /* not used */ + IDI_CALL callback; /* routine adress to call back */ + ENTITY *contxt; /* ptr to entity to use */ +}; + +#define REQ_XLOG 0x0400 /* structure is card dependent/defined locally */ + +struct buffers_s { + word PLength; + byte *P; +}; + +struct entity_s { + byte Req; /* pending request */ + byte Rc; /* return code received */ + byte Ind; /* indication received */ + byte ReqCh; /* channel of current Req */ + byte RcCh; /* channel of current Rc */ + byte IndCh; /* channel of current Ind */ + byte Id; /* ID used by this entity */ + byte GlobalId; /* reserved field */ + byte XNum; /* number of X-buffers */ + byte RNum; /* number of R-buffers */ + BUFFERS *X; /* pointer to X-buffer list */ + BUFFERS *R; /* pointer to R-buffer list */ + word RLength; /* length of current R-data */ + DBUFFER *RBuffer; /* buffer of current R-data */ + byte RNR; /* receive not ready flag */ + byte complete; /* receive complete status */ + IDI_CALL callback; + + word user[2]; + + /* fields used by the driver internally */ + byte No; /* entity number */ + byte reserved2; /* reserved field */ + byte More; /* R/X More flags */ + byte MInd; /* MDATA coding for this ID */ + byte XCurrent; /* current transmit buffer */ + byte RCurrent; /* current receive buffer */ + word XOffset; /* offset in x-buffer */ + word ROffset; /* offset in r-buffer */ +}; + +typedef struct { + byte type; + byte channels; + word features; + /* dword serial; */ + IDI_CALL request; +} DESCRIPTOR; + +extern void DIVA_DIDD_Read(DESCRIPTOR *, int); + + /* descriptor type field coding */ +#define IDI_ADAPTER_S 1 +#define IDI_ADAPTER_PR 2 +#define IDI_ADAPTER_DIVA 3 +#define IDI_ADAPTER_MAESTRA 4 +#define IDI_ADAPTER_MAESTRAQ 5 +#define IDI_ADAPTER_MAESTRAP 6 +#define IDI_VADAPTER 0x40 +#define IDI_DRIVER 0x80 +#define IDI_DIMAINT 0xff + +/* feature bit mask values */ + +#define DI_VOICE 0x0 /* obsolete define */ +#define DI_FAX3 0x1 +#define DI_MODEM 0x2 +#define DI_POST 0x4 +#define DI_V110 0x8 +#define DI_V120 0x10 +#define DI_POTS 0x20 +#define DI_CODEC 0x40 +#define DI_MANAGE 0x80 +#define DI_V_42 0x0100 +#define DI_EXTD_FAX 0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */ + +#endif /* IDI_H */ diff --git a/drivers/isdn/eicon/kprintf.c b/drivers/isdn/eicon/kprintf.c new file mode 100644 index 000000000000..f549a039c92e --- /dev/null +++ b/drivers/isdn/eicon/kprintf.c @@ -0,0 +1,535 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.3 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Source file for kernel interface to kernel log facility + */ + + +#include "sys.h" +#include +#undef MAX +#undef MIN + +#include +#include + +#include "divas.h" +#include "divalog.h" +#include "uxio.h" + +/* + * Implementation of printf and sprintf for kernel + */ + +#define MAX_BUFF (80) /* limit size of temporary buffers */ + +#define WRITE_CHAR(BUFFER, SIZE, C) \ + if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C) + + +/* + * convert a number to decimal ASCII + */ + +static +void do_decimal( char *temp, + int temp_len, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i < temp_len; i++) + { + temp[i] = (char) ((value % 10) + (int) '0'); + value /= 10; + } + + for (i = (temp_len - 1); temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to octal ASCII + */ + +static +void do_octal( char *temp, + unsigned int value, + char *s) + +{ + int i; + + temp[0] = '\0'; + + for (i = 1; i <= 11; i++) + { + temp[i] = (char) ((value & 07) + (int) '0'); + value >>= 3; + } + temp[11] &= '3'; + + for (i = 11; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a number to hex ASCII + */ + +static +void do_hex( char *temp, + unsigned int value, + char *s) + +{ + int i; + static + char *dec_to_hex = "0123456789abcdef"; + + temp[0] = '\0'; + + for (i = 1; i <= 8; i++) + { + temp[i] = dec_to_hex[value & 0x0f]; + value >>= 4; + } + + for (i = 8; temp[i] == '0'; i--) + { + ; + } + + if (i == 0) + { + i++; + } + + while (i >= 0) + { + *s++ = temp[i--]; + } + + return; +} + +/* + * convert a buffer to ASCII HEX + */ + +static +void do_buffer( char *buffer, + int length, + char *s) + +{ + static + char hex_char [] = "0123456789abcdef"; + char *b = buffer; + int hex_byte; + int nybble; + + length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length; + + while (length) + { + hex_byte = (int) *b++; + nybble = (hex_byte >> 4) & 0xf; + *s++ = hex_char[nybble]; + nybble = hex_byte & 0xf; + *s++ = hex_char[nybble]; + *s++ = ' '; + length--; + } + *s = '\0'; + + return; +} + +/* + * Body of sprintf function: behaves just like standard sprintf, except we + * have an extra argument (buffer size) which we use to ensure we don't + * overflow + */ + +void Divas_vsprintf( char *buffer, + int size, + char *fmt, + va_list argptr) + +{ + char c; /* single character buffer */ + int i; /* handy scratch counter */ + int f; /* format character (after %) */ + char *str; /* pointer into string */ + char temp[20]; /* temp buffer used in printing numbers */ + char string[MAX_BUFF]; /* output from number conversion */ + int length; /* length of string "str" */ + char fill; /* fill character ' ' or '0' */ + boolean_t leftjust; /* TRUE if left justified, else right justified */ + int fmax, fmin; /* field specifiers % MIN . MAX s */ + int leading; /* number of leading/trailing fill characters */ + char sign; /* set to '-' for negative decimals */ + int number; /* numeric argument */ + + char *buff_ptr; /* pointer to user's buffer of hex data */ + int buff_len; /* length of hex data */ + + /* make sure we have somthing to write into */ + + if ((!buffer) || (size <= 0)) + { + return; + } + + while (TRUE) + { + /* echo characters until end or '%' encountered */ + + while ((c = *fmt++) != '%') + { + if (!c) + { + *buffer = '\0'; + return; + } + WRITE_CHAR(buffer, size, c); + } + + /* echo %% as % */ + + if (*fmt == '%') + { + WRITE_CHAR(buffer, size, *fmt); + continue; + } + + /* %- turns on left-justify */ + + if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE))) + { + fmt++; + } + + /* %0 turns on zero filling */ + + if (*fmt == '0') + { + fill = '0'; + } + else + { + fill = ' '; + } + + /* minium field width specifier for %d, u, x, c, s */ + + fmin = 0; + + if (*fmt == '*') + { + fmin = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmin = (fmin * 10) + (*fmt++ - '0'); + } + } + + /* maximum string width specifier for %s */ + + fmax = 0; + + if (*fmt == '.') + { + if (*(++fmt) == '*') + { + fmax = va_arg(argptr, int); + fmt++; + } + else + { + while ('0' <= *fmt && *fmt <= '9') + { + fmax = (fmax * 10) + (*fmt++ - '0'); + } + } + } + + /* skip over 'l' option (ints are assumed same size as longs) */ + + if (*fmt == 'l') + { + fmt++; + } + + /* get the format chacater */ + + if (!(f = *fmt++)) + { + WRITE_CHAR(buffer, size, '%'); + *buffer = '\0'; + return; + } + + sign = '\0'; /* sign == '-' for negative decimal */ + + str = string; + + switch (f) + { + case 'c' : + string[0] = (char) va_arg(argptr, int); + string[1] = '\0'; + fmax = 0; + fill = ' '; + break; + + case 's' : + str = va_arg(argptr, char *); + fill = ' '; + break; + + case 'D' : + case 'd' : + number = va_arg(argptr, int); + if (number < 0) + { + sign = '-'; + number = -number; + } + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'U' : + case 'u' : + number = va_arg(argptr, int); + do_decimal(temp, DIM(temp), (unsigned int) number, str); + fmax = 0; + break; + + case 'O' : + case 'o' : + number = va_arg(argptr, int); + do_octal(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'X' : + case 'x' : + number = va_arg(argptr, int); + do_hex(temp, (unsigned int) number, str); + fmax = 0; + break; + + case 'H' : + case 'h' : + buff_ptr = va_arg(argptr, char *); + buff_len = va_arg(argptr, int); + do_buffer(buff_ptr, buff_len, str); + fmax = 0; + break; + + default : + WRITE_CHAR(buffer, size, ((char) f)); + break; + } + + /* get the length of the string */ + + length = 0; + while (str[length]) + { + length++; + } + + /* make sure we have fmax and fmin values that are O.K. */ + + if (fmin > DIM(string) || fmin < 0) + { + fmin = 0; + } + + if (fmax > DIM(string) || fmax < 0) + { + fmax = 0; + } + + /* figure out how many leading characters thare are */ + + leading = 0; + + if (fmax || fmin) + { + if (fmax) + { + if (length > fmax) + { + length = fmax; + } + } + + if (fmin) + { + leading = fmin - length; + } + + if (sign == '-') + { + leading--; + } + } + + /* output sign now, if fill is numeric */ + + if (sign == '-' && fill == '0') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* if right justified, output fill characters */ + + if (!leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + + /* output sign now, if fill is spaces */ + + if (sign == '-' && fill == ' ') + { + WRITE_CHAR(buffer, size, '-'); + } + + /* now the actual value */ + + for (i = 0; i < length; i++) + { + WRITE_CHAR(buffer, size, str[i]); + } + + /* if left justified, fill out with the fill character */ + + if (leftjust) + { + for (i = 0; i < leading; i++) + { + WRITE_CHAR(buffer, size, fill); + } + } + } +} + +/* + * sprintf for kernel + * + * call our vsprintf assuming user has a big buffer.... + */ + +void DivasSprintf(char *buffer, char *fmt, ...) + +{ + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + Divas_vsprintf(buffer, 1024, fmt, argptr); + + va_end(argptr); + + return; +} + +void DivasPrintf(char *fmt, ...) + +{ + klog_t log; /* log entry buffer */ + + va_list argptr; /* pointer to additional args */ + + va_start(argptr, fmt); + + /* clear log entry */ + + bzero((caddr_t) &log, sizeof(klog_t)); + + log.card = -1; + log.type = KLOG_TEXT_MSG; + + /* time stamp the entry */ + + log.time_stamp = UxTimeGet(); + + /* call vsprintf to format the user's information */ + + Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr); + + va_end(argptr); + + /* send to the log streams driver and return */ + + DivasLogAdd(&log, sizeof(klog_t)); + + return; +} diff --git a/drivers/isdn/eicon/lincfg.c b/drivers/isdn/eicon/lincfg.c new file mode 100644 index 000000000000..8092da21a0b1 --- /dev/null +++ b/drivers/isdn/eicon/lincfg.c @@ -0,0 +1,407 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.9 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#undef N_DATA /* Because we have our own definition */ + +#include +#include + +#include "sys.h" +#include "idi.h" +#include "constant.h" +#include "divas.h" +#undef ID_MASK +#include "pc.h" +#include "pr_pc.h" + +#include "adapter.h" +#include "uxio.h" + +#include +#include +#include + +#define HW_ID_EICON_PCI 0x1133 +#define HW_ID_DIVA_SERVER_P 0xE014 +#define HW_ID_DIVA_SERVER_B_ST 0xE010 +#define HW_ID_DIVA_SERVER_B_U 0xE013 +#define HW_ID_DIVA_SERVER_Q 0xE012 + +struct file_operations Divas_fops; +int Divas_major; + +extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg); +extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable); +extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset); +extern int do_open(struct inode *, struct file *); +extern int do_release(struct inode *, struct file *); + +int FPGA_Done=0; + +int DivasCardsDiscover(void) +{ + word wNumCards = 0, wDeviceIndex = 0; + byte byBus, byFunc; + word wPCIConsultation, PCItmp; + dword j, i; + unsigned int PCIserial; + dia_card_t Card; + byte *b; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_Q, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + + dword dwRAM, dwDivasIOBase, dwCFG, dwCTL; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM); + dwRAM &= 0xFFC00000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG); + dwCFG &= 0xFFFFFF00; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL); + dwCTL &= 0xFFFFE000; + + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + /* Retrieve the serial number */ + + pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC); + + for (j=0, PCItmp=0; j<10000 && !PCItmp; j++) + { + pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp); + PCItmp &= 0x8000; // extract done flag + } + + pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial); + + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000); + Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100); + Card.io_base=dwDivasIOBase; + + Card.irq = byIRQ; + + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q; + Card.bus_type = DIA_BUS_TYPE_PCI; + + FPGA_Done = 0; + + /* Create four virtual card structures as we want to treat + the 4Bri card as 4 Bri cards*/ + for(i=0;i<4;i++) + { + + b=Card.memory[DIVAS_RAM_MEMORY]; + b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1); + DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET)); + Card.memory[DIVAS_RAM_MEMORY]=b; + + b = Card.memory[DIVAS_RAM_MEMORY]; + b += MQ_SM_OFFSET; + Card.memory[DIVAS_SHARED_MEMORY] = b; + + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + + + /* Fill in Name */ + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'Q'; + Card.name[6] = '0' + i; + Card.name[7] = '\0'; + + Card.serial = PCIserial; + + Card.card_id = wNumCards; + + if (DivasCardNew(&Card) != 0) + { + // Force for loop to terminate + i = 4; + continue; + } + wNumCards++; + + }//for + } + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_ST, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n"); + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_B_U, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwPLXIOBase, dwDivasIOBase; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFF80; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFFFC; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; + Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase; + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'B'; + Card.name[6] = '\0'; + + if (check_region(Card.io_base, 0x20)) + { + printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F); + wDeviceIndex++; + continue; + } + + if (check_region(Card.reset_base, 0x80)) + { + printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F); + wDeviceIndex++; + continue; + } + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + wDeviceIndex = 0; + + while (wDeviceIndex < 10) + { + wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, + HW_ID_DIVA_SERVER_P, + wDeviceIndex, + &byBus, &byFunc); + + if (wPCIConsultation == PCIBIOS_SUCCESSFUL) + { + dword dwRAM, dwREG, dwCFG; + byte byIRQ; + + printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n"); + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM); + dwRAM &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG); + dwREG &= 0xFFFFF000; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG); + dwCFG &= 0xFFFFF000; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); + + Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000); + Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000); + Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000); + Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET; + +/* pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase); + dwPLXIOBase &= 0xFFFFFFFc; + + pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase); + dwDivasIOBase &= 0xFFFFFF80; + + pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ); +*/ + Card.card_id = wNumCards; + Card.card_type = DIA_CARD_TYPE_DIVA_SERVER; + Card.bus_type = DIA_BUS_TYPE_PCI; + Card.irq = byIRQ; +/* Card.reset_base = dwPLXIOBase; + Card.io_base = dwDivasIOBase;*/ + Card.bus_num = byBus; + Card.func_num = byFunc; + Card.slot = -1; + Card.name[0] = 'D'; + Card.name[1] = 'I'; + Card.name[2] = 'V'; + Card.name[3] = 'A'; + Card.name[4] = 'S'; + Card.name[5] = 'P'; + Card.name[6] = '\0'; + + if (DivasCardNew(&Card) != 0) + { + wDeviceIndex++; + continue; + } + wNumCards++; + } + + wDeviceIndex++; + } + + + printk(KERN_INFO "Divas: %d cards detected\n", wNumCards); + + if(wNumCards == 0) + { + return -1; + } + + Divas_fops.ioctl = do_ioctl; + Divas_fops.poll = do_poll; + Divas_fops.read = do_read; + Divas_fops.open = do_open; + Divas_fops.release = do_release; + + Divas_major = register_chrdev(0, "Divas", &Divas_fops); + + if (Divas_major < 0) + { + printk(KERN_WARNING "Divas: Unable to register character driver\n"); + return -1; + } + + return 0; +} + +/* Error return -1 */ +int DivasConfigGet(dia_card_t *card) +{ + /* Retrieve Config from O/S? Not in Linux */ + return 0; +} + +dia_config_t *DivasConfig(card_t *card, dia_config_t *config) +{ + /* If config retrieved from OS then copy the data into a dia_config_t structure here + and return the pointer here. If the config 'came from above' then just + + return config; + */ + + return config; +} + diff --git a/drivers/isdn/eicon/linchr.c b/drivers/isdn/eicon/linchr.c new file mode 100644 index 000000000000..a35979ac25b2 --- /dev/null +++ b/drivers/isdn/eicon/linchr.c @@ -0,0 +1,269 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.12 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + +#define __NO_VERSION__ +#include + +#include +#include +#include +#include + +#undef N_DATA + +#include "adapter.h" +#include "divas.h" +#include "divalog.h" + +extern int DivasCardNext; +void UxPause(long ms); +void bcopy(void *pSource, void *pDest, dword dwLength); +int DivasGetMem(mem_block_t *); + +#define DIA_IOCTL_UNLOCK 12 +void UnlockDivas(void); + +int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, + unsigned int command, unsigned long arg) +{ + dia_load_t *pDivaLoad; + dia_start_t *pDivaStart; + dia_config_t *pDivaConfig; + dia_log_t *pDivaLog; + byte *pUserCards, card_i; + word wCardNum; + mem_block_t *mem_block; + + switch (command) + { + case DIA_IOCTL_CONFIG: + pDivaConfig = (dia_config_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t))) + { + DivasCardConfig(pDivaConfig); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_DETECT: + pUserCards = (byte *) arg; + + if (!verify_area(VERIFY_WRITE, pUserCards, 20)) + { + put_user(DivasCardNext, pUserCards++); + + for (card_i=1; card_i < 20; card_i++) + { + put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++); + } + } + else + { + printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_START: + pDivaStart = (dia_start_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t))) + { + return DivasCardStart(pDivaStart->card_id); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n"); + return -1; + } + + + case DIA_IOCTL_FLAVOUR: + return 0; + + case DIA_IOCTL_LOAD: + pDivaLoad = (dia_load_t *) arg; + if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length)) + { + if (DivasCardLoad(pDivaLoad)) + { + printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n"); + return -EINVAL; + } + } + else + { + printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n"); + return -EINVAL; + } + return 0; + + case DIA_IOCTL_LOG: + pDivaLog = (dia_log_t *) arg; + + if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t))) + { + DivasLog(pDivaLog); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_XLOG_REQ: + + if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word))) + { + wCardNum = * (word *) arg; + DivasXlogReq(wCardNum); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_NUM: + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) + { + * (int *) arg = DivasCardNext; + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_LIST: + DPRINTF(("divas: DIA_IOCTL_GET_LIST")); + + if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t))) + { + DivasGetList((dia_card_list_t *)arg); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_GET_MEM: + mem_block = (mem_block_t *) arg; + + if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t))) + { + DivasGetMem(mem_block); + } + else + { + printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n"); + return -1; + } + return 0; + + case DIA_IOCTL_UNLOCK: + UnlockDivas(); + return 0; + + default: + printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command); + return -EINVAL; + } + + return -EINVAL; +} + +unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable) +{ + word wMask = 0; + + if (!DivasLogFifoEmpty()) + { + wMask |= POLLIN | POLLRDNORM; + } + + return wMask; +} + +ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset) +{ + klog_t *pClientLogBuffer = (klog_t *) pUserBuffer; + klog_t *pHeadItem; + + if (BufferSize < sizeof(klog_t)) + { + printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n", + BufferSize, sizeof(klog_t)); + return 0; + } + + pHeadItem = (klog_t *) DivasLogFifoRead(); + + if (pHeadItem) + { + bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t)); + kfree(pHeadItem); + return sizeof(klog_t); + } + + return 0; +} +static int private_usage_count; + +int do_open(struct inode *pInode, struct file *pFile) +{ + MOD_INC_USE_COUNT; +#ifdef MODULE + private_usage_count++; +#endif + return 0; +} + +int do_release(struct inode *pInode, struct file *pFile) +{ + MOD_DEC_USE_COUNT; +#ifdef MODULE + private_usage_count--; +#endif + return 0; +} + +void UnlockDivas(void) +{ + while (private_usage_count > 0) + { + private_usage_count--; + MOD_DEC_USE_COUNT; + } +} diff --git a/drivers/isdn/eicon/linio.c b/drivers/isdn/eicon/linio.c new file mode 100644 index 000000000000..3d970abce382 --- /dev/null +++ b/drivers/isdn/eicon/linio.c @@ -0,0 +1,747 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.16 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#define N_DATA + +#include +#include +#include +#include +#include +#undef N_DATA + +#include "uxio.h" + +static +int log_on=0; + +int Divasdevflag = 0; + +//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED; + +static +ux_diva_card_t card_pool[MAX_CARDS]; + +void UxPause(long int ms) +{ + int timeout = jiffies + ((ms * HZ) / 1000); + + while (time_before(jiffies, timeout)); +} + +int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg) +{ + int i; + ux_diva_card_t *c; + + if (cfg->bus_type != DIA_BUS_TYPE_PCI) + { + DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type)); + return -1; + } + + for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++) + { + ; + } + + if (i == DIM(card_pool)) + { + DPRINTF(("divas hw: card_pool exhausted")); + return -1; + } + + c = *card = &card_pool[i]; + + switch (cfg->bus_type) + { + case DIA_BUS_TYPE_PCI: + c->bus_num = cfg->bus_num; + c->func_num = cfg->func_num; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->card_type = cfg->card_type; + c->mapped = NULL; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + c->pCONTROL = cfg->memory[DIVAS_CTL_MEMORY]; + + /* c->bus_type = DIA_BUS_TYPE_PCI; + c->bus_num = cfg->bus_num & 0x3f; + c->slot = cfg->slot; + c->irq = (int) cfg->irq; + c->int_priority = (int) cfg->int_priority; + c->card_type = cfg->card_type; + c->io_base = cfg->io_base; + c->reset_base = cfg->reset_base; + c->pDRAM = cfg->memory[DIVAS_RAM_MEMORY]; + c->pDEVICES = cfg->memory[DIVAS_REG_MEMORY]; + c->pCONFIG = cfg->memory[DIVAS_CFG_MEMORY]; + c->pSHARED = cfg->memory[DIVAS_SHARED_MEMORY]; + DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM)); + DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED)); + DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG)); + c->cm_key = cm_getbrdkey("Divas", cfg->card_id);*/ + break; + default: + break; + } + + c->in_use = TRUE; + + return 0; +} + +void UxCardHandleFree(ux_diva_card_t *card) +{ + card->in_use = FALSE; +} + + +#define PLX_IOBASE 0 +#define DIVAS_IOBASE 1 +void *UxCardMemAttach(ux_diva_card_t *card, int id) +{ + if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = card->pDEVICES; + return card->pDEVICES; + break; + case DIVAS_CFG_MEMORY: + card->mapped = card->pCONFIG; + return card->pCONFIG; + break; + default: + ASSERT(FALSE); + card->mapped = NULL; + return (void *) 0; + } + } + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) + { + switch (id) + { + case PLX_IOBASE: + return (void *) card->reset_base; + break; + case DIVAS_IOBASE: + return (void *) card->io_base; + break; + default: + ASSERT(FALSE); + return 0; + } + } + + else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) + { + switch (id) + { + case DIVAS_SHARED_MEMORY: + card->mapped = card->pSHARED; + return card->pSHARED; + break; + case DIVAS_RAM_MEMORY: + card->mapped = card->pDRAM; + return card->pDRAM; + break; + case DIVAS_REG_MEMORY: + card->mapped = (void *) card->io_base; + return (void *) card->io_base; + break; + case DIVAS_CTL_MEMORY: + card->mapped = card->pCONTROL; + return card->pCONTROL; + break; + default: + // ASSERT(FALSE); + DPRINTF(("divas: Trying to attach to mem %d", id)); + card->mapped = NULL; + return (void *) 0; + } + } else + DPRINTF(("divas: Tried to attach to unknown card")); + + /* Unknown card type */ + return NULL; +} + +void UxCardMemDetach(ux_diva_card_t *card, void *address) +{ + return; // Just a place holder. No un-mapping done. +} + +void UxCardLog(int turn_on) +{ + log_on = turn_on; +} + +/* + * Control Register I/O Routines to be performed on Attached I/O ports + */ + +void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outb(the_byte, base); +} + +void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outw(the_word, base); +} + +void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + outl(the_dword, base); +} + +byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inb(base); +} + +word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset) +{ + word base = (word) (dword) AttachedBase; + + base += offset; + + return inw(base); +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address) +{ + byte b; + volatile byte* t = (byte*)address; + + b = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a)); + } + + return(b); +} + +word UxCardMemInW(ux_diva_card_t *card, void *address) +{ + word w; + volatile word* t = (word*)address; + + w = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a)); + } + + return (w); +} + +dword UxCardMemInD(ux_diva_card_t *card, void *address) +{ + dword dw; + volatile dword* t = (dword*)address; + + dw = *t; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a)); + } + + return (dw); +} + +void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + volatile byte *pSource = address; + byte *pDest = buffer; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data) +{ + volatile byte* t = (byte*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a)); + } + + *t = data; + + return; +} + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data) +{ + volatile word* t = (word*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a)); + } + + *t = data; + return; +} + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data) +{ + volatile dword* t = (dword*)address; + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a)); + } + + *t = data; + return; +} + +void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length) +{ + byte *pSource = buffer; + byte *pDest = address; + + while (length--) + { + *pDest++ = *pSource++; + } + + if (log_on) + { + byte *a = address; + a -= (int) card->mapped; + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + a)); + } + + return; +} + +/* + * Memory mapped card I/O functions + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + byte the_byte; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + + the_byte = inb(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)", + the_byte & 0xff, address)); + } + + return the_byte; +} + +word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + word the_word; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_word = inw(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)", + the_word & 0xffff, address)); + } + + return the_word; +} + +dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address) + +{ + dword the_dword; + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + the_dword = inl(card->io_base); + + if (log_on) + { + DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)", + the_dword, address)); + } + + return the_dword; +} + +void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = address; + byte *pDest = buffer; + + if ((word) (dword) address & 0x1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + *pDest = (byte) inb(card->io_base); + pDest++; + pSource++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pSource, card->io_base + 4); + insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +/* Output */ + +void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)", + data & 0xff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outb((byte) data & 0xFF, card->io_base); + + return; +} + +void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)", + data & 0xffff, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outw((word) data & 0xFFFF, card->io_base); + + return; +} + +void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data) +{ + if (log_on) + { + DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address)); + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) address, card->io_base + 4); + outl((dword) data & 0xFFFFFFFF, card->io_base); + + return; +} + +void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length) + +{ + byte *pSource = buffer; + byte *pDest = address; + + if ((word) (dword) address & 1) + { + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outb(*pSource, card->io_base); + pSource++; + pDest++; + length--; + if (!length) + { + return; + } + } + + outb(0xFF, card->io_base + 0xC); + outw((word) (dword) pDest, card->io_base + 4); + outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1); + + if (log_on) + { + pDest = buffer; + DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)", + pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff, + pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff, + address)); + } + + return; +} + +void Divasintr(int arg, void *unused, struct pt_regs *unused_regs) +{ + int i; + card_t *card = NULL; + ux_diva_card_t *ux_ref = NULL; + + for (i = 0; i < DivasCardNext; i++) + { + + if (arg == DivasCards[i].cfg.irq) + { + card = &DivasCards[i]; + ux_ref = card->hw; + + if ((ux_ref) && (card->is_live)) + { + (*ux_ref->user_isr)(ux_ref->user_isr_arg); + } + else + { + DPRINTF(("divas: ISR couldn't locate card")); + } + } + } + + return; +} + + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg) +{ + int result; + + card->user_isr = isr_fn; + card->user_isr_arg = isr_arg; + + result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg); + + return result; +} + +void UxIsrRemove(ux_diva_card_t *card, void *dev_id) +{ + free_irq(card->irq, card->user_isr_arg); +} + +void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value); + break; + case sizeof(word): + pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value); + break; + case sizeof(dword): + pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n"); + } +} + +void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value) +{ + switch (size) + { + case sizeof(byte): + pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value); + break; + case sizeof(word): + pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value); + break; + case sizeof(dword): + pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value); + break; + default: + printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n"); + } +} + +void *UxAlloc(unsigned int size) +{ + void *m; + + m = kmalloc(size, GFP_ATOMIC); + + return m; +} + +void UxFree(void *ptr) +{ + kfree(ptr); +} + +int UxCardLock(ux_diva_card_t *card) +{ + unsigned long flags; + + //spin_lock_irqsave(&diva_lock, flags); + + save_flags(flags); + cli(); + return flags; + +} + +void UxCardUnlock(ux_diva_card_t *card, int ipl) +{ + //spin_unlock_irqrestore(&diva_lock, ipl); + + restore_flags(ipl); + +} + +dword UxTimeGet(void) +{ + return jiffies; +} + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p += 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} + +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst) +{ + register volatile long *p; + register long ret; + int ipl; + + p =dst; + + ipl = UxCardLock(card); + + *p -= 1; + ret = *p; + + UxCardUnlock(card,ipl); + + return(ret); + +} diff --git a/drivers/isdn/eicon/linsys.c b/drivers/isdn/eicon/linsys.c new file mode 100644 index 000000000000..30de1cc6d9a9 --- /dev/null +++ b/drivers/isdn/eicon/linsys.c @@ -0,0 +1,167 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.10 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#include +#undef N_DATA +#include + +#include +struct pt_regs; +#include +#include + +#include "sys.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +#ifdef MODULE +void bcopy(void *pSource, void *pDest, dword dwLength) +{ + memcpy(pDest, pSource, dwLength); +} +#endif + +void bzero(void *pDataArea, dword dwLength) +{ + memset(pDataArea, 0, dwLength); +} + +int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); +*/ + return 0; +} + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Use UxPciConfigWrite routines to initialise PCI config space */ + +/* wPCIcommand = 0x03; + cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand); + + wPCIcommand = 0x280; + cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand); + + bPCIcommand = 0x30; + cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/ + + return 0; +} + +int DivasBRIInitPCI(card_t *card, dia_card_t *cfg) +{ + /* Need to set these platform dependent values after patching */ + + card->hw->reset_base = card->cfg.reset_base; + card->hw->io_base = card->cfg.io_base; + + request_region(card->hw->reset_base,0x80,"Divas"); + request_region(card->hw->io_base,0x20,"Divas"); + + + /* Same as for PRI */ + return DivasPRIInitPCI(card, cfg); +} + +/* ######################### Stubs of routines that are not done yet ################## */ +/*void DivasLogIdi(card_t *card, ENTITY *e, int request) +{ +} +*/ + +int DivasDpcSchedule(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +int DivasScheduleRequestDpc(void) +{ + static struct tq_struct DivasTask; + + DivasTask.routine = DivasDoRequestDpc; + DivasTask.data = (void *) 0; + + queue_task(&DivasTask, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +void DivasLogAdd(void *buffer, int length) +{ + static + boolean_t overflow = FALSE; + static + boolean_t busy = FALSE; + + /* make sure we're not interrupting ourselves */ + + if (busy) + { + printk(KERN_DEBUG "Divas: Logging interrupting self !\n"); + return; + } + busy = TRUE; + + /* ignore call if daemon isn't running and we've reached limit */ + + if (DivasLogFifoFull()) + { + if (!overflow) + { + printk(KERN_DEBUG "Divas: Trace buffer full\n"); + overflow = TRUE; + } + busy = FALSE; + return; + } + + DivasLogFifoWrite(buffer, length); + + busy = FALSE; + return; +} + +/* #################################################################################### */ diff --git a/drivers/isdn/eicon/log.c b/drivers/isdn/eicon/log.c new file mode 100644 index 000000000000..30018d13d614 --- /dev/null +++ b/drivers/isdn/eicon/log.c @@ -0,0 +1,176 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Source file for diva log facility + */ + +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "adapter.h" +#include "divalog.h" + +#include "uxio.h" + +/*Counter to monitor number of messages */ +static int m_count; + +#define MAX_BUFFERED_MSGS (1000) + +/* Our Linked List Structure to hold message */ +typedef struct klog_link{ + klog_t klog; + struct klog_link *next; +}KNODE; + +/* First & Last structures in list*/ +KNODE *head; +KNODE *tail; + +/* + * retrieve message from FIFO buffer + * returns NULL if buffer empty + * otherwise returns pointer to entry + */ + +char *DivasLogFifoRead(void) + +{ + KNODE *old_head; + + if(head==NULL) + { + /* Buffer Empty - No Messages */ + return NULL; + } + + m_count--; + /* Keep track of message to be read & increment to next message*/ + old_head = head; + head = head->next; + /*Return ptr to Msg */ + return((char *)old_head); +} + +/* + * write message into FIFO buffer + */ + +void DivasLogFifoWrite(char *entry, int length) + +{ + KNODE *new_klog; + + if(head == NULL) + { + /* No Entries in Log */ + tail=NULL; + m_count=0; + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Set head & tail to point to the new Msg Struct */ + head=tail=new_klog; + tail->next=NULL; + } + else + { + new_klog=UxAlloc(sizeof(KNODE)); + + if(new_klog==NULL) + { + return; + } + + m_count++; + bzero(new_klog,sizeof(KNODE)); + + /* Let last Msg Struct point to new Msg Struct & inc tail */ + tail->next=new_klog; + tail=new_klog; + tail->next=NULL; + } + + if (length > sizeof(klog_t)) + { + length = sizeof(klog_t); + } + + bcopy(entry,&tail->klog,length); + + return; +} + +/* + * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE + */ +int DivasLogFifoEmpty(void) +{ + return (m_count == 0); +} + +/* + *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE + */ +int DivasLogFifoFull(void) +{ + return (m_count == MAX_BUFFERED_MSGS); +} + +/* + * generate an IDI log entry + */ + +void DivasLogIdi(card_t *card, ENTITY *e, int request) + +{ + klog_t klog; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = UxTimeGet(); + + klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ? + sizeof(klog.buffer) : sizeof(ENTITY); + + klog.card = (int) (card - DivasCards); + + klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK; + klog.code = 0; + bcopy(e, klog.buffer, klog.length); + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} diff --git a/drivers/isdn/eicon/pc.h b/drivers/isdn/eicon/pc.h new file mode 100644 index 000000000000..0ba821ad2600 --- /dev/null +++ b/drivers/isdn/eicon/pc.h @@ -0,0 +1,317 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef PC_H_INCLUDED +#define PC_H_INCLUDED + + +#define byte unsigned char +#define word unsigned short +#define dword unsigned long +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/*------------------------------------------------------------------*/ +/* buffer definition */ +/*------------------------------------------------------------------*/ + +typedef struct { + word length; /* length of data/parameter field */ + byte P[270]; /* data/parameter field */ +} PBUFFER; + +/*------------------------------------------------------------------*/ +/* dual port ram structure */ +/*------------------------------------------------------------------*/ + +struct dual +{ + byte Req; /* request register */ + byte ReqId; /* request task/entity identification */ + byte Rc; /* return code register */ + byte RcId; /* return code task/entity identification */ + byte Ind; /* Indication register */ + byte IndId; /* Indication task/entity identification */ + byte IMask; /* Interrupt Mask Flag */ + byte RNR; /* Receiver Not Ready (set by PC) */ + byte XLock; /* XBuffer locked Flag */ + byte Int; /* ISDN-S interrupt */ + byte ReqCh; /* Channel field for layer-3 Requests */ + byte RcCh; /* Channel field for layer-3 Returncodes */ + byte IndCh; /* Channel field for layer-3 Indications */ + byte MInd; /* more data indication field */ + word MLength; /* more data total packet length */ + byte ReadyInt; /* request field for ready interrupt */ + byte SWReg; /* Software register for special purposes */ + byte Reserved[11]; /* reserved space */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-S adapter Signature (GD) */ + PBUFFER XBuffer; /* Transmit Buffer */ + PBUFFER RBuffer; /* Receive Buffer */ +}; + +/*------------------------------------------------------------------*/ +/* SWReg Values (0 means no command) */ +/*------------------------------------------------------------------*/ +#define SWREG_DIE_WITH_LEDON 0x01 +#define SWREG_HALT_CPU 0x02 /* Push CPU into a while(1) loop */ + +/*------------------------------------------------------------------*/ +/* Id Fields Coding */ +/*------------------------------------------------------------------*/ + +#define ID_MASK 0xe0 /* Mask for the ID field */ +#define GL_ERR_ID 0x1f /* ID for error reporting on global requests*/ + +#define DSIG_ID 0x00 /* ID for D-channel signaling */ +#define NL_ID 0x20 /* ID for network-layer access (B or D) */ +#define BLLC_ID 0x60 /* ID for B-channel link level access */ +#define TASK_ID 0x80 /* ID for dynamic user tasks */ +#define TIMER_ID 0xa0 /* ID for timer task */ +#define TEL_ID 0xc0 /* ID for telephone support */ +#define MAN_ID 0xe0 /* ID for management */ + +/*------------------------------------------------------------------*/ +/* ASSIGN and REMOVE requests are the same for all entities */ +/*------------------------------------------------------------------*/ + +#define ASSIGN 0x01 +#define UREMOVE 0xfe /* without returncode */ +#define REMOVE 0xff + +/*------------------------------------------------------------------*/ +/* Timer Interrupt Task Interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TIM 0x01 +#define REMOVE_TIM 0xff + +/*------------------------------------------------------------------*/ +/* dynamic user task interface */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_TSK 0x01 +#define REMOVE_TSK 0xff + +#define LOAD 0xf0 +#define RELOCATE 0xf1 +#define START 0xf2 +#define LOAD2 0xf3 +#define RELOCATE2 0xf4 + +/*------------------------------------------------------------------*/ +/* dynamic user task messages */ +/*------------------------------------------------------------------*/ + +#define TSK_B2 0x0000 +#define TSK_WAKEUP 0x2000 +#define TSK_TIMER 0x4000 +#define TSK_TSK 0x6000 +#define TSK_PC 0xe000 + +/*------------------------------------------------------------------*/ +/* LL management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_LL 1 /* assign logical link */ +#define REMOVE_LL 0xff /* remove logical link */ + +/*------------------------------------------------------------------*/ +/* LL service primitives */ +/*------------------------------------------------------------------*/ + +#define LL_UDATA 1 /* link unit data request/indication */ +#define LL_ESTABLISH 2 /* link establish request/indication */ +#define LL_RELEASE 3 /* link release request/indication */ +#define LL_DATA 4 /* data request/indication */ +#define LL_LOCAL 5 /* switch to local operation (COM only) */ +#define LL_DATA_PEND 5 /* data pending indication (SDLC SHM only) */ +#define LL_REMOTE 6 /* switch to remote operation (COM only) */ +#define LL_TEST 8 /* link test request */ +#define LL_MDATA 9 /* more data request/indication */ +#define LL_BUDATA 10 /* broadcast unit data request/indication */ +#define LL_XID 12 /* XID command request/indication */ +#define LL_XID_R 13 /* XID response request/indication */ + +/*------------------------------------------------------------------*/ +/* NL service primitives */ +/*------------------------------------------------------------------*/ + +#define N_MDATA 1 /* more data to come REQ/IND */ +#define N_CONNECT 2 /* OSI N-CONNECT REQ/IND */ +#define N_CONNECT_ACK 3 /* OSI N-CONNECT CON/RES */ +#define N_DISC 4 /* OSI N-DISC REQ/IND */ +#define N_DISC_ACK 5 /* OSI N-DISC CON/RES */ +#define N_RESET 6 /* OSI N-RESET REQ/IND */ +#define N_RESET_ACK 7 /* OSI N-RESET CON/RES */ +#define N_DATA 8 /* OSI N-DATA REQ/IND */ +#define N_EDATA 9 /* OSI N-EXPEDITED DATA REQ/IND */ +#define N_UDATA 10 /* OSI D-UNIT-DATA REQ/IND */ +#define N_BDATA 11 /* BROADCAST-DATA REQ/IND */ +#define N_DATA_ACK 12 /* data ack ind for D-bit procedure */ +#define N_EDATA_ACK 13 /* data ack ind for INTERRUPT */ + +#define N_Q_BIT 0x10 /* Q-bit for req/ind */ +#define N_M_BIT 0x20 /* M-bit for req/ind */ +#define N_D_BIT 0x40 /* D-bit for req/ind */ + +/*------------------------------------------------------------------*/ +/* Signaling management primitives */ +/*------------------------------------------------------------------*/ + +#define ASSIGN_SIG 1 /* assign signaling task */ +#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */ +#define REMOVE_SIG 0xff /* remove signaling task */ + +/*------------------------------------------------------------------*/ +/* Signaling service primitives */ +/*------------------------------------------------------------------*/ + +#define CALL_REQ 1 /* call request */ +#define CALL_CON 1 /* call confirmation */ +#define CALL_IND 2 /* incoming call connected */ +#define LISTEN_REQ 2 /* listen request */ +#define HANGUP 3 /* hangup request/indication */ +#define SUSPEND 4 /* call suspend request/confirm */ +#define RESUME 5 /* call resume request/confirm */ +#define SUSPEND_REJ 6 /* suspend rejected indication */ +#define USER_DATA 8 /* user data for user to user signaling */ +#define CONGESTION 9 /* network congestion indication */ +#define INDICATE_REQ 10 /* request to indicate an incoming call */ +#define INDICATE_IND 10 /* indicates that there is an incoming call */ +#define CALL_RES 11 /* accept an incoming call */ +#define CALL_ALERT 12 /* send ALERT for incoming call */ +#define INFO_REQ 13 /* INFO request */ +#define INFO_IND 13 /* INFO indication */ +#define REJECT 14 /* reject an incoming call */ +#define RESOURCES 15 /* reserve B-Channel hardware resources */ +#define TEL_CTRL 16 /* Telephone control request/indication */ +#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ +#define FAC_REG_REQ 18 /* connection idependent fac registration */ +#define FAC_REG_ACK 19 /* fac registration acknowledge */ +#define FAC_REG_REJ 20 /* fac registration reject */ +#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ +#define FACILITY_REQ 22 /* send a Facility Message type */ +#define FACILITY_IND 22 /* Facility Message type indication */ +#define SIG_CTRL 29 /* Control for signalling hardware */ +#define DSP_CTRL 30 /* Control for DSPs */ +#define LAW_REQ 31 /* Law config request for (returns info_i) */ + + +/*------------------------------------------------------------------*/ +/* management service primitives */ +/*------------------------------------------------------------------*/ + +#define MAN_READ 2 +#define MAN_WRITE 3 +#define MAN_EXECUTE 4 +#define MAN_EVENT_ON 5 +#define MAN_EVENT_OFF 6 +#define MAN_LOCK 7 +#define MAN_UNLOCK 8 + +#define MAN_INFO_IND 2 +#define MAN_EVENT_IND 3 +#define MAN_TRACE_IND 4 + +#define MAN_ESC 0x80 + +/*------------------------------------------------------------------*/ +/* return code coding */ +/*------------------------------------------------------------------*/ + +#define UNKNOWN_COMMAND 0x01 /* unknown command */ +#define WRONG_COMMAND 0x02 /* wrong command */ +#define WRONG_ID 0x03 /* unknown task/entity id */ +#define WRONG_CH 0x04 /* wrong task/entity id */ +#define UNKNOWN_IE 0x05 /* unknown information el. */ +#define WRONG_IE 0x06 /* wrong information el. */ +#define OUT_OF_RESOURCES 0x07 /* ISDN-S card out of res. */ +#define ADAPTER_DEAD 0x08 /* ISDN card CPU halted */ +#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ +#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ +#define ASSIGN_OK 0xef /* ASSIGN OK */ +#define OK_FC 0xfc /* Flow-Control RC */ +#define READY_INT 0xfd /* Ready interrupt */ +#define TIMER_INT 0xfe /* timer interrupt */ +#define OK 0xff /* command accepted */ + +/*------------------------------------------------------------------*/ +/* information elements */ +/*------------------------------------------------------------------*/ + +#define SHIFT 0x90 /* codeset shift */ +#define MORE 0xa0 /* more data */ +#define CL 0xb0 /* congestion level */ + + /* codeset 0 */ + +#define BC 0x04 /* Bearer Capability */ +#define CAU 0x08 /* cause */ +#define CAD 0x0c /* Connected address */ +#define CAI 0x10 /* call identity */ +#define CHI 0x18 /* channel identification */ +#define LLI 0x19 /* logical link id */ +#define CHA 0x1a /* charge advice */ +#define DT 0x29 /* ETSI date/time */ +#define KEY 0x2c /* keypad information element */ +#define FTY 0x1c /* facility information element */ +#define DSP 0x28 /* display */ +#define OAD 0x6c /* origination address */ +#define OSA 0x6d /* origination sub-address */ +#define CPN 0x70 /* called party number */ +#define DSA 0x71 /* destination sub-address */ +#define RDX 0x73 /* redirected number extended */ +#define RDN 0x74 /* redirected number */ +#define LLC 0x7c /* low layer compatibility */ +#define HLC 0x7d /* high layer compatibility */ +#define UUI 0x7e /* user user information */ +#define ESC 0x7f /* escape extension */ + +#define DLC 0x20 /* data link layer configuration */ +#define NLC 0x21 /* network layer configuration */ + + /* codeset 6 */ + +#define SIN 0x01 /* service indicator */ +#define CIF 0x02 /* charging information */ +#define DATE 0x03 /* date */ +#define CPS 0x07 /* called party status */ + +/*------------------------------------------------------------------*/ +/* TEL_CTRL contents */ +/*------------------------------------------------------------------*/ + +#define RING_ON 0x01 +#define RING_OFF 0x02 +#define HANDS_FREE_ON 0x03 +#define HANDS_FREE_OFF 0x04 +#define ON_HOOK 0x80 +#define OFF_HOOK 0x90 + +#endif diff --git a/drivers/isdn/eicon/pc_maint.h b/drivers/isdn/eicon/pc_maint.h new file mode 100644 index 000000000000..f6fa6733dc04 --- /dev/null +++ b/drivers/isdn/eicon/pc_maint.h @@ -0,0 +1,162 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef PC_MAINT_H +#define PC_MAINT_H + +#if !defined(MIPS_SCOM) +#define BUFFER_SZ 48 +#define MAINT_OFFS 0x380 +#else +#define BUFFER_SZ 128 +#define MAINT_OFFS 0xff00 +#endif + +#define MIPS_BUFFER_SZ 128 +#define MIPS_MAINT_OFFS 0xff00 + +#define DO_LOG 1 +#define MEMR 2 +#define MEMW 3 +#define IOR 4 +#define IOW 5 +#define B1TEST 6 +#define B2TEST 7 +#define BTESTOFF 8 +#define DSIG_STATS 9 +#define B_CH_STATS 10 +#define D_CH_STATS 11 +#define BL1_STATS 12 +#define BL1_STATS_C 13 +#define GET_VERSION 14 +#define OS_STATS 15 +#define XLOG_SET_MASK 16 +#define XLOG_GET_MASK 17 +#define DSP_READ 20 +#define DSP_WRITE 21 + +#define OK 0xff +#define MORE_EVENTS 0xfe +#define NO_EVENT 1 + +struct DSigStruc +{ + byte Id; + byte uX; + byte listen; + byte active; + byte sin[3]; + byte bc[6]; + byte llc[6]; + byte hlc[6]; + byte oad[20]; +}; + +struct BL1Struc { + dword cx_b1; + dword cx_b2; + dword cr_b1; + dword cr_b2; + dword px_b1; + dword px_b2; + dword pr_b1; + dword pr_b2; + word er_b1; + word er_b2; +}; + +struct L2Struc { + dword XTotal; + dword RTotal; + word XError; + word RError; +}; + +struct OSStruc { + word free_n; +}; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[BUFFER_SZ]; + word w[BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[BUFFER_SZ>>2]; +} BUFFER; + +typedef union +{ + struct DSigStruc DSigStats; + struct BL1Struc BL1Stats; + struct L2Struc L2Stats; + struct OSStruc OSStats; + byte b[MIPS_BUFFER_SZ]; + word w[MIPS_BUFFER_SZ>>1]; + word l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + dword d[MIPS_BUFFER_SZ>>2]; +} MIPS_BUFFER; + + +#if !defined(MIPS_SCOM) +struct pc_maint +{ + byte req; + byte rc; + byte *mem; /*far*/ + short length; + word port; + byte fill[6]; + BUFFER data; +}; +#else +struct pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte far *mem; + short length; + word port; + byte fill[4]; /* data at offset 16 */ + BUFFER data; +}; +#endif + +struct mi_pc_maint +{ + byte req; + byte rc; + byte reserved[2]; /* R3000 alignment ... */ + byte *mem; /*far*/ + short length; + word port; + byte fill[4]; /* data at offset 16 */ + MIPS_BUFFER data; +}; + +#endif /* PC_MAINT_H */ diff --git a/drivers/isdn/eicon/pr_pc.h b/drivers/isdn/eicon/pr_pc.h new file mode 100644 index 000000000000..7634c7b7da94 --- /dev/null +++ b/drivers/isdn/eicon/pr_pc.h @@ -0,0 +1,83 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.0 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +#if !defined(PR_PC_H) +#define PR_PC_H + +struct pr_ram { + word NextReq; /* pointer to next Req Buffer */ + word NextRc; /* pointer to next Rc Buffer */ + word NextInd; /* pointer to next Ind Buffer */ + byte ReqInput; /* number of Req Buffers sent */ + byte ReqOutput; /* number of Req Buffers returned */ + byte ReqReserved; /* number of Req Buffers reserved */ + byte Int; /* ISDN-P interrupt */ + byte XLock; /* Lock field for arbitration */ + byte RcOutput; /* number of Rc buffers received */ + byte IndOutput; /* number of Ind buffers received */ + byte IMask; /* Interrupt Mask Flag */ + byte Reserved1[2]; /* reserved field, do not use */ + byte ReadyInt; /* request field for ready interrupt */ + byte Reserved2[12]; /* reserved field, do not use */ + byte InterfaceType; /* interface type 1=16K interface */ + word Signature; /* ISDN-P initialized indication */ + byte B[1]; /* buffer space for Req,Ind and Rc */ +}; + +typedef struct { + word next; + byte Req; + byte ReqId; + byte ReqCh; + byte Reserved1; + word Reference; + byte Reserved[8]; + PBUFFER XBuffer; +} REQ; + +typedef struct { + word next; + byte Rc; + byte RcId; + byte RcCh; + byte Reserved1; + word Reference; + byte Reserved2[8]; +} RC; + +typedef struct { + word next; + byte Ind; + byte IndId; + byte IndCh; + byte MInd; + word MLength; + word Reference; + byte RNR; + byte Reserved; + dword Ack; + PBUFFER RBuffer; +} IND; + +#endif diff --git a/drivers/isdn/eicon/pri.c b/drivers/isdn/eicon/pri.c new file mode 100644 index 000000000000..ee15449742ac --- /dev/null +++ b/drivers/isdn/eicon/pri.c @@ -0,0 +1,530 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.5 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Diva Server PRI specific part of initialisation */ +#include "sys.h" +#include "idi.h" +#include "divas.h" +#include "pc.h" +#include "pr_pc.h" +#include "dsp_defs.h" + +#include "adapter.h" +#include "uxio.h" + +#define DIVAS_LOAD_CMD 0x02 +#define DIVAS_START_CMD 0x03 +#define DIVAS_IRQ_RESET 0xC18 +#define DIVAS_IRQ_RESET_VAL 0xFE + +#define TEST_INT_DIVAS 0x11 +#define TEST_INT_DIVAS_BRI 0x12 + +#define DIVAS_RESET 0x81 +#define DIVAS_LED1 0x04 +#define DIVAS_LED2 0x08 +#define DIVAS_LED3 0x20 +#define DIVAS_LED4 0x40 + +#define DIVAS_RESET_REG 0x20 + +#define DIVAS_SIGNATURE 0x4447 + +/* offset to start of MAINT area (used by xlog) */ + +#define DIVAS_MAINT_OFFSET 0xef00 /* value for PRI card */ + +#define MP_PROTOCOL_ADDR 0xA0011000 +#define MP_DSP_CODE_BASE 0xa03a0000 + +typedef struct { + dword cmd; + dword addr; + dword len; + dword err; + dword live; + dword reserved[(0x1020>>2)-6]; + dword signature; + byte data[1]; +} diva_server_boot_t; + +byte mem_in(ADAPTER *a, void *adr); +word mem_inw(ADAPTER *a, void *adr); +void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e); +void mem_out(ADAPTER *a, void *adr, byte data); +void mem_outw(ADAPTER *a, void *adr, word data); +void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length); +void mem_inc(ADAPTER *a, void *adr); + +int DivasPRIInitPCI(card_t *card, dia_card_t *cfg); +static int pri_ISR (card_t* card); + +static int diva_server_reset(card_t *card) +{ + byte *reg; + diva_server_boot_t *boot = NULL; + dword live = 0; + int i = 0; + dword dwWait; + + DPRINTF(("divas: reset Diva Server PRI")); + + reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], DIVAS_RESET | + DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemOut(card->hw, ®[DIVAS_RESET_REG], 0x00); + + for (dwWait = 0x000fffff; dwWait; dwWait--) + ; + + UxCardMemDetach(card->hw, reg); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, boot->reserved, 0); + + live = UxCardMemInD(card->hw, &boot->live); + + for (i=0; i<5; i++) + { + if (live != UxCardMemInD(card->hw, &boot->live)) + { + break; + } + UxPause(10); + } + + if (i == 5) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card is reset but CPU not running")); + return -1; + } + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card reset after %d ms", i * 10)); + + return 0; +} + +static int diva_server_config(card_t *card, dia_config_t *config) +{ + byte *shared; + int i, j; + + DPRINTF(("divas: configure Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardLog(0); + for (i=0; i<256; i++) + { + UxCardMemOut(card->hw, &shared[i], 0); + } + + UxCardMemOut(card->hw, &shared[ 8], config->tei); + UxCardMemOut(card->hw, &shared[ 9], config->nt2); + UxCardMemOut(card->hw, &shared[10], config->sig_flags); + UxCardMemOut(card->hw, &shared[11], config->watchdog); + UxCardMemOut(card->hw, &shared[12], config->permanent); + UxCardMemOut(card->hw, &shared[13], config->x_interface); + UxCardMemOut(card->hw, &shared[14], config->stable_l2); + UxCardMemOut(card->hw, &shared[15], config->no_order_check); + UxCardMemOut(card->hw, &shared[16], config->handset_type); + UxCardMemOut(card->hw, &shared[17], 0); + UxCardMemOut(card->hw, &shared[18], config->low_channel); + UxCardMemOut(card->hw, &shared[19], config->prot_version); + UxCardMemOut(card->hw, &shared[20], config->crc4); + + for (i=0; i<2; i++) + { + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]); + } + + for (j=0; j<32; j++) + { + UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]); + } + } + + UxCardMemDetach(card->hw, shared); + + return 0; +} + +static +void diva_server_reset_int(card_t *card) +{ + byte *cfg; + + cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL); + UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0); + UxCardMemDetach(card->hw, cfg); + + return; +} + + +static int diva_server_test_int(card_t *card) +{ + int i; + byte *shared; + byte req_int; + + DPRINTF(("divas: test interrupt for Diva Server PRI")); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + UxCardMemIn(card->hw, &shared[0x3FE]); + UxCardMemOut(card->hw, &shared[0x3FE], 0); + UxCardMemIn(card->hw, &shared[0x3FE]); + + UxCardMemDetach(card->hw, shared); + + diva_server_reset_int(card); + + shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); + + card->test_int_pend = TEST_INT_DIVAS; + + req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt)); + + req_int++; + + UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int); + + UxCardMemDetach(card->hw, shared); + + UxCardLog(0); + for (i = 0; i < 50; i++) + { + if (!card->test_int_pend) + { + break; + } + UxPause(10); + } + + + if (card->test_int_pend) + { + + DPRINTF(("active: timeout waiting for card to interrupt")); + return (-1); + + } + + return 0; +} + + +static void print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i; + + i = 0; + + while ((i < (DIM(hdr) -1)) && + (code[offset + i] != '\0') && + (code[offset + i] != '\r') && + (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + + hdr[i] = '\0'; + + DPRINTF(("divas: loading %s", hdr)); +} + +static int diva_server_load(card_t *card, dia_load_t *load) +{ + diva_server_boot_t *boot; + int i, offset, length; + dword cmd = 0; + + DPRINTF(("divas: loading Diva Server PRI")); + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + switch(load->code_type) + { + case DIA_CPU_CODE: + DPRINTF(("divas: RISC code")); + print_hdr(load->code, 0x80); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + break; + + case DIA_DSP_CODE: + DPRINTF(("divas: DSP code")); + print_hdr(load->code, 0x0); + + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + (((sizeof(dword) + + (sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT)) + + ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA))); + break; + + case DIA_TABLE_CODE: + DPRINTF(("divas: TABLE code")); + UxCardMemOutD(card->hw, &boot->addr, + (MP_DSP_CODE_BASE + sizeof(dword))); + break; + + case DIA_CONT_CODE: + DPRINTF(("divas: continuation code")); + break; + + case DIA_DLOAD_CNT: + DPRINTF(("divas: COUNT code")); + UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE); + break; + + default: + DPRINTF(("divas: unknown code type")); + UxCardMemDetach(card->hw, boot); + return -1; + } + + UxCardLog(0); + offset = 0; + + do + { + length = (load->length - offset >= 400) ? 400 : load->length - offset; + + for (i=0; ihw, &boot->data[i], load->code[offset+i]); + } + + for (i=0; icode[offset + i] != UxCardMemIn(card->hw, &boot->data[i])) + { + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: card code block verify failed")); + return -1; + } + } + + UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD); + + for (i=0; i<50000; i++) + { + cmd = UxCardMemInD(card->hw, &boot->cmd); + if (!cmd) + { + break; + } + /*UxPause(1);*/ + } + + if (cmd) + { + DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset)); + UxCardMemDetach(card->hw, boot); + return -1; + } + + offset += length; + + } while (offset < load->length); + + UxCardMemDetach(card->hw, boot); + + DPRINTF(("divas: DIVA Server card loaded")); + + return 0; +} + +static int diva_server_start(card_t *card, byte *channels) +{ + diva_server_boot_t *boot; + byte *ram; + int i; + dword signature = 0; + + DPRINTF(("divas: start Diva Server PRI")); + + card->is_live = FALSE; + + boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR); + UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD); + + UxCardLog(0); + + for (i = 0; i < 300; i++) + { + signature = UxCardMemInD(card->hw, &boot->signature); + if ((signature >> 16) == DIVAS_SIGNATURE) + { + DPRINTF(("divas: started card after %d ms", i * 10)); + break; + } + UxPause(10); + } + + if ((signature >> 16) != DIVAS_SIGNATURE) + { + UxCardMemDetach(card->hw, boot); + DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature)); + return -1; + } + + card->is_live = TRUE; + + ram = (byte *) boot; + ram += DIVAS_SHARED_OFFSET; + + *channels = UxCardMemIn(card->hw, &ram[0x3F6]); + card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]); + + UxCardMemDetach(card->hw, boot); + + if (diva_server_test_int(card)) + { + DPRINTF(("divas: interrupt test failed")); + return -1; + } + + DPRINTF(("divas: DIVA Server card started")); + + return 0; +} + +static +int diva_server_mem_get(card_t *card, mem_block_t *mem_block) + +{ + byte *a; + byte *card_addr; + word length = 0; + int i; + + a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY); + + card_addr = a; + card_addr += mem_block->addr; + + for (i=0; i < sizeof(mem_block->data); i++) + { + mem_block->data[i] = UxCardMemIn(card->hw, card_addr); + card_addr++; + length++; + } + + UxCardMemDetach(card->hw, a); + + return length; +} + +/* + * Initialise PRI specific entry points + */ + +int DivasPriInit(card_t *card, dia_card_t *cfg) +{ + DPRINTF(("divas: initialise Diva Server PRI")); + + if (DivasPRIInitPCI(card, cfg) == -1) + { + return -1; + } + + card->card_reset = diva_server_reset; + card->card_load = diva_server_load; + card->card_config = diva_server_config; + card->card_start = diva_server_start; + card->reset_int = diva_server_reset_int; + card->card_mem_get = diva_server_mem_get; + + card->xlog_offset = DIVAS_MAINT_OFFSET; + + card->out = DivasOut; + card->test_int = DivasTestInt; + card->dpc = DivasDpc; + card->clear_int = DivasClearInt; + card->card_isr = pri_ISR; + + card->a.ram_out = mem_out; + card->a.ram_outw = mem_outw; + card->a.ram_out_buffer = mem_out_buffer; + card->a.ram_inc = mem_inc; + + card->a.ram_in = mem_in; + card->a.ram_inw = mem_inw; + card->a.ram_in_buffer = mem_in_buffer; + card->a.ram_look_ahead = mem_look_ahead; + + return 0; +} + + +static int pri_ISR (card_t* card) +{ + int served = 0; + byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); + volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET]; + register unsigned long val = *isr; + + if (val & 0x80000000) /* our card had caused interrupt ??? */ + { + served = 1; + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ + + *isr = (unsigned long)~0x03E00000; /* Clear interrupt line */ + } + + UxCardMemDetach(card->hw, cfg); + + return (served != 0); +} + + diff --git a/drivers/isdn/eicon/sys.h b/drivers/isdn/eicon/sys.h new file mode 100644 index 000000000000..e5141b856b04 --- /dev/null +++ b/drivers/isdn/eicon/sys.h @@ -0,0 +1,116 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* Environment provided by system and miscellaneous definitions */ + +#if !defined(SYS_H) +#define SYS_H + +/* abreviations for unsigned types */ +typedef int boolean_t; + +typedef unsigned char byte; + +typedef unsigned long dword; +typedef unsigned short word; + +/* abreviations for volatile types */ + +typedef volatile byte vbyte; +typedef volatile word vword; +typedef volatile dword vdword; + +/* Booleans */ + +#if !defined(TRUE) +#define TRUE (1) +#define FALSE (0) +#endif + +/* NULL pointer */ + +#if !defined(NULL) +#define NULL ((void *) 0) +#endif + +/* MIN and MAX */ + +#if !defined(MIN) +#define MIN(a,b) ((a)>(b) ? (b) : (a)) +#endif +#if !defined(MAX) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#endif + +/* Return the dimension of an array */ + +#if !defined(DIM) +#define DIM(array) (sizeof (array)/sizeof ((array)[0])) +#endif + +/* + * Return the number of milliseconds since last boot + */ + +extern dword UxTimeGet(void); + +extern void DivasSprintf(char *buffer, char *format, ...); +extern void DivasPrintf(char *format, ...); + +/* fatal errors, asserts and tracing */ + +void HwFatalErrorFrom(char *file, int line); +void HwFatalError(void); +/* void HwAssert(char *file, int line, char *condition); */ + +#include +#define _PRINTK printk + +#define _PRINTF DivasPrintf +void _PRINTF(char *format, ...); +#define PRINTF(arg_list) _PRINTF arg_list +#if defined DTRACE +# define DPRINTF(arg_list) _PRINTF arg_list +# define KDPRINTF(arg_list) _PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n"); +#else +# define DPRINTF(arg_list) (void)0 +# define KDPRINTF(arg_list) _PRINTK arg_list ; _PRINTK("\n"); +#endif + +#if !defined(ASSERT) +#if defined DEBUG || defined DBG +# define HwFatalError() HwFatalErrorFrom(__FILE__, __LINE__) +# define ASSERT(cond) \ + if (!(cond)) \ + { \ +/* HwAssert(__FILE__, __LINE__, #cond);*/ \ + } +#else +# define ASSERT(cond) ((void)0) +#endif +#endif /* !defined(ASSERT) */ + +#define TRACE (_PRINTF(__FILE__"@%d\n", __LINE__)) + +#endif /* SYS_H */ diff --git a/drivers/isdn/eicon/uxio.h b/drivers/isdn/eicon/uxio.h new file mode 100644 index 000000000000..e3302830b7d5 --- /dev/null +++ b/drivers/isdn/eicon/uxio.h @@ -0,0 +1,217 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.6 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Interface to Unix specific code for performing card I/O + */ + +#if !defined(UXIO_H) +#define UXIO_H + +#include "sys.h" +#include "adapter.h" + + +struct pt_regs; + +/* user callback, returns zero if interrupt was from this card */ +typedef void isr_fn_t(void *); +struct ux_diva_card_s +{ + word in_use; + int io_base; + int reset_base; + int card_type; + byte *mapped; + int bus_num; + int func_num; + int slot; + int irq; + byte *pDRAM; + byte *pDEVICES; + byte *pCONFIG; + byte *pSHARED; + byte *pCONTROL; + word features; + void *user_isr_arg; + isr_fn_t *user_isr; +}; + +void bcopy(void *pSource, void *pDest, dword dwLength); +void bzero(void *pDataArea, dword dwLength); + + +/* + * Get a card handle to enable card to be accessed + */ + +int UxCardHandleGet( ux_diva_card_t **card, + dia_card_t *cfg); + +/* + * Free a card handle as no longer needed + */ + +void UxCardHandleFree(ux_diva_card_t *card); + +/* + * Lock and unlock access to a card + */ + +int UxCardLock(ux_diva_card_t *card); +void UxCardUnlock(ux_diva_card_t *card, int ipl); + +/* + * Set the mapping address for PCI cards + */ + +int UxCardAddrMappingSet(ux_diva_card_t *card, + int id, + void *address, + int size); + +/* + * Attach card to memory to enable it to be accessed + * Returns the mapped address + */ + +void *UxCardMemAttach(ux_diva_card_t *card, int id); + +/* + * map card out of memory after completion of access + */ + +void UxCardMemDetach(ux_diva_card_t *card, void *address); + +/* + * input functions for memory-mapped cards + */ + +byte UxCardMemIn(ux_diva_card_t *card, void *address); + +word UxCardMemInW(ux_diva_card_t *card, void *address); + +dword UxCardMemInD(ux_diva_card_t *card, void *address); + +void UxCardMemInBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * output functions for memory-mapped cards + */ + +void UxCardMemOut(ux_diva_card_t *card, void *address, byte data); + +void UxCardMemOutW(ux_diva_card_t *card, void *address, word data); + +void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data); + +void UxCardMemOutBuffer( ux_diva_card_t *card, + void *address, + void *buffer, + int length); + +/* + * input functions for I/O-mapped cards + */ + +byte UxCardIoIn(ux_diva_card_t *card, void *, void *address); + +word UxCardIoInW(ux_diva_card_t *card, void *, void *address); + +dword UxCardIoInD(ux_diva_card_t *card, void *, void *address); + +void UxCardIoInBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * output functions for I/O-mapped cards + */ + +void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data); + +void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data); + +void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data); + +void UxCardIoOutBuffer( ux_diva_card_t *card, + void *, void *address, + void *buffer, + int length); + +/* + * Get specified PCI config + */ + +void UxPciConfigRead(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* + * Set specified PCI config + */ + +void UxPciConfigWrite(ux_diva_card_t *card, + int size, + int offset, + void *value); + +/* allocate memory, returning NULL if none available */ + +void *UxAlloc(unsigned int size); + +void UxFree(void *); + +/* + * Pause for specified number of milli-seconds + */ + +void UxPause(long ms); + +/* + * Install an ISR for the specified card + */ + +int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg); + +/* + * Remove an ISR for the specified card + */ +void UxIsrRemove(ux_diva_card_t *card, void *); + +/* + * DEBUG function to turn logging ON or OFF + */ + +void UxCardLog(int turn_on); + +long UxInterlockedIncrement(ux_diva_card_t *card, long *dst); +long UxInterlockedDecrement(ux_diva_card_t *card, long *dst); + +#endif /* of UXIO_H */ diff --git a/drivers/isdn/eicon/xlog.c b/drivers/isdn/eicon/xlog.c new file mode 100644 index 000000000000..b9786601dc41 --- /dev/null +++ b/drivers/isdn/eicon/xlog.c @@ -0,0 +1,180 @@ + +/* + * + * Copyright (C) Eicon Technology Corporation, 2000. + * + * Eicon File Revision : 1.2 + * + * 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 OF ANY KIND WHATSOEVER INCLUDING ANY + * 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. + * + */ + + +/* + * Unix Eicon active card driver + * XLOG related functions + */ + +#include "sys.h" +#include "idi.h" +#include "pc.h" +#include "pc_maint.h" +#include "divalog.h" + +#include "adapter.h" +#include "uxio.h" + +/* + * convert/copy XLOG info into a KLOG entry + */ + +static +void xlog_to_klog(byte *b, int size, int card_num) + +{ + typedef struct + { + word code; + word time_hi; + word time_lo; + word xcode; + byte data[2]; + } card_xlog_t; + + card_xlog_t *x; + + klog_t klog; + + x = (card_xlog_t *) b; + + bzero(&klog, sizeof(klog)); + + klog.time_stamp = (dword) x->time_hi; + klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo; + + klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size; + + klog.card = card_num; + if (x->code == 1) + { + klog.type = KLOG_XTXT_MSG; + klog.code = 0; + bcopy(&x->xcode, klog.buffer, klog.length); + } + else if (x->code == 2) + { + klog.type = KLOG_XLOG_MSG; + klog.code = x->xcode; + bcopy(&x->data, klog.buffer, klog.length); + } + else + { + char *c; int i; + klog.type = KLOG_TEXT_MSG; + klog.code = 0; + c = "divas: invalid xlog message code from card"; + i = 0; + while (*c) + { + klog.buffer[i] = *c; + c++; + i++; + } + klog.buffer[i] = *c; + } + + /* send to the log driver and return */ + + DivasLogAdd(&klog, sizeof(klog)); + + return; +} + +/* + * send an XLOG request down to specified card + * if response available from previous request then read it + * if not then just send down new request, ready for next time + */ + +void DivasXlogReq(int card_num) + +{ + card_t *card; + ADAPTER *a; + + if ((card_num < 0) || (card_num > DivasCardNext)) + { + DPRINTF(("xlog: invalid card number")); + return; + } + + card = &DivasCards[card_num]; + + if (DivasXlogRetrieve(card)) + { + return; + } + + /* send down request for next time */ + + a = &card->a; + + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return; +} + +/* + * retrieve XLOG request from specified card + * returns non-zero if new request sent to card + */ + +int DivasXlogRetrieve(card_t *card) + +{ + ADAPTER *a; + struct mi_pc_maint pcm; + + a = &card->a; + + /* get status of last request */ + + pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1)); + + /* if nothing there from previous request, send down a new one */ + + if (pcm.rc == OK) + { + /* read in response */ + + a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm)); + + xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data), + (int) (card - DivasCards)); + } + + /* if any response received from card, re-send request */ + + if (pcm.rc) + { + a->ram_out(a, (word *) (card->xlog_offset + 1), 0); + a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG); + + return 1; + } + + return 0; +} diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index d5dd7d7715a8..b50412b22f75 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -60,14 +60,42 @@ - In vortex_open(), set vp->tx_full to zero (else we get errors if the device was closed with a full Tx ring). - 15Sep00 <2.2.18-pre3> andrewm + 17Oct00 <2.2.18-pre16> andrewm - Added support for the 3c556B Laptop Hurricane (Louis Gerbarg) + - Backported transceiver options handling from 2.4. This changes the semantics + of forcing full duplex in the `options' parm! (It's better to use + `full_duplex' anyway). See Documentation/vortex.txt (Maciej Rozycki). + - Set PCI latency timer to maximum for the 3c590 (From Donald's driver) + - Removed all the CARDBUS code (it's never used). + - Added INVERT_MII_PWR, EEPROM_8BIT, EEPROM_OFFSET. Use them. + - Use EEPROM_8BIT for the 3c555 + - Merged ACPI WOL support from Donald's drivers. + - Sort-of backported Donald's new medialock code. Called it duplexlock + and we now prefer to use `full_duplex=[-1,0,1]' to force duplex mode. + - Merged the rx_oom_timer from 2.4. This gives better handling of OOM + conditions. Backed out the previous way of handling this. + - Replace suser() with capable(CAP_NET_ADMIN) in ioctl(). + + 07Jan01 <2.2.19-pre6> andrewm + - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO" + - Added and used wait_for_completion(). 3c905CX problems. + - Removed the code for older kernel versions. + - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger) + - Search for phy 24 first for 3c905CX. (D Becker) + - Don't free skbs we don't own on oom path in vortex_open(). + - Added explicit `medialock' flag so we can truly + lock the media type down with `options'. + - In vortex_error(), only reset the up/down load engine, not all the + interface stuff. + - Added and used EEPROM_NORESET for 3c556B PM resumes. + - Enable WOL with the `enable_wol' module parm + - Give the 3c980 HAS_NWAY - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.2 for more details. */ static char version[] = -"3c59x.c 15Sep00 Donald Becker and others http://www.scyld.com/network/vortex.html\n"; +"3c59x.c 18Feb01 Donald Becker and others http://www.scyld.com/network/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -101,16 +129,6 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #include #include -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif -#include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include @@ -124,9 +142,8 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #include #include #include -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -#include -#endif +#include +#include #include /* For NR_IRQS only. */ #include #include @@ -136,48 +153,18 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; #define RUN_AT(x) (jiffies + (x)) -#include -#if (LINUX_VERSION_CODE <= 0x20100) -#ifndef __alpha__ -#define ioremap(a,b) \ - (((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b)) -#define iounmap(v) \ - do { if ((u_long)(v) > 0x100000) vfree(v); } while (0) -#endif -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20138 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#define le32_to_cpu(val) (val) -#define cpu_to_le32(val) (val) -#endif -#if LINUX_VERSION_CODE < 0x20155 -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE); -#else /* Grrr, unneeded incompatible change. */ -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); -#endif - -#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 -MODULE_AUTHOR("Donald Becker "); +MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); -#endif /* Operational parameter that usually are not changed. */ @@ -286,7 +273,9 @@ struct pci_id_info { }; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, - HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; + HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, + INVERT_MII_PWR=0x100, EEPROM_8BIT=0x200, EEPROM_OFFSET=0x400, + EEPROM_NORESET=0x800}; static struct device *vortex_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr, int irq, int dev_id, int card_idx); @@ -316,7 +305,7 @@ static struct pci_id_info pci_tbl[] = { {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, {"3c900 Cyclone 10Mbps TPO", 0x10B7, 0x9004, 0xffff, /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, {"3c900 Cyclone 10Mbps TPC", 0x10B7, 0x9006, 0xffff, /* AKPM: from Don's 0.99M */ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff, @@ -332,15 +321,15 @@ static struct pci_id_info pci_tbl[] = { {"3c905C Tornado", 0x10B7, 0x9200, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, vortex_probe1}, {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, vortex_probe1}, {"3c556 10/100 Mini PCI Adapter", 0x10B7, 0x6055, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_CB_FNS, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, vortex_probe1}, {"3c556B Laptop Hurricane", 0x10B7, 0x6056, 0xffff, - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_CB_FNS, 128, vortex_probe1}, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|EEPROM_NORESET, 128, vortex_probe1}, {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, @@ -501,7 +490,7 @@ enum tx_desc_status { }; /* Chip features we care about in vp->capabilities, read from the EEPROM. */ -enum ChipCaps { CapBusMaster=0x20 }; +enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 }; struct vortex_private { /* The Rx and Tx rings should be quad-word-aligned. */ @@ -515,23 +504,27 @@ struct vortex_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. */ struct net_device_stats stats; - struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ + struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ /* PCI configuration space information. */ - u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ - char *cb_fn_base; /* CardBus function status addr space. */ + u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ + char *cb_fn_base; /* CardBus function status addr space. */ int chip_id; /* The remainder are related to chip state, mostly media selection. */ - struct timer_list timer; /* Media selection timer. */ - int options; /* User-settable misc. driver options. */ - unsigned int media_override:3, /* Passed-in media type. */ + struct timer_list timer; /* Media selection timer. */ + struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ + int options; /* User-settable misc. driver options. */ + unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, force_fd:1, autoselect:1, - bus_master:1, /* Vortex can only do a fragment bus-m. */ + full_duplex:1, /* User wants FD (or we're running at FD) */ + duplexlock:1, /* User has forced duplex */ + autoselect:1, /* Can use NWAY negotiation */ + bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ - hw_csums:1, /* Has hardware checksums. */ - tx_full:1; + tx_full:1, + enable_wol:1, + medialock:1; u16 status_enable; u16 intr_enable; u16 available_media; /* From Wn3_Options. */ @@ -571,14 +564,13 @@ static struct media_table { { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifndef CARDBUS static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]); -#endif static int vortex_open(struct device *dev); static void mdio_sync(long ioaddr, int bits); static int mdio_read(long ioaddr, int phy_id, int location); static void mdio_write(long ioaddr, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); +static void rx_oom_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev); static int vortex_rx(struct device *dev); @@ -590,116 +582,33 @@ static void update_stats(long ioaddr, struct device *dev); static struct net_device_stats *vortex_get_stats(struct device *dev); static void set_rx_mode(struct device *dev); static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static void acpi_wake(int pci_bus, int pci_devfn); +static void acpi_set_WOL(struct device *dev); -/* #define dev_alloc_skb dev_alloc_skb_debug */ +#if 0 +#warning dev_alloc_skb_debug is defined! +#define dev_alloc_skb dev_alloc_skb_debug +#endif /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Option count limit only -- unlimited interfaces are supported. */ #define MAX_UNITS 8 -static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* A list of all installed Vortex devices, for removing the driver module. */ static struct device *root_vortex_dev = NULL; #ifdef MODULE -#ifndef CARDBUS /* Variables to work-around the Compaq PCI BIOS32 problem. */ static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900; -#endif - -#ifdef CARDBUS - -#include - -static dev_node_t *vortex_attach(dev_locator_t *loc) -{ - u16 dev_id, vendor_id; - u32 io; - u8 bus, devfn, irq; - struct device *dev; - int chip_idx; - - if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); - pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); - pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id); - pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); - printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", - bus, devfn, dev_id); - io &= ~3; - if (io == 0 || irq == 0) { - printk(KERN_ERR "The 3Com 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; - } - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor_id == pci_tbl[chip_idx].vendor_id - && (dev_id & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */ - printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in " - "vortex_attach().\n", vendor_id, dev_id); - return NULL; - } - dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1); - if (dev) { - dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - if (!node) - return NULL; - strcpy(node->dev_name, dev->name); - node->major = node->minor = 0; - node->next = NULL; - MOD_INC_USE_COUNT; - return node; - } - return NULL; -} - -static void vortex_detach(dev_node_t *node) -{ - struct device **devp, **next; - printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name); - for (devp = &root_vortex_dev; *devp; devp = next) { - next = &((struct vortex_private *)(*devp)->priv)->next_module; - if (strcmp((*devp)->name, node->dev_name) == 0) break; - } - if (*devp) { - struct device *dev = *devp; - struct vortex_private *vp = dev->priv; - if (dev->flags & IFF_UP) - vortex_close(dev); - dev->flags &= ~(IFF_UP|IFF_RUNNING); - unregister_netdev(dev); - if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - kfree(dev); - *devp = *next; - kfree(vp); - kfree(node); - MOD_DEC_USE_COUNT; - } -} - -struct driver_operations vortex_ops = { - "3c575_cb", vortex_attach, NULL, NULL, vortex_detach -}; - -#endif /* Cardbus support */ - int init_module(void) { if (vortex_debug) printk(KERN_INFO "%s", version); -#ifdef CARDBUS - register_driver(&vortex_ops); - return 0; -#else return vortex_scan(0, pci_tbl); -#endif } #else @@ -713,7 +622,30 @@ int tc59x_probe(struct device *dev) } #endif /* not MODULE */ -#ifndef CARDBUS +static void wait_for_completion(struct device *dev, int cmd) +{ + int i; + + outw(cmd, dev->base_addr + EL3_CMD); + for (i = 0; i < 2000; i++) { + if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) + return; + } + + /* OK, that didn't work. Do it the slow way. One second */ + for (i = 0; i < 100000; i++) { + if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) { + if (vortex_debug > 1) + printk(KERN_INFO "%s: command 0x%04x took %d usecs!\n", + dev->name, cmd, i * 10); + return; + } + udelay(10); + } + printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", + dev->name, cmd, inw(dev->base_addr + EL3_STATUS)); +} + static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) { int cards_found = 0; @@ -734,8 +666,7 @@ static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) long ioaddr; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) + &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) break; pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); @@ -749,21 +680,13 @@ static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ continue; + /* The Cyclone requires config space re-write if powered down. */ + acpi_wake(pci_bus, pci_device_fn); + { -#if LINUX_VERSION_CODE >= 0x20155 struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[0] & ~3; irq = pdev->irq; -#else - u32 pci_ioaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - ioaddr = pci_ioaddr & ~3;; - irq = pci_irq_line; -#endif } /* Power-up the card. */ @@ -811,21 +734,21 @@ static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) chip_idx, cards_found); if (dev) { - /* Get and check the latency values. On the 3c590 series - the latency timer must be set to the maximum value to avoid - data corruption that occurs when the timer expires during - a transfer -- a bug in the Vortex chip only. */ - u8 pci_latency; - u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32; - - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < new_latency) { - printk(KERN_INFO "%s: Overriding PCI latency" - " timer (CFLT) setting of %d, new value is %d.\n", - dev->name, pci_latency, new_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, new_latency); + if ((device & 0xff00) == 0x5900) { + /* Get and check the latency values. On the 3c590 series + the latency timer must be set to the maximum value to avoid + data corruption that occurs when the timer expires during + a transfer -- a bug in the Vortex chip only. */ + u8 pci_latency; + u8 new_latency = 248; + + pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < new_latency) { + printk(KERN_INFO "%s: Overriding PCI latency" + " timer (CFLT) setting of %d, new value is %d.\n", + dev->name, pci_latency, new_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, new_latency); + } } dev = 0; cards_found++; @@ -866,7 +789,6 @@ static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]) return cards_found ? 0 : -ENODEV; } -#endif /* ! Cardbus */ static struct device *vortex_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr, @@ -878,6 +800,10 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, int i; dev = init_etherdev(dev, 0); + if (dev == NULL) { + printk(KERN_EMERG "3c59x: init_etherdev failed\n"); + return NULL; + } printk(KERN_INFO "%s: 3Com %s at 0x%lx, ", dev->name, pci_tbl[chip_idx].name, ioaddr); @@ -889,12 +815,16 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, /* Make certain the descriptor lists are aligned. */ { void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL); - if (!mem) + if (!mem) { + printk(KERN_EMERG "3c59x: out of memory for dev->priv\n"); + unregister_netdev(dev); + kfree(dev); return NULL; + } vp = (void *)(((long)mem + 15) & ~15); + memset(vp, 0, sizeof(*vp)); vp->priv_addr = mem; } - memset(vp, 0, sizeof(*vp)); dev->priv = vp; vp->next_module = root_vortex_dev; @@ -906,51 +836,68 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, vp->pci_devfn = pci_devfn; /* The lower four bits are the media type. */ + option = -1; if (dev->mem_start) option = dev->mem_start; else if (card_idx < MAX_UNITS) option = options[card_idx]; - else - option = -1; if (option >= 0) { - vp->media_override = ((option & 7) == 2) ? 0 : option & 7; - vp->full_duplex = (option & 8) ? 1 : 0; + vp->media_override = ((option & 7) == 2) ? 0 : option & 15; + if (vp->media_override != 7) + vp->medialock = 1; + if (option & 0x200) { + vp->full_duplex = 1; + vp->duplexlock = 1; + printk( "\n" KERN_WARNING + "%s: forcing duplex via options is deprecated - use `full_duplex'.\n", + dev->name); + } vp->bus_master = (option & 16) ? 1 : 0; } else { vp->media_override = 7; vp->full_duplex = 0; vp->bus_master = 0; } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - vp->full_duplex = 1; - - vp->force_fd = vp->full_duplex; + if (card_idx < MAX_UNITS) { + if (enable_wol[card_idx] > 0) + vp->enable_wol = 1; + if (full_duplex[card_idx] == 0) { /* full_duplex=0 : force half duplex */ + vp->duplexlock = 1; + } + if (full_duplex[card_idx] > 0) { /* full_duplex=1: force full duplex */ + vp->duplexlock = 1; + vp->full_duplex = 1; + } + /* full_duplex=-1: duplex is not forced */ + } vp->options = option; /* Read the station address from the EEPROM. */ EL3WINDOW(0); - for (i = 0; i < 0x40; i++) { - int timer; -#ifdef CARDBUS - outw(0x230 + i, ioaddr + Wn0EepromCmd); -#else - if (pci_tbl[chip_idx].device_id == 0x6055) { - outw(0x230 + i, ioaddr + Wn0EepromCmd); - } else if (pci_tbl[chip_idx].device_id == 0x6056) { - outw(EEPROM_Read + 0x30 + i, ioaddr + Wn0EepromCmd); - } else { - outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); - } -#endif - /* Pause for at least 162 us. for the read to take place. */ - for (timer = 10; timer >= 0; timer--) { - udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) - break; + { + int base; + + if (pci_tbl[chip_idx].drv_flags & EEPROM_8BIT) + base = 0x230; + else if (pci_tbl[chip_idx].drv_flags & EEPROM_OFFSET) + base = EEPROM_Read + 0x30; + else + base = EEPROM_Read; + + for (i = 0; i < 0x40; i++) { + int timer; + outw(base + i, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 10; timer >= 0; timer--) { + udelay(162); + if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) + break; + } + eeprom[i] = inw(ioaddr + Wn0EepromData); } - eeprom[i] = inw(ioaddr + Wn0EepromData); } + for (i = 0; i < 0x18; i++) checksum ^= eeprom[i]; checksum = (checksum ^ (checksum >> 8)) & 0xff; @@ -978,6 +925,7 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ + u16 n; pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2, &fn_st_addr); if (fn_st_addr) @@ -985,11 +933,12 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee" " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base); EL3WINDOW(2); - if (pci_tbl[chip_idx].device_id == 0x6055) { - outw(0x4010 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); - } else { - outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions); - } + + n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + n |= 0x10; + if (pci_tbl[chip_idx].drv_flags & INVERT_MII_PWR) + n |= 0x4000; + outw(n, ioaddr + Wn2_ResetOptions); } /* Extract our information from the EEPROM data. */ @@ -997,7 +946,7 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; - if (vp->info1 & 0x8000) + if (!vp->duplexlock && (vp->info1 & 0x8000)) vp->full_duplex = 1; { @@ -1035,8 +984,19 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, mii_preamble_required++; mii_preamble_required++; mdio_read(ioaddr, 24, 1); - for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) { - int mii_status, phyx = phy & 0x1f; + for (phy = 0; phy < 32 && phy_idx < 1; phy++) { + int mii_status, phyx; + + /* + * For the 3c905CX we look at index 24 first, because it bogusly + * reports an external PHY at all indices + */ + if (phy == 0) + phyx = 24; + else if (phy <= 24) + phyx = phy - 1; + else + phyx = phy; mii_status = mdio_read(ioaddr, phyx, 1); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; @@ -1060,6 +1020,9 @@ static struct device *vortex_probe1(int pci_bus, int pci_devfn, } } + if (vp->enable_wol && (vp->capabilities & CapPwrMgmt)) + acpi_set_WOL(dev); + if (vp->capabilities & CapBusMaster) { vp->full_bus_master_tx = 1; printk(KERN_INFO" Enabling bus-master transmits and %s receives.\n", @@ -1093,6 +1056,9 @@ vortex_open(struct device *dev) MOD_INC_USE_COUNT; + if (vp->enable_wol) + acpi_wake(vp->pci_bus, vp->pci_devfn); + /* Before initializing select the active media port. */ EL3WINDOW(3); config = inl(ioaddr + Wn3_Config); @@ -1104,7 +1070,9 @@ vortex_open(struct device *dev) media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) { - dev->if_port = XCVR_NWAY; + if (vortex_debug > 1) + printk(KERN_INFO "%s: using NWAY from config\n", dev->name); + dev->if_port = XCVR_NWAY; } else if (vp->autoselect) { /* Find first available media type, starting with 100baseTx. */ dev->if_port = XCVR_100baseTx; @@ -1113,11 +1081,11 @@ vortex_open(struct device *dev) } else dev->if_port = vp->default_media; - if (vortex_debug > 1) - printk(KERN_DEBUG "%s: Initial media type %s.\n", - dev->name, media_tbl[dev->if_port].name); + printk(KERN_INFO "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); + + if (!vp->duplexlock && (vp->info1 & 0x8000)) + vp->full_duplex = 1; - vp->full_duplex = vp->force_fd; config = BFINS(config, dev->if_port, 20, 4); outl(config, ioaddr + Wn3_Config); @@ -1129,35 +1097,25 @@ vortex_open(struct device *dev) mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) ; /* No MII device or no link partner report */ - else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ - || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ + else if (!vp->duplexlock && + ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ + || (mii_reg5 & 0x00C0) == 0x0040)) /* 10T-FD, but not 100-HD */ vp->full_duplex = 1; - if (vortex_debug > 1) - printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," - " setting %s-duplex.\n", dev->name, vp->phys[0], - mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); + printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," + " setting %s-duplex.\n", dev->name, vp->phys[0], + mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); EL3WINDOW(3); } /* Set the full-duplex bit. */ - outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); + outb((vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", - dev->name, config); + printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", dev->name, config); } - outw(TxReset, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - - outw(RxReset, ioaddr + EL3_CMD); - /* Wait a few ticks for the RxReset command to complete. */ - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TxReset); + wait_for_completion(dev, RxReset); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); @@ -1224,18 +1182,15 @@ vortex_open(struct device *dev) if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ -#if LINUX_VERSION_CODE >= 0x10300 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail)); -#else - vp->rx_ring[i].addr = virt_to_bus(skb->data); -#endif } if (i != RX_RING_SIZE) { int j; - for (j = 0; j < RX_RING_SIZE; j++) { + printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name); + for (j = 0; j < i; j++) { if (vp->rx_skbuff[j]) - DEV_FREE_SKB(vp->rx_skbuff[j]); + dev_kfree_skb(vp->rx_skbuff[j]); } retval = -ENOMEM; goto out_free_irq; @@ -1285,6 +1240,10 @@ vortex_open(struct device *dev) vp->timer.function = &vortex_timer; /* timer handler */ add_timer(&vp->timer); + init_timer(&vp->rx_oom_timer); + vp->rx_oom_timer.data = (unsigned long)dev; + vp->rx_oom_timer.function = rx_oom_timer; + return 0; out_free_irq: @@ -1306,6 +1265,8 @@ static void vortex_timer(unsigned long data) printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", dev->name, media_tbl[dev->if_port].name); + if (vp->medialock) + goto leave_media_alone; disable_irq(dev->irq); old_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); @@ -1332,7 +1293,7 @@ static void vortex_timer(unsigned long data) dev->name, mii_status); if (mii_status & 0x0004) { int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5); - if (! vp->force_fd && mii_reg5 != 0xffff) { + if (!vp->duplexlock && mii_reg5 != 0xffff) { int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; if (vp->full_duplex != duplex) { @@ -1342,7 +1303,7 @@ static void vortex_timer(unsigned long data) dev->name, vp->full_duplex ? "full" : "half", vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ - EL3WINDOW(3); /* AKPM */ + EL3WINDOW(3); outb((vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); @@ -1392,6 +1353,7 @@ static void vortex_timer(unsigned long data) EL3WINDOW(old_window); enable_irq(dev->irq); +leave_media_alone: if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1407,7 +1369,6 @@ static void vortex_tx_timeout(struct device *dev) { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - int j; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", dev->name, inb(ioaddr + TxStatus), @@ -1435,12 +1396,7 @@ static void vortex_tx_timeout(struct device *dev) __restore_flags(flags); } } - outw(TxReset, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; -#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300 if (vp->full_bus_master_tx) { int i; printk(KERN_DEBUG " Flags; bus-master %d, full %d; dirty %d " @@ -1456,7 +1412,7 @@ static void vortex_tx_timeout(struct device *dev) le32_to_cpu(vp->tx_ring[i].status)); } } -#endif + wait_for_completion(dev, TxReset); vp->stats.tx_errors++; if (vp->full_bus_master_tx) { if (vortex_debug > 0) @@ -1494,7 +1450,6 @@ vortex_error(struct device *dev, int status) struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; int do_tx_reset = 0; - int i; if (status & TxComplete) { /* Really "TxError" for us. */ unsigned char tx_status = inb(ioaddr + TxStatus); @@ -1545,20 +1500,14 @@ vortex_error(struct device *dev, int status) dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { - outw(TotalReset | 0xff, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TotalReset|0xff); /* Re-enable the receiver. */ outw(RxEnable, ioaddr + EL3_CMD); outw(TxEnable, ioaddr + EL3_CMD); } else if (fifo_diag & 0x0400) do_tx_reset = 1; if (fifo_diag & 0x3000) { - outw(RxReset, ioaddr + EL3_CMD); - for (i = 2000; i >= 0 ; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, RxReset); /* Set the Rx filter to the current state. */ set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ @@ -1566,11 +1515,7 @@ vortex_error(struct device *dev, int status) } } if (do_tx_reset) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j = 4000; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); if (!vp->full_bus_master_tx) { clear_bit(0, (void*)&dev->tbusy); @@ -1580,7 +1525,6 @@ vortex_error(struct device *dev, int status) } - static int vortex_start_xmit(struct sk_buff *skb, struct device *dev) { @@ -1609,7 +1553,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) #else outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); #endif - DEV_FREE_SKB(skb); + dev_kfree_skb(skb); if (inw(ioaddr + TxFree) > 1536) { clear_bit(0, (void*)&dev->tbusy); } else @@ -1631,13 +1575,8 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev) dev->name, tx_status); if (tx_status & 0x04) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; - if (tx_status & 0x30) { - int j; - outw(TxReset, ioaddr + EL3_CMD); - for (j = 200; j >= 0 ; j--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; - } + if (tx_status & 0x30) + wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); } outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ @@ -1663,7 +1602,6 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev) struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; unsigned long flags; - int i; if (vortex_debug > 3) printk(KERN_DEBUG "%s: Trying to send a boomerang packet, Tx index %d.\n", @@ -1681,11 +1619,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev) vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); spin_lock_irqsave(&vp->lock, flags); - outw(DownStall, ioaddr + EL3_CMD); - /* Wait for the stall to complete. */ - for (i = 4000; i >= 0; i--) - if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) - break; + wait_for_completion(dev, DownStall); prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry])); if (inl(ioaddr + DownListPtr) == 0) { outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); @@ -1761,7 +1695,7 @@ static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status & DMADone) { if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */ + dev_kfree_skb(vp->tx_skb); /* Release the transfered buffer */ if (inw(ioaddr + TxFree) > 1536) { clear_bit(0, (void*)&dev->tbusy); mark_bh(NET_BH); @@ -1854,7 +1788,7 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) virt_to_bus(&vp->tx_ring[entry])) break; /* It still hasn't been processed. */ if (vp->tx_skbuff[entry]) { - DEV_FREE_SKB(vp->tx_skbuff[entry]); + dev_kfree_skb(vp->tx_skbuff[entry]); vp->tx_skbuff[entry] = 0; } /* vp->stats.tx_packets++; Counted below. */ @@ -1898,14 +1832,6 @@ static void boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) } while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch); - /* - * If we have totally run out to rx skb's due to persistent OOM, - * we can use the Tx interrupt to retry the allocation. Dirty - * but expedient - */ - if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) - boomerang_rx(dev); - if (vortex_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, status); @@ -1980,12 +1906,8 @@ static int vortex_rx(struct device *dev) printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " "size %d.\n", dev->name, pkt_len); } - outw(RxDiscard, ioaddr + EL3_CMD); vp->stats.rx_dropped++; - /* Wait a limited time to skip this packet. */ - for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) - break; + wait_for_completion(dev, RxDiscard); } return 0; @@ -2074,8 +1996,16 @@ boomerang_rx(struct device *dev) entry = vp->dirty_rx % RX_RING_SIZE; if (vp->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) + if (skb == NULL) { + static unsigned long last_jif; + if ((jiffies - last_jif) > 10 * HZ) { + printk(KERN_WARNING "%s: memory shortage\n", dev->name); + last_jif = jiffies; + } + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) + mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1)); break; /* Bad news! */ + } skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail)); @@ -2087,6 +2017,26 @@ boomerang_rx(struct device *dev) return 0; } +/* + * If we've hit a total OOM refilling the Rx ring we poll once a second + * for some memory. Otherwise there is no way to restart the rx process. + */ +static void +rx_oom_timer(unsigned long arg) +{ + struct device *dev = (struct device *)arg; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + + spin_lock_irq(&vp->lock); + if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ + boomerang_rx(dev); + if (vortex_debug > 1) { + printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name, + ((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying"); + } + spin_unlock_irq(&vp->lock); +} + static int vortex_close(struct device *dev) { @@ -2106,6 +2056,7 @@ vortex_close(struct device *dev) } del_timer(&vp->timer); + del_timer(&vp->rx_oom_timer); /* Turn off statistics ASAP. We update vp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -2127,10 +2078,7 @@ vortex_close(struct device *dev) outl(0, ioaddr + UpListPtr); for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - vp->rx_skbuff[i]->free = 1; -#endif - DEV_FREE_SKB(vp->rx_skbuff[i]); + dev_kfree_skb(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } @@ -2138,11 +2086,13 @@ vortex_close(struct device *dev) outl(0, ioaddr + DownListPtr); for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { - DEV_FREE_SKB(vp->tx_skbuff[i]); + dev_kfree_skb(vp->tx_skbuff[i]); vp->tx_skbuff[i] = 0; } } + if (vp->enable_wol && (vp->capabilities & CapPwrMgmt)) + acpi_set_WOL(dev); MOD_DEC_USE_COUNT; return 0; @@ -2219,7 +2169,7 @@ static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd) retval = 0; break; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) { + if (!capable(CAP_NET_ADMIN)) { retval = -EPERM; } else { EL3WINDOW(4); @@ -2349,22 +2299,66 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value) return; } +/* ACPI: Advanced Configuration and Power Interface. */ +/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ +static void acpi_set_WOL(struct device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + long ioaddr = dev->base_addr; + + /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ + EL3WINDOW(7); + outw(2, ioaddr + 0x0c); + /* The RxFilter must accept the WOL frames. */ + outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); + outw(RxEnable, ioaddr + EL3_CMD); + /* Change the power state to D3; RxEnable doesn't take effect. */ + pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103); +} + +/* Change from D3 (sleep) to D0 (active). + Problem: The Cyclone forgets all PCI config info during the transition! */ +static void acpi_wake(int bus, int devfn) +{ + u32 base0, base1, romaddr; + u16 pci_command, pwr_command; + u8 pci_latency, pci_cacheline, irq; + + pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command); + if ((pwr_command & 3) == 0) + return; + pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command); + pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0); + pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1); + pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr); + pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency); + pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline); + pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq); + + pcibios_write_config_word( bus, devfn, 0xe0, 0x0000); + pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0); + pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1); + pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr); + pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq); + pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency); + pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline); + pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5); +} + #ifdef MODULE void cleanup_module(void) { struct device *next_dev; -#ifdef CARDBUS - unregister_driver(&vortex_ops); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_vortex_dev) { struct vortex_private *vp=(void *)(root_vortex_dev->priv); + int drv_flags = pci_tbl[vp->chip_id].drv_flags; next_dev = vp->next_module; unregister_netdev(root_vortex_dev); - outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); + outw((drv_flags & EEPROM_NORESET) ? (TotalReset|0x10) : TotalReset, + root_vortex_dev->base_addr + EL3_CMD); release_region(root_vortex_dev->base_addr, pci_tbl[vp->chip_id].io_size); kfree(root_vortex_dev); @@ -2377,9 +2371,6 @@ void cleanup_module(void) /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" - * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index ed56c3542093..c480895748b3 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -5,12 +5,12 @@ Maintained by Jeff Garzik Much code comes from Donald Becker's rtl8139.c driver, - versions 1.11 and older. This driver was originally based - on rtl8139.c version 1.07. Header of rtl8139.c version 1.11: + versions 1.13 and older. This driver was originally based + on rtl8139.c version 1.07. Header of rtl8139.c version 1.13: ---------- - Written 1997-2000 by Donald Becker. + Written 1997-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Drivers based on or derived from this @@ -74,6 +74,9 @@ Tobias Ringström - Rx interrupt status checking suggestion + Andrew Morton - Clear blocked signals, avoid + buffer overrun setting current->comm. + Submitting bug reports: "rtl8139-diag -mmmaaavvveefN" output @@ -147,7 +150,7 @@ an MMIO register read. #include -#define RTL8139_VERSION "0.9.12-2.2" +#define RTL8139_VERSION "0.9.14-2.2" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " FastEthernet driver " RTL8139_VERSION #define RTL8139_AUTHOR "Jeff Garzik " @@ -283,7 +286,9 @@ static void rtl8139_read_pci_resources(struct pci_dev *dev, struct resource *res /* A few user-configurable values. */ /* media options */ -static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#define MAX_UNITS 8 +static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -325,6 +330,7 @@ static int multicast_filter_limit = 32; enum { + HAS_MII_XCVR = 0x010000, HAS_CHIP_XCVR = 0x020000, HAS_LNK_CHNG = 0x040000, }; @@ -332,26 +338,34 @@ enum { #define RTL_MIN_IO_SIZE 0x80 #define RTL8139B_IO_SIZE 256 +#define RTL8129_CAPS HAS_MII_XCVR #define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG typedef enum { RTL8139 = 0, RTL8139_CB, SMC1211TX, + /*MPX5030,*/ DELTA8139, ADDTRON8139, + DFE538TX, + RTL8129, } board_t; /* indexed by board_t, above */ static struct { const char *name; + u32 hw_flags; } board_info[] = { - { "RealTek RTL8139 Fast Ethernet" }, - { "RealTek RTL8139B PCI/CardBus" }, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" }, - { "Delta Electronics 8139 10/100BaseTX" }, - { "Addtron Technolgy 8139 10/100BaseTX" }, + { "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS }, + { "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS }, + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS }, +/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/ + { "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS }, + { "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS }, + { "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS }, + { "RealTek RTL8129", RTL8129_CAPS }, }; struct pci_device_id { @@ -363,8 +377,11 @@ static struct pci_device_id rtl8139_pci_tbl[] = { {0x10ec, 0x8139, RTL8139 }, {0x10ec, 0x8138, RTL8139_CB }, {0x1113, 0x1211, SMC1211TX }, +/* {0x1113, 0x1211, MPX5030 },*/ {0x1500, 0x1360, DELTA8139 }, {0x4033, 0x1360, ADDTRON8139 }, + {0x1186, 0x1300, DFE538TX }, + {0x10ec, 0x8129, RTL8129 }, {0,} }; @@ -601,7 +618,6 @@ const static struct { struct rtl8139_private { - board_t board; void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; @@ -610,8 +626,8 @@ struct rtl8139_private { unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ unsigned int tx_flag; - unsigned int cur_tx; - unsigned int dirty_tx; + unsigned long cur_tx; + unsigned long dirty_tx; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ @@ -619,6 +635,7 @@ struct rtl8139_private { dma_addr_t rx_ring_dma; dma_addr_t tx_bufs_dma; char phys[4]; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; @@ -841,14 +858,6 @@ static int rtl8139_init_board (struct pci_dev *pdev, struct device **dev_out, RTL_W8 (Config1, 0); } -#ifndef USE_IO_OPS - /* sanity checks -- ensure PIO and MMIO registers agree */ - assert (inb (pio_start+Config0) == readb (ioaddr+Config0)); - assert (inb (pio_start+Config1) == readb (ioaddr+Config1)); - assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig)); - assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); -#endif /* !USE_IO_OPS */ - /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { @@ -949,17 +958,13 @@ static int rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *e tp = dev->priv; /* note: tp->chipset set in rtl8139_init_board */ - tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | RTL8139_CAPS; + tp->drv_flags = board_info[ent->board].hw_flags; tp->pci_dev = pdev; - tp->board = ent->board; tp->mmio_addr = ioaddr; spin_lock_init (&tp->lock); init_waitqueue_head (&tp->thr_wait); init_MUTEX_LOCKED (&tp->thr_exited); - tp->phys[0] = 32; - if (rtl8139_device_count == 0) { printk (KERN_INFO "%s: " RTL8139_DRIVER_NAME " " RTL8139_AUTHOR "\n", dev->name); printk (KERN_INFO "%s: Linux-2.2 bug reports to Jens David \n", dev->name); @@ -976,6 +981,30 @@ static int rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *e dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + if (tp->drv_flags & HAS_MII_XCVR) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + tp->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " + "advertising %4.4x.\n", + dev->name, phy, mii_status, tp->advertising); + } + } + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " + "transceiver.\n", + dev->name); + tp->phys[0] = 32; + } + } else + tp->phys[0] = 32; + /* Put the chip into low-power mode. */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -986,21 +1015,29 @@ static int rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *e RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ /* The lower four bits are the media type. */ - option = (board_idx >= ARRAY_SIZE(media)) ? 0 : media[board_idx]; + option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; if (option > 0) { - tp->full_duplex = (option & 0x200) ? 1 : 0; - tp->default_port = option & 15; + tp->full_duplex = (option & 0x210) ? 1 : 0; + tp->default_port = option & 0xFF; if (tp->default_port) tp->medialock = 1; } - + if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) + tp->full_duplex = full_duplex[board_idx]; if (tp->full_duplex) { - printk (KERN_INFO - "%s: Media type forced to Full Duplex.\n", - dev->name); - mdio_write (dev, tp->phys[0], 4, 0x141); + printk (KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); + /* Changing the MII-advertised media because might prevent + re-connection. */ tp->duplex_lock = 1; } + if (tp->default_port) { + printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", + (option & 0x20 ? 100 : 10), + (option & 0x10 ? "full" : "half")); + mdio_write(dev, tp->phys[0], 0, + ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + } rtl8139_device_tab[rtl8139_device_count++] = dev; @@ -1120,7 +1157,7 @@ static int read_eeprom (void *ioaddr, int location, int addr_len) #define MDIO_WRITE0 (MDIO_DIR) #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) -#define mdio_delay() readb(mdio_addr) +#define mdio_delay(mdio_addr) readb(mdio_addr) static char mii_2_8139_map[8] = { @@ -1144,9 +1181,9 @@ static void mdio_sync (void *mdio_addr) for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } DPRINTK ("EXIT\n"); @@ -1174,20 +1211,18 @@ static int mdio_read (struct device *dev, int phy_id, int location) int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; writeb (MDIO_DIR | dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); - retval = - (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 - : 0); + mdio_delay (mdio_addr); + retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); @@ -1200,19 +1235,19 @@ static void mdio_write (struct device *dev, int phy_id, int location, { struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; - int mii_cmd = - (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i; DPRINTK ("ENTER\n"); if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - if (location < 8 && mii_2_8139_map[location]) { - writew (value, - tp->mmio_addr + mii_2_8139_map[location]); - readw (tp->mmio_addr + mii_2_8139_map[location]); - } - DPRINTK ("EXIT after directly using 8139 internal regs\n"); + void *ioaddr = tp->mmio_addr; + if (location == 0) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W16_F (BasicModeCtrl, value); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } else if (location < 8 && mii_2_8139_map[location]) + RTL_W16_F (mii_2_8139_map[location], value); return; } mdio_sync (mdio_addr); @@ -1222,20 +1257,19 @@ static void mdio_write (struct device *dev, int phy_id, int location, int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; writeb (dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } - - DPRINTK ("EXIT\n"); + return; } @@ -1249,9 +1283,12 @@ static int rtl8139_open (struct device *dev) DPRINTK ("ENTER\n"); + MOD_INC_USE_COUNT; + retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); if (retval) { DPRINTK ("EXIT, returning %d\n", retval); + MOD_DEC_USE_COUNT; return retval; } @@ -1267,6 +1304,7 @@ static int rtl8139_open (struct device *dev) if (tp->rx_ring) kfree(tp->rx_ring); DPRINTK ("EXIT, returning -ENOMEM\n"); + MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -1313,6 +1351,8 @@ static void rtl8139_hw_start (struct device *dev) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; + /* unlock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); @@ -1328,12 +1368,23 @@ static void rtl8139_hw_start (struct device *dev) /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); - /* unlock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - udelay (10); - tp->cur_rx = 0; + /* This is check_duplex() */ + if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) { + u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); + if (mii_reg5 == 0xffff) + ; /* Not there */ + else if ((mii_reg5 & 0x0100) == 0x0100 + || (mii_reg5 & 0x00C0) == 0x0040) + tp->full_duplex = 1; + printk(KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability %4.4x.\n", dev->name, + mii_reg5 == 0 ? "" : + (mii_reg5 & 0x0180) ? "100Mbps " : "10Mbps ", + tp->full_duplex ? "full" : "half", mii_reg5); + } + if (tp->chipset >= CH_8139A) { tmp = RTL_R8 (Config1) & Config1Clear; tmp |= Cfg1_Driver_Load; @@ -1536,7 +1587,7 @@ static inline void rtl8139_thread_iter (struct device *dev, DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", dev->name, RTL_R16 (NWayLPAR)); DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4x.\n", dev->name, + " RxStatus %4.4lx.\n", dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus), RTL_R32 (RxEarlyStatus)); @@ -1553,7 +1604,13 @@ static int rtl8139_thread (void *data) unsigned long timeout; daemonize (); - sprintf (current->comm, "k8139d-%s", dev->name); + spin_lock_irq(¤t->sigmask_lock); + sigemptyset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + strncpy (current->comm, dev->name, sizeof(current->comm) - 1); + current->comm[sizeof(current->comm) - 1] = '\0'; while (1) { timeout = next_tick; @@ -1615,7 +1672,7 @@ static void rtl8139_tx_timeout (struct device *dev) RTL_W16 (IntrMask, 0x0000); /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", + printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", dev->name, tp->cur_tx, tp->dirty_tx); for (i = 0; i < NUM_TX_DESC; i++) printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", @@ -1665,11 +1722,15 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct device *dev) tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; + + spin_lock_irq (&tp->lock); + tp->cur_tx++; - mb(); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); + spin_unlock_irq (&tp->lock); + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); @@ -1681,7 +1742,7 @@ static void rtl8139_tx_interrupt (struct device *dev, struct rtl8139_private *tp, void *ioaddr) { - unsigned int dirty_tx, tx_left; + unsigned long dirty_tx, tx_left; assert (dev != NULL); assert (tp != NULL); @@ -1736,8 +1797,7 @@ static void rtl8139_tx_interrupt (struct device *dev, #ifndef RTL8139_NDEBUG if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk (KERN_ERR - "%s: Out-of-sync dirty pointer, %d vs. %d.\n", + printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } @@ -1746,7 +1806,6 @@ static void rtl8139_tx_interrupt (struct device *dev, /* only wake the queue if we did work, and the queue is stopped */ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; - mb(); if (netif_queue_stopped (dev)) netif_wake_queue (dev); } @@ -1979,8 +2038,6 @@ static void rtl8139_interrupt (int irq, void *dev_instance, void *ioaddr = tp->mmio_addr; int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ - spin_lock (&tp->lock); - do { status = RTL_R16 (IntrStatus); @@ -2031,8 +2088,11 @@ static void rtl8139_interrupt (int irq, void *dev_instance, if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ rtl8139_rx_interrupt (dev, tp, ioaddr); - if (status & (TxOK | TxErr)) + if (status & (TxOK | TxErr)) { + spin_lock (&tp->lock); rtl8139_tx_interrupt (dev, tp, ioaddr); + spin_unlock (&tp->lock); + } boguscnt--; } while (boguscnt > 0); @@ -2047,8 +2107,6 @@ static void rtl8139_interrupt (int irq, void *dev_instance, RTL_W16 (IntrStatus, 0xffff); } - spin_unlock (&tp->lock); - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -2121,6 +2179,8 @@ static int rtl8139_close (struct device *dev) RTL_W8 (Config1, 0x03); RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + MOD_DEC_USE_COUNT; + DPRINTK ("EXIT\n"); return 0; } @@ -2149,8 +2209,20 @@ static int mii_ioctl (struct device *dev, struct ifreq *rq, int cmd) break; } - mdio_write (dev, data[0], data[1] & 0x1f, data[2]); - break; + if (data[0] == tp->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + tp->medialock = (value & 0x9000) ? 0 : 1; + if (tp->medialock) + tp->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: tp->advertising = value; break; + } + } + mdio_write(dev, data[0], data[1] & 0x1f, data[2]); + break; default: rc = -EOPNOTSUPP; @@ -2170,8 +2242,10 @@ static struct net_device_stats *rtl8139_get_stats (struct device *dev) DPRINTK ("ENTER\n"); if (netif_running(dev)) { + spin_lock_irq(&tp->lock); tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + spin_unlock_irq(&tp->lock); } DPRINTK ("EXIT\n"); @@ -2194,8 +2268,7 @@ static inline u32 ether_crc (int length, unsigned char *data) unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? + crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } @@ -2208,13 +2281,14 @@ static void rtl8139_set_rx_mode (struct device *dev) { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; u32 tmp; DPRINTK ("ENTER\n"); - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", + DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, dev->flags, RTL_R32 (RxConfig)); /* Note: do not reorder, GCC is clever about common statements. */ @@ -2241,7 +2315,7 @@ static void rtl8139_set_rx_mode (struct device *dev) mc_filter); } - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); /* We can safely update without stopping the chip. */ tmp = rtl8139_rx_config | rx_mode | @@ -2250,7 +2324,7 @@ static void rtl8139_set_rx_mode (struct device *dev) RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } @@ -2291,7 +2365,8 @@ MODULE_AUTHOR (RTL8139_AUTHOR); MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver"); MODULE_PARM (multicast_filter_limit, "i"); MODULE_PARM (max_interrupt_work, "i"); -MODULE_PARM (media, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); int init_module(void) { diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index 558c03090b01..d39a080774dc 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -82,8 +82,6 @@ #include #include -int last_retran; - static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); @@ -257,8 +255,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, ip = (struct iphdr *) icp; /* Bail if this packet isn't TCP, or is an IP fragment */ - if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || - (ip->frag_off & 32)){ + if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { /* Send as regular IP */ if(ip->protocol != IPPROTO_TCP) comp->sls_o_nontcp++; @@ -352,10 +349,9 @@ found: */ oth = &cs->cs_tcp; - if(last_retran - || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos - || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64) + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) || ip->ttl != cs->cs_ip.ttl || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index f719e33909fe..a3bde7c72ab7 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -3523,6 +3523,7 @@ int __init happy_meal_probe(struct device *dev) struct linux_sbus_device *sdev = 0; static int called = 0; int cards = 0, v; + char model[128]; if(called) return ENODEV; @@ -3534,7 +3535,13 @@ int __init happy_meal_probe(struct device *dev) dev = NULL; if(!strcmp(sdev->prom_name, "SUNW,hme")) { cards++; - if((v = happy_meal_ether_init(dev, sdev, 0))) + prom_getstring(sdev->prom_node, "model", + model, sizeof(model)); + if (!strcmp(model, "SUNW,sbus-qfe")) + v = happy_meal_ether_init(dev, sdev, 1); + else + v = happy_meal_ether_init(dev, sdev, 0); + if(v) return v; } else if(!strcmp(sdev->prom_name, "qfe") || !strcmp(sdev->prom_name, "SUNW,qfe")) { @@ -3582,12 +3589,21 @@ void cleanup_module(void) { struct happy_meal *sunshine; + struct quattro *last_seen_qfe = NULL; /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_happy_dev) { struct happy_meal *hp = root_happy_dev; sunshine = root_happy_dev->next_module; + if (!(hp->happy_flags & HFLAG_PCI) && + (hp->happy_flags & HFLAG_QUATTRO)) { + if (hp->qfe_parent != last_seen_qfe) { + free_irq(hp->dev->irq, hp->qfe_parent); + last_seen_qfe = hp->qfe_parent; + } + } + sparc_free_io(hp->gregs, sizeof(struct hmeal_gregs)); sparc_free_io(hp->etxregs, sizeof(struct hmeal_etxregs)); sparc_free_io(hp->erxregs, sizeof(struct hmeal_erxregs)); diff --git a/drivers/s390/Config.in b/drivers/s390/Config.in index 53f5b894d237..6da5d6c11b6c 100644 --- a/drivers/s390/Config.in +++ b/drivers/s390/Config.in @@ -53,7 +53,7 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_NETDEVICES" = "y" ]; then comment 'S390 Network devices' tristate 'CTC device support' CONFIG_CTC - bool 'IUCV device support (VM only)' CONFIG_IUCV + tristate 'IUCV device support (VM only)' CONFIG_IUCV tristate 'Dummy net driver support' CONFIG_DUMMY bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET bool 'Token Ring driver support' CONFIG_TR diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 89174105a268..06ba81ebad3d 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -11,12 +11,13 @@ all: io.o CFLAGS += O_TARGET := io.o -O_OBJS := ccwcache.o idals.o +O_OBJS := idals.o +OX_OBJS := ccwcache.o M_OBJS := SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \ arch/s390/drivers/misc arch/s390/drivers/net -MOD_SUB_DIRS += ./net ./block +MOD_SUB_DIRS += ./net ./block ./char O_OBJS += block/s390-block.o \ char/s390-char.o \ diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index 53ab87600e4d..2b77ade87109 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile @@ -4,10 +4,11 @@ CFLAGS += O_TARGET := s390-block.o O_OBJS := M_OBJS := -D_OBJS := +MI_OBJS := +MIX_OBJS := ifeq ($(CONFIG_DASD),y) - O_OBJS += dasd.o + OX_OBJS += dasd.o ifeq ($(CONFIG_DASD_ECKD),y) O_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o endif @@ -17,26 +18,20 @@ ifeq ($(CONFIG_DASD),y) ifeq ($(CONFIG_DASD_MDSK),y) O_OBJS += dasd_diag.o endif -# ifeq ($(CONFIG_DASD_CKD),y) -# O_OBJS += dasd_ckd.o -# endif endif ifeq ($(CONFIG_DASD),m) M_OBJS += dasd_mod.o - D_OBJS += dasd.o + MIX_OBJS += dasd.o ifeq ($(CONFIG_DASD_ECKD),y) - D_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o + MI_OBJS += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o endif ifeq ($(CONFIG_DASD_FBA),y) - D_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o + MI_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o endif ifeq ($(CONFIG_DASD_MDSK),y) - D_OBJS += dasd_diag.o + MI_OBJS += dasd_diag.o endif -# ifeq ($(CONFIG_DASD_CKD),y) -# O_OBJS += dasd_ckd.o -# endif endif ifeq ($(CONFIG_MDISK),y) @@ -51,7 +46,7 @@ else endif endif -dasd_mod.o: $(D_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ $(D_OBJS) +dasd_mod.o: $(MI_OBJS) $(MIX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS) include $(TOPDIR)/Rules.make diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 6dc1b7070723..1f9ee7a97610 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1,9 +1,10 @@ /* * File...........: linux/drivers/s390/block/dasd.c * Author(s)......: Holger Smolinski + * Horst Hummel * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 - + * * History of changes (starts July 2000) * 07/03/00 Adapted code to compile with 2.2 and 2.4 kernels * 07/05/00 Added some missing cases when shutting down a device @@ -36,8 +37,12 @@ * 10/26/00 fixed ITPM PL010261EPA race condition when formatting are the fixes in dasd_do_chanq * 11/21/00 fixed BLKFLSBUF ioctl and dasd_release to flush the buffers + * 01/17/01 fixed PL020234MVE problem accessing DASD 68-127, 133-191,... + * 01/23/01 fixed sleep_on_request to terminate when signal_pending + * 01/25/01 added code for error recovery with PAC'0x1D' = long busy */ +#include #include #include #include @@ -96,12 +101,7 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct block_device_operations dasd_device_operations; #endif /* VERSION_CODE */ - -#ifdef MODULE -#define EXPORT_SYMTAB -#include -EXPORT_NO_SYMBOLS; MODULE_AUTHOR ("Holger Smolinski "); MODULE_DESCRIPTION ("Linux on S/390 DASD device driver, Copyright 2000 IBM Corporation"); MODULE_SUPPORTED_DEVICE("dasd"); @@ -113,13 +113,8 @@ EXPORT_SYMBOL (dasd_int_handler); EXPORT_SYMBOL (dasd_alloc_request); EXPORT_SYMBOL (dasd_free_request); -#else -#endif /* MODULE */ - /* SECTION: Constant definitions to be used within this file */ -#ifdef PRINTK_HEADER #undef PRINTK_HEADER -#endif #define PRINTK_HEADER DASD_NAME":" #define DASD_QUEUE_LIMIT 10 @@ -252,7 +247,7 @@ dasd_split_parm_string ( char * str ) static char dasd_parm_string[1024] = {0,}; -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17)) static int dasd_setup (char *str) { @@ -280,7 +275,7 @@ dasd_setup (char *str, int *ints) #endif /* LINUX_IS_24 */ -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17)) __setup("dasd=", dasd_setup); #endif /* LINUX_IS_24 */ @@ -476,7 +471,7 @@ dasd_discipline_deq (dasd_discipline_t * d) * void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) */ -static void +void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) { if (q->head != NULL) { @@ -493,7 +488,7 @@ dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) * void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) */ -static void +void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) { cqr->next = q->head; @@ -501,14 +496,17 @@ dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) if (q->tail == NULL) q->tail = cqr; q->queued_requests++; - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED); + + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_FILLED, + CQR_STATUS_QUEUED); } /* * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) */ -static int +int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) { ccw_req_t *prev; @@ -776,9 +774,8 @@ dasd_start_IO (ccw_req_t * cqr) int retries = DASD_SSCH_RETRIES; dasd_device_t *device = cqr->device; int irq, devno; - int devindex, partn; + int devindex; major_info_t *major_info; - struct request *req; if (!cqr) { printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function"); @@ -786,10 +783,9 @@ dasd_start_IO (ccw_req_t * cqr) } irq = device->devinfo.irq; devno = device->devinfo.devno; - req = (struct request *) cqr->req; - devindex = devindex_from_kdev_t (req->rq_dev); + devindex = devindex_from_devno (devno); major_info = major_info_from_devindex (devindex); - partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1); + if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) { printk (KERN_WARNING PRINTK_HEADER "0x%04X on sch %d = /dev/%s (%d:%d)" @@ -801,10 +797,12 @@ dasd_start_IO (ccw_req_t * cqr) cqr->magic, *(long *) device->discipline->name); return -EINVAL; } - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_QUEUED, + CQR_STATUS_IN_IO); do { asm volatile ("STCK %0":"=m" (cqr->startclk)); - rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options); + rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options); switch (rc) { case 0: if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) { @@ -848,7 +846,7 @@ dasd_start_IO (ccw_req_t * cqr) if (rc) { atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, - CQR_STATUS_ERROR); + CQR_STATUS_FAILED); } return rc; } @@ -879,6 +877,10 @@ sleep_on_req ( ccw_req_t * req ) schedule (); s390irq_spin_lock_irqsave (device->devinfo.irq, flags); cs = atomic_read (&req->status); + if ( signal_pending(current) ) { + rc = -ERESTARTSYS; + break; + } } while ( ! (cs & CQR_STATUS_FINISHED) ); /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */ remove_wait_queue (&device->wait_q, &wait); @@ -1178,189 +1180,216 @@ dasd_do_chanq (void) printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Failing to start I/O operation with rc %d\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc); + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, rc); switch (rc) { case EBUSY: if (cqr->retries--) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:" " retrying ... %d retries left\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, cqr->retries); break; } default:{ /* Fallthrough ?? */ printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Giving up this request!\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_QUEUED, - CQR_STATUS_FAILED | CQR_STATUS_FINISHED); + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); break; } } } break; case CQR_STATUS_IN_IO:{ - unsigned long long now; - unsigned long long delta; - - asm volatile ("STCK %0":"=m" (now)); - if (cqr->expires && cqr->startclk && - cqr->expires < now) { - delta = cqr->expires - cqr->startclk; - printk (KERN_ERR PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr); - cqr->expires += delta; + unsigned long long now; + unsigned long long delta; + + asm volatile ("STCK %0":"=m" (now)); + if (cqr->expires && cqr->startclk && + cqr->expires < now) { + delta = cqr->expires - cqr->startclk; + printk (KERN_ERR PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr); + cqr->expires += delta; #if 0 - if ( cqr->retries-- ) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " waiting %d more times\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); - cqr->expires += delta; - break; - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " You should disable that device by issueing '@#?!'\n", /* FIXME */ - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); - halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT); - break; - } + if ( cqr->retries-- ) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " waiting %d more times\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); + cqr->expires += delta; + break; + } else { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " You should disable that device by issueing '@#?!'\n", /* FIXME */ + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); + atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); + halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT); + break; + } #endif - } - break; + } + break; } case CQR_STATUS_ERROR:{ - dasd_erp_action_fn_t erp_action; - ccw_req_t *erp_cqr = NULL; - - if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) { - atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED); - next = cqr; - } else if ( cqr -> retries-- && - cqr -> refers == NULL && - discipline -> erp_action != NULL && - (erp_action = discipline->erp_action (cqr)) != NULL && - (erp_cqr = erp_action (cqr)) != NULL ) { + dasd_erp_action_fn_t erp_action; + ccw_req_t *erp_cqr = NULL; + + if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) { + atomic_compare_and_swap_debug(&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + next = cqr; + } else if (discipline -> erp_action != NULL && + (erp_action = discipline->erp_action (cqr)) != NULL && + (erp_cqr = erp_action (cqr)) != NULL ) { + + if (erp_cqr != cqr){ + dasd_chanq_enq_head (qp, erp_cqr); - next = erp_cqr; /* prefer execution of erp ccw */ - } else { - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - next = cqr; } - break; - } + cqr->retries--; + next = erp_cqr; /* prefer execution of erp ccw */ + + } else { + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + next = cqr; + } + break; + } case CQR_STATUS_DONE:{ - dasd_erp_postaction_fn_t erp_postaction; - next = cqr->next; - asm volatile ("STCK %0":"=m" (cqr->endclk)); - if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if ( discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing successful error recovery action using %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); - erp_postaction (cqr, 1); - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " No procedure to postprocess error recovery action" - " giving up request", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - } + dasd_erp_postaction_fn_t erp_postaction; + next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); + if (cqr->refers && cqr->function) { /* we deal with an ERP */ + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " postprocessing successful ERA using %p\n", + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, erp_postaction); + cqr = erp_postaction (cqr); + next = cqr; + } else { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " No procedure to postprocess ERA - " + " giving up request", + devno, irq, device->name, major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + atomic_dec (&device->queue.dirty_requests); dasd_chanq_deq (&device->queue, cqr); dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else if ( cqr->req ) { - dasd_end_request (cqr->req, 1); + } + } else if ( cqr->req ) { + dasd_end_request (cqr->req, 1); #ifdef DASD_PROFILE - dasd_profile_add (cqr); + dasd_profile_add (cqr); #endif /* DASD_PROFILE */ - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else { - /* during format we don't have the request structure */ - /* notify sleeping task about finished postprocessing */ - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_DONE, - CQR_STATUS_DONE | CQR_STATUS_FINISHED); - dasd_chanq_deq (&device->queue, cqr); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ + } else { + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_DONE, + CQR_STATUS_DONE | CQR_STATUS_FINISHED); + dasd_chanq_deq (&device->queue, cqr); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - wake_up (&device->wait_q); + wake_up (&device->wait_q); #else - if (device->wait_q) { - wake_up (&device->wait_q); - } -#endif /* LINUX_IS_24 */ + if (device->wait_q) { + wake_up (&device->wait_q); } - break; - } +#endif /* LINUX_IS_24 */ + } + break; + } case CQR_STATUS_FAILED:{ - dasd_erp_postaction_fn_t erp_postaction; - next = cqr->next; - asm volatile ("STCK %0":"=m" (cqr->endclk)); - if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if ( discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing unsuccessful error recovery action using %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); - erp_postaction (cqr, 0); - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " No procedure to postprocess unsuccessful error recovery action" - " giving up request", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - } + dasd_erp_postaction_fn_t erp_postaction; + next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); + if (cqr->refers && cqr->function) { /* we deal with an ERP */ + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " postprocessing unsuccessful ERA using %p\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); + cqr = erp_postaction (cqr); + next = cqr; + } else { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " No procedure to postprocess unsuccessful ERA - " + " giving up request", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + atomic_dec (&device->queue.dirty_requests); dasd_chanq_deq (&device->queue, cqr); dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else if (cqr->req) { - dasd_end_request (cqr->req, 0); + } + } else if (cqr->req) { + dasd_end_request (cqr->req, 0); #ifdef DASD_PROFILE - dasd_profile_add (cqr); + dasd_profile_add (cqr); #endif /* DASD_PROFILE */ - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ - } else { - /* during format we don't have the request structure */ - /* notify sleeping task about finished postprocessing */ - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_FAILED, - CQR_STATUS_FAILED | CQR_STATUS_FINISHED); - - dasd_chanq_deq (&device->queue, cqr); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ + } else { + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_FAILED, + CQR_STATUS_FAILED | CQR_STATUS_FINISHED); + + dasd_chanq_deq (&device->queue, cqr); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - wake_up (&device->wait_q); + wake_up (&device->wait_q); #else - if (device->wait_q) { - wake_up (&device->wait_q); - } + if (device->wait_q) { + wake_up (&device->wait_q); + } #endif /* LINUX_IS_24 */ - } - break; - } + } + break; + } - default:{ - printk (KERN_WARNING PRINTK_HEADER - "Internal error in " __FILE__ " on line %d." - " inconsistent content of ccw_req_t" - " cqrstatus = %d" - " Pls send this message and your System.map to" - " linux390@de.ibm.com\n", - __LINE__, cqrstatus); - } + case CQR_STATUS_PENDING: + /* just wait */ + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " CQR_STATUS_PENDING - just wait...\n", + devno, irq, device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + break; + + default: + printk (KERN_WARNING PRINTK_HEADER + "Internal error in " __FILE__ " on line %d." + " inconsistent content of ccw_req_t" + " cqrstatus = %d" + " Pls send this message and your System.map to" + " linux390@de.ibm.com\n", + __LINE__, cqrstatus); + } s390irq_spin_unlock_irqrestore (irq, flags); } while ((cqr = next) != NULL); @@ -1369,6 +1398,56 @@ dasd_do_chanq (void) return; } +/* + * DASD_HANDLE_STATE_CHANGE_PENDING + * + * DESCRIPTION + * Handles the state change pending interrupt. + * Search for the device related request queue and check if the first + * cqr in queue in in status 'CQR_STATUE_PENDING'. + * If so the status is set to 'CQR_STATUS_QUEUED' and the bh is + * scheduled. + * + * PARAMETER + * stat device status of state change pending interrupt. + */ +void +dasd_handle_state_change_pending (devstat_t *stat) +{ + dasd_device_t *device; + ccw_req_t *cqr; + int devindex; + + devindex = devindex_from_devno (stat->devno); + if (devindex < 0) { + return; + } + + device = find_dasd_device (devindex); + if (device == NULL) { + return; + } + + /* re-activate first request in queue */ + cqr = device->queue.head; + + if (cqr != NULL && + atomic_read(&cqr->status) == CQR_STATUS_PENDING ) { + dasd_device_t *device = cqr->device; + + DASD_MESSAGE (KERN_INFO, device, + "%s", + "device request queue restarted by " + "SCP interrupt\n"); + + del_timer(&device->timer); + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); + dasd_schedule_bh(); + } +} /* end dasd_handle_state_change_pending */ + void dasd_int_handler (int irq, void *ds, struct pt_regs *regs) { @@ -1380,8 +1459,7 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) dasd_device_t *device; int devno = -1, devindex = -1; -#undef ERP_DEBUG -#ifdef ERP_DEBUG +#ifdef ERP_DEBUG /* #define ERP_DEBUG is done in dasd.h */ static int counter = 0; #endif @@ -1389,12 +1467,23 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) PRINT_ERR ("handler called without devstat"); return; } + ip = stat->intparm; if (!ip) { /* no intparm: unsolicited interrupt */ PRINT_INFO ("%04X caught unsolicited interrupt\n", stat->devno); + + /* check for state change pending interrupt */ + if (stat->dstat & (DEV_STAT_ATTENTION | + DEV_STAT_DEV_END | + DEV_STAT_UNIT_EXCEP )) { + + dasd_handle_state_change_pending (stat); + } + return; } + if (ip & 0x80000001) { PRINT_INFO ("%04X caught spurious interrupt with parm %08x\n", stat->devno, ip); @@ -1436,20 +1525,63 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) return; } asm volatile ("STCK %0":"=m" (cqr->stopclk)); - if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) && - stat->cstat == 0x00 && - stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || - (device->discipline->examine_error && - (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) { #ifdef ERP_DEBUG - if ( ++counter % 137 == 0 ) { - printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from\n"); + if ((++counter % 937 >= 100) && + ( counter % 937 <= 110) && + ( counter < 5000 ) && + ( counter > 2000 ) ){ + static int fake_count = 0; + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); + printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count); + printk ( KERN_INFO PRINTK_HEADER "***********************************************\n"); era = dasd_era_recover; stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; stat->dstat |= 0x02; - goto error_fake_done; +// reset notification + { + char *sense = stat->ii.sense.data; + char buffer[100]; + memset(sense,0,32); + sprintf(buffer,"CPU ALL TR IO %X INST INT CCW", devno); + cpcmd(buffer,NULL,NULL); + sense[0]=0x10; + sense[4]=0x21; + sense[7]=0x9; + sense[15]=0x4; + sense[16]=0xe5; + sense[18]=0x43; + sense[19]=0xfb; + sense[20]=0x54; + sense[22]=0x0f; + sense[23]=0x09; + sense[26]=0x40; + sense[27]=0xe0; + } +// sense 32 +// { +// char *sense = stat->ii.sense.data; +// sense [25] = 0x1D; +// sense [27] = 0x00; +// //sense [25] = (fake_count % 256); //0x1B; +// //sense [27] = 0x00; +// } +// sense 24 +// { +// char *sense = stat->ii.sense.data; +// sense [0] = (counter % 0xFF); //0x1B; +// sense [1] = ((counter * 7) % 0xFF); //0x1B; +// sense [2] = (fake_count % 0xFF); //0x1B; +// sense [27] = 0x80; +// } } #endif + + if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) && + stat->cstat == 0x00 && + stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || + (device->discipline->examine_error && + (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) { + atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE); atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, @@ -1462,9 +1594,6 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) } } } else { /* only visited in case of error ! */ -#ifdef ERP_DEBUG - error_fake_done: -#endif if (cqr->dstat == NULL) cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC); if (cqr->dstat) { @@ -1512,7 +1641,12 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) ccw_req_t * default_erp_action (ccw_req_t * cqr) { - ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0); + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); + if ( !erp ) { + printk(KERN_WARNING PRINTK_HEADER + "unable to allocate ERP request\n"); + return NULL; + } erp->cpaddr->cmd_code = CCW_CMD_TIC; erp->cpaddr->cda = (__u32)cqr -> cpaddr; @@ -1528,30 +1662,97 @@ default_erp_action (ccw_req_t * cqr) return erp; } -int -default_erp_postaction (ccw_req_t * cqr, int success) +/* + * DEFAULT_ERP_POSTACTION + * + * DESCRIPTION + * Frees all ERPs of the current ERP Chain and set the status + * of the original CQR either to CQR_STATUS_DONE if ERP was successful + * or to CQR_STATUS_FAILED if ERP was NOT successful. + * + * PARAMETER + * erp current erp_head + * + * RETURN VALUES + * cqr pointer to the original CQR + */ +ccw_req_t * +default_erp_postaction (ccw_req_t * erp) { - if (cqr->refers == NULL || cqr->function == NULL) { - printk (KERN_WARNING PRINTK_HEADER - "ERP postaction called for non ERP cqr\n"); - return -EINVAL; + ccw_req_t *cqr = NULL, *free_erp = NULL; + dasd_device_t *device = NULL; + int success; + + device = (dasd_device_t *) (erp->device); + + if (atomic_read(&erp->status) == CQR_STATUS_DONE) + success = 1; + else + success = 0; + +#ifdef ERP_DEBUG + + /* print current erp_chain */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP postaction called for erp chain:\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p with erp function %p\n", + temp_erp, + temp_erp->refers, + temp_erp->function ); + } + } + +#endif /* ERP_DEBUG*/ + + if (erp->refers == NULL || erp->function == NULL) { + panic (PRINTK_HEADER "Programming error in ERP! Postaction called " + "for invalid ERPt\n"); } - if (cqr->function != default_erp_action) { - printk (KERN_WARNING PRINTK_HEADER - "default ERP postaction called for non default ERP cqr\n"); - return -EINVAL; + + /* free all ERPs - but NOT the original cqr */ + while (erp->refers != NULL) { + free_erp = erp; + erp = erp->refers; + /* remove the request from the device queue */ + dasd_chanq_deq (&device->queue, free_erp); + /* free the finished erp request */ + dasd_free_request (free_erp); } - if ( success ) { - atomic_compare_and_swap_debug (&cqr->refers->status, - CQR_STATUS_ERROR, - CQR_STATUS_DONE); - } else { - atomic_compare_and_swap_debug (&cqr->refers->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); - } - return 0; -} + + /* save ptr to original cqr */ + cqr = erp; + + /* set corresponding status to original cqr */ + if (success) { + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + } else { + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + +#ifdef ERP_DEBUG + /* print current erp_chain */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP postaction finished with remaining chain:\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) { + printk (KERN_WARNING PRINTK_HEADER + " erp %p refers to %p \n", + temp_erp, temp_erp->refers); + } + } +#endif /* ERP_DEBUG */ + + return cqr; +} /* end default_erp_postaction */ /* SECTION: The helpers of the struct file_operations */ @@ -1985,10 +2186,6 @@ get_new_major_info (void) major_info_t *major_info = NULL; major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL); if (major_info) { - major_info_t *temp = dasd_major_info; - while (temp->next) - temp = temp->next; - temp->next = major_info; memset (major_info, 0, sizeof (major_info_t)); major_info->read_ahead = 8; @@ -1998,7 +2195,8 @@ get_new_major_info (void) major_info->gendisk.minor_shift = DASD_PARTN_BITS; major_info->gendisk.max_p = 1 << DASD_PARTN_BITS; #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - major_info->gendisk.max_nr= 1 << DASD_PARTN_BITS; + /* HSM changed for PL020234MVE */ + major_info->gendisk.max_nr= DASD_PER_MAJOR; #endif /* LINUX_IS_24 */ major_info->gendisk.nr_real=DASD_PER_MAJOR; } @@ -2013,6 +2211,7 @@ dasd_register_major (major_info_t * major_info) #endif /* LINUX_IS_24 */ int rc = 0; int major; + int need_insert=0; if (major_info == NULL) { major_info = get_new_major_info (); @@ -2024,6 +2223,7 @@ dasd_register_major (major_info_t * major_info) printk (KERN_INFO PRINTK_HEADER "Created another major number\n"); } + need_insert=1; //insert new major info into dasd_major_info later } major = major_info->gendisk.major; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) @@ -2052,6 +2252,13 @@ dasd_register_major (major_info_t * major_info) } } + /* Insert the new major info into dasd_major_info if needed */ + if (need_insert) { + major_info_t *temp = dasd_major_info; + while (temp->next) + temp = temp->next; + temp->next = major_info; + } major_info->dasd_device = (dasd_device_t **) kmalloc( DASD_PER_MAJOR * sizeof(dasd_device_t*), GFP_ATOMIC); memset ( major_info->dasd_device ,0,DASD_PER_MAJOR * sizeof(dasd_device_t*)); @@ -2153,15 +2360,15 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd) index = devindex_from_kdev_t (MKDEV(hd->major,index<minor_shift)); } third = index % 26; - second = (index / 26) % 27; - first = ((index / 26) / 27) % 27; + second = ((index-26) / 26) % 26; + first = (((index-702) / 26) / 26) % 26; len = sprintf (str, "dasd"); - if (first) { - len += sprintf (str + len, "%c", first + 'a' - 1 ); + if (index>701) { + len += sprintf (str + len, "%c", first + 'a' ); } - if (second) { - len += sprintf (str + len, "%c", second + 'a' - 1 ); + if (index>25) { + len += sprintf (str + len, "%c", second + 'a' ); } len += sprintf (str + len, "%c", third + 'a' ); if (partition) { @@ -2307,6 +2514,7 @@ dasd_set_device_level (unsigned int irq, int desired_level, #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) init_waitqueue_head(&device->wait_q); #endif /* KERNEL_VERSION */ + init_timer(&device->timer); minor = MINOR(device->kdev); current_level = atomic_read (&device->level); if (desired_level > current_level) { @@ -2509,6 +2717,14 @@ typedef struct { int len; } tempinfo_t; +void dasd_fill_inode (struct inode* inode, int fill) { + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct proc_dir_entry *dasd_proc_root_entry = NULL; #else @@ -2521,7 +2737,8 @@ static struct proc_dir_entry dasd_proc_root_entry = nlink:1, uid:0, gid:0, - size:0 + size:0, + fill_inode:dasd_fill_inode }; #endif /* KERNEL_VERSION */ static struct proc_dir_entry* dasd_devices_entry; @@ -2604,6 +2821,9 @@ dasd_devices_open (struct inode* inode, struct file* file ) temp = temp->next; } info->len=len; +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif return rc; } @@ -2661,6 +2881,9 @@ dasd_devices_close (struct inode* inode, struct file* file) if ( p_info->data ) vfree(p_info->data); vfree(p_info); } +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif return rc; } diff --git a/drivers/s390/block/dasd.h b/drivers/s390/block/dasd.h index 3a0313007f88..ffcb991924f7 100644 --- a/drivers/s390/block/dasd.h +++ b/drivers/s390/block/dasd.h @@ -1,5 +1,4 @@ ccw_req_t *default_erp_action (ccw_req_t *); -int default_erp_postaction ( ccw_req_t *, int); int dasd_start_IO (ccw_req_t * cqr); void dasd_int_handler (int , void *, struct pt_regs *); ccw_req_t * dasd_alloc_request (char *, int , int ) ; diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index a116db771ba4..797fa20948a6 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -1,47 +1,31 @@ /* * File...........: linux/drivers/s390/block/dasd_3990_erp.c - * Author(s)......: Holger Smolinski - * Horst Hummel + * Author(s)......: Horst Hummel + * Holger Smolinski * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 */ #include #include +#include #include +#include +#include +#include "dasd_eckd.h" +#include "dasd_3990_erp.h" #ifdef PRINTK_HEADER #undef PRINTK_HEADER -#define PRINTK_HEADER "dasd_erp(3990)" -#endif /* PRINTK_HEADER */ +#endif /* PRINTK_HEADER */ +#define PRINTK_HEADER "dasd_erp(3990): " + /* - * DASD_3990_ERP_EXAMINE_32 - * - * DESCRIPTION - * Checks only for fatal/no/recoverable error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for recoverable others. + ***************************************************************************** + * SECTION ERP EXAMINATION + ***************************************************************************** */ -dasd_era_t -dasd_3990_erp_examine_32 (char *sense) -{ - - switch (sense[25]) { - case 0x00: - return dasd_era_none; - case 0x01: - return dasd_era_fatal; - default: - return dasd_era_recover; - } - -} /* end dasd_3990_erp_examine_32 */ /* * DASD_3990_ERP_EXAMINE_24 @@ -53,7 +37,7 @@ dasd_3990_erp_examine_32 (char *sense) * * Each bit configuration leading to an action code 2 (Exit with * programming error or unusual condition indication) - * and 10 (disabled interface) are handled as fatal error´s. + * are handled as fatal error´s. * * All other configurations are handled as recoverable errors. * @@ -65,31 +49,58 @@ dasd_era_t dasd_3990_erp_examine_24 (char *sense) { - /* check for 'Command Recejct' whithout environmental data present */ - if (sense[0] & 0x80) { - if (sense[2] &0x10){ - return dasd_era_recover; - } else { - return dasd_era_fatal; - } - } - - /* check for 'Invalid Track Format' whithout environmental data present */ - if (sense[1] & 0x40) { - if (sense[2] &0x10){ - return dasd_era_recover; - } else { - return dasd_era_fatal; - } + /* check for 'Command Recejct' which is always a fatal error */ + if (sense[0] & SNS0_CMD_REJECT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } + } + /* check for 'Invalid Track Format' */ + if (sense[1] & SNS1_INV_TRACK_FORMAT) { + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + return dasd_era_recover; + } else { + return dasd_era_fatal; + } } /* check for 'No Record Found' */ - if (sense[1] & 0x08) { + if (sense[1] & SNS1_NO_REC_FOUND) { return dasd_era_fatal; } /* return recoverable for all others */ return dasd_era_recover; -} /* END dasd_3990_erp_examine_24 */ +} /* END dasd_3990_erp_examine_24 */ + +/* + * DASD_3990_ERP_EXAMINE_32 + * + * DESCRIPTION + * Checks only for fatal/no/recoverable error. + * A detailed examination of the sense data is done later outside + * the interrupt handler. + * + * RETURN VALUES + * dasd_era_none no error + * dasd_era_fatal for all fatal (unrecoverable errors) + * dasd_era_recover for recoverable others. + */ +dasd_era_t +dasd_3990_erp_examine_32 (char *sense) +{ + + switch (sense[25]) { + case 0x00: + return dasd_era_none; + case 0x01: + return dasd_era_fatal; + default: + return dasd_era_recover; + } + +} /* end dasd_3990_erp_examine_32 */ /* * DASD_3990_ERP_EXAMINE @@ -119,19 +130,1134 @@ dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat) return dasd_era_none; /* distinguish between 24 and 32 byte sense data */ - if (sense[27] & 0x80) { + if (sense[27] & DASD_SENSE_BIT_0) { + + /* examine the 24 byte sense data */ + return dasd_3990_erp_examine_24 (sense); + + } else { /* examine the 32 byte sense data */ return dasd_3990_erp_examine_32 (sense); + } /* end distinguish between 24 and 32 byte sense data */ + +} /* END dasd_3990_erp_examine */ + +/* + ***************************************************************************** + * SECTION ERP HANDLING + ***************************************************************************** + */ +/* + ***************************************************************************** + * 24 and 32 byte sense ERP functions + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_BLOCK_QUEUE + * + * DESCRIPTION + * Block the given device request queue to prevent from further + * processing until the started timer has expired or an related + * interrupt was received. + * + * PARAMETER + * erp request to be blocked + * expires time to wait until restart (in seconds) + * + * RETURN VALUES + * void + */ +void +dasd_3990_erp_block_queue (ccw_req_t *erp, + unsigned long expires) +{ + + dasd_device_t *device = erp->device; + + DASD_MESSAGE (KERN_INFO, device, + "blocking request queue for %is", + (int) expires); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_PENDING); + + /* restart queue after some time */ + device->timer.function = dasd_3990_erp_restart_queue; + device->timer.data = (unsigned long) erp; + device->timer.expires = jiffies + (expires * HZ); + add_timer(&device->timer); + + /* restart queue using int handler routing - just for testing - TDB */ + /* insert "void dasd_handle_state_change_pending (devstat_t *stat);" to dasd.h */ +// device->timer.function = dasd_handle_state_change_pending; +// device->timer.data = (unsigned long) &device->dev_status; +// device->timer.expires = jiffies + (expires * HZ); +// add_timer(&device->timer); + +} /* end dasd_3990_erp_block_queue */ + +/* + * DASD_3990_ERP_RESTART_QUEUE + * + * DESCRIPTION + * Restarts request currently in status PENDING. + * This has to be done if either an related interrupt has received, or + * a timer has expired. + * + * + * PARAMETER + * erp pointer to the PENDING ERP + * + * RETURN VALUES + * void + * + */ +void +dasd_3990_erp_restart_queue (unsigned long erp) +{ + ccw_req_t *cqr = (void *) erp; + dasd_device_t *device = cqr->device; + unsigned long flags; + + /* TBD delete */ + DASD_MESSAGE (KERN_INFO, device, + "%s irq %d erp %p", + "dasd_3990_erp_restart_queue entered",device->devinfo.irq, erp); + /* get the needed locks to modify the request queue */ + s390irq_spin_lock_irqsave (device->devinfo.irq, + flags); + + /* 'restart' the device queue */ + if (atomic_read(&cqr->status) == CQR_STATUS_PENDING){ + + DASD_MESSAGE (KERN_INFO, device, + "%s", + "request queue restarted by MIH"); + + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_PENDING, + CQR_STATUS_QUEUED); +} + + /* release the lock */ + s390irq_spin_unlock_irqrestore (device->devinfo.irq, + flags); + dasd_schedule_bh(); + +} /* end dasd_3990_erp_restart_queue */ + +/* + * DASD_3990_ERP_ALTERNATE_PATH + * + * DESCRIPTION + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp modified pointer to the ERP + * + */ +void +dasd_3990_erp_alternate_path (ccw_req_t *erp) +{ + + dasd_device_t *device = erp->device; + int irq = device->devinfo.irq; + + /* dissable current channel path - this causes the use of an other + channel path if there is one.. */ + + DASD_MESSAGE (KERN_WARNING, device, + "disable lpu %x", + erp->dstat->lpum); + + /* try alternate valid path */ + erp->lpm &= ~(erp->dstat->lpum); + erp->options |= DOIO_VALID_LPM; /* use LPM for DO_IO */ + + if ((erp->lpm & ioinfo[irq]->opm) != 0x00) { + + DASD_MESSAGE (KERN_WARNING, device, + "try alternate lpm %x", + erp->lpm); + + /* reset status to queued to handle the request again... */ + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + + erp->retries = 1; + } else { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "No alternate channel path left -> " + "permanent error"); + + /* post request with permanent error */ + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); - /* examine the 24 byte sense data */ - return dasd_3990_erp_examine_24 (sense); + } + +} /* end dasd_3990_erp_alternate_path */ + +/* + * DASD_3990_ERP_ACTION_1 + * + * DESCRIPTION + * Setup ERP to do the ERP action 1 (see Reference manual). + * Repeat the operation on a different channel path. + * If all alternate paths have been tried, the request is posted with a + * permanent error. + * Note: duplex handling is not implemented (yet). + * + * PARAMETER + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_1 (ccw_req_t * erp) +{ + + erp->function = dasd_3990_erp_action_1; + + // cpcmd ("TRACE IO 153 INST INT CCW", NULL, 0); + + dasd_3990_erp_alternate_path (erp); + + return erp; + +} /* end dasd_3990_erp_action_1 */ + +/* + * DASD_3990_ERP_ACTION_4 + * + * DESCRIPTION + * Setup ERP to do the ERP action 4 (see Reference manual). + * Set the current request to PENDING to block the CQR queue for that device + * until the state change interrupt appears. + * Use a timer (20 seconds) to retry the cqr if the interrupt is still missing. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the current ERP + * + * RETURN VALUES + * erp pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_action_4 (ccw_req_t *erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + /* first time set initial retry counter and erp_function */ + /* and retry once without waiting for state change pending */ + /* interrupt (this enables easier enqueing of the cqr) */ + if (erp->function != dasd_3990_erp_action_4) { + erp->retries = 255; /* TBD 255 */ + erp->function = dasd_3990_erp_action_4; + + } else { + + if (sense[25] & 0x1D) { /* state change pending */ + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "waiting for state change pending " + "int"); + + dasd_3990_erp_block_queue (erp, + 60); /* TBD change to 30 */ + + } else { + /* no state change pending - retry */ + printk (KERN_WARNING PRINTK_HEADER + "no state change pending - retry\n"); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } + + return erp; + +} /* end dasd_3990_erp_action_4 */ + +/* + ***************************************************************************** + * 24 byte sense ERP functions (only) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_EQUIP_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Equipment Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_equip_check (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_equip_check; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Equipment Check - environmental data present"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } + + return erp; + +} /* end dasd_3990_erp_equip_check */ + +/* + * DASD_3990_ERP_DATA_CHECK + * + * DESCRIPTION + * Handles 24 byte 'Data Check' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_data_check (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_data_check; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Uncorrectable data check recovered secondary " + "addr of duplex pair"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } + + return erp; + +} /* end dasd_3990_erp_data_check */ + + +/* + * DASD_3990_ERP_INV_FORMAT + * + * DESCRIPTION + * Handles 24 byte 'Invalid Track Format' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_inv_format (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inv_format; + + if (sense[2] & SNS2_ENV_DATA_PRESENT) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Track format error when destaging or " + "staging data"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + } + + return erp; + +} /* end dasd_3990_erp_inv_format */ + +/* + * DASD_3990_ERP_ENV_DATA + * + * DESCRIPTION + * Handles 24 byte 'Environmental-Data Present' error. + * + * PARAMETER + * erp current erp_head + * RETURN VALUES + * erp new erp_head - pointer to new ERP + */ +ccw_req_t * +dasd_3990_erp_env_data (ccw_req_t * erp, + char *sense) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_env_data; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Environmental data present"); + + erp = dasd_3990_erp_action_4 (erp, + sense); + + return erp; + +} /* end dasd_3990_erp_env_data */ + +/* + * DASD_3990_ERP_INSPECT_24 + * + * DESCRIPTION + * Does a detailed inspection of the 24 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp pointer to the (addtitional) ERP + */ +ccw_req_t * +dasd_3990_erp_inspect_24 ( ccw_req_t * erp, + char *sense) +{ + ccw_req_t *erp_filled = NULL; + + /* Check sense for .... */ + /* 'Equipment Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_EQUIPMENT_CHECK)) { + erp_filled = dasd_3990_erp_equip_check (erp, + sense); + } + /* 'Data Check' */ + if ((erp_filled == NULL) && + (sense[0] & SNS0_DATA_CHECK)) { + erp_filled = dasd_3990_erp_data_check (erp, + sense); + } + /* 'Invalid Track Format' */ + if ((erp_filled == NULL) && + (sense[1] & SNS1_INV_TRACK_FORMAT)) { + erp_filled = dasd_3990_erp_inv_format (erp, + sense); + } + /* 'Environmental Data' */ + if ((erp_filled == NULL) && + (sense[2] & SNS2_ENV_DATA_PRESENT)) { + erp_filled = dasd_3990_erp_env_data (erp, + sense); + } + + /* other (unknown/not jet implemented) error - do default ERP */ + if (erp_filled == NULL) { + + printk (KERN_WARNING PRINTK_HEADER + "default ERP taken\n"); + + erp_filled = erp; + } + + return erp_filled; + +} /* END dasd_3990_erp_inspect_24 */ + +/* + ***************************************************************************** + * 32 byte sense ERP functions (only) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_ACTION_1B_32 + * + * DESCRIPTION + * Handles 32 byte 'Action 1B' of Single Program Action Codes. + * A write operation could not be finished because of an unexpected + * condition. + * The already created 'default erp' is used to get the link to + * the erp chain, but it can not be used for this recovery + * action because it contains no DE/LO data space. + * + * PARAMETER + * default_erp already created default erp. + * sense current sense data + * RETURN VALUES + * erp new erp or default_erp in case of error + */ +ccw_req_t * +dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp, + char *sense) +{ + dasd_device_t *device = default_erp->device; + ccw_req_t *cqr; + ccw_req_t *erp; + __u32 cpa; + DE_eckd_data_t *DE_data; + char *LO_data; /* LO_eckd_data_t */ + ccw1_t *ccw; + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Write not finsihed because of unexpected condition"); + + /* determine the original cqr */ + cqr = default_erp; + while (cqr->refers != NULL){ + cqr = cqr->refers; + } + + /* determine the address of the CCW to be restarted */ + cpa = default_erp->refers->dstat->cpa; + + if (cpa == 0) { + cpa = (__u32) cqr->cpaddr; + } + + if (cpa == 0) { + + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to determine address of the CCW " + "to be restarted"); + + atomic_compare_and_swap_debug (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* Build new ERP request including DE/LO */ + erp = dasd_alloc_request ((char *) &cqr->magic, + 2 + 1, /* DE/LO + TIC */ + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + if ( !erp ) { + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "Unable to allocate ERP"); + + atomic_compare_and_swap_debug (&default_erp->status, + CQR_STATUS_FILLED, + CQR_STATUS_FAILED); + + return default_erp; + } + + /* use original DE */ + DE_data = erp->data; + memcpy (DE_data, + cqr->data, + sizeof (DE_eckd_data_t)); + + /* create LO */ + LO_data = erp->data + sizeof (DE_eckd_data_t); + + if ((sense[3] == 0x01) && + (LO_data[1] & 0x01) ){ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "BUG - this should not happen"); + //BUG(); /* check for read count suffixing n.a. */ + } + + LO_data[0] = sense[7]; /* operation */ + LO_data[1] = sense[8]; /* auxiliary */ + LO_data[2] = sense[9]; + LO_data[3] = sense[3]; /* count */ + LO_data[4] = sense[29]; /* seek_addr.cyl */ + LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ + LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ + + memcpy (&(LO_data[8]), &(sense[11]), 8); + + /* create DE ccw */ + ccw = erp->cpaddr; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + ccw->cda = (__u32) __pa (DE_data); + + /* create LO ccw */ + ccw++; + memset (ccw, 0, sizeof (ccw1_t)); + ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; + ccw->flags = CCW_FLAG_CC; + ccw->count = 16; + ccw->cda = (__u32) __pa (LO_data); + + /* TIC to the failed ccw */ + ccw++; + ccw->cmd_code = CCW_CMD_TIC; + ccw->cda = cpa; + + /* fill erp related fields */ + erp->function = dasd_3990_erp_action_1B_32; + erp->refers = default_erp->refers; + erp->device = device; + erp->magic = default_erp->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 2; + + atomic_set(&erp->status, + CQR_STATUS_FILLED); + + /* remove the default erp */ + dasd_free_request (default_erp); + + return erp; + +} /* end dasd_3990_erp_action_1B_32 */ + + +/* + * DASD_3990_ERP_INSPECT_32 + * + * DESCRIPTION + * Does a detailed inspection of the 32 byte sense data + * and sets up a related error recovery action. + * + * PARAMETER + * sense sense data of the actual error + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp_filled pointer to the ERP + * + */ +ccw_req_t * +dasd_3990_erp_inspect_32 ( ccw_req_t *erp, + char *sense ) +{ + dasd_device_t *device = erp->device; + + erp->function = dasd_3990_erp_inspect_32; + + if (sense[25] & DASD_SENSE_BIT_0) { + + /* compound program action codes (byte25 bit 0 == '1') */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP taken\n"); + + } else { + + /* single program action codes (byte25 bit 0 == '0') */ + switch (sense[25]) { + + case 0x1B: /* unexpected condition during write */ + + erp = dasd_3990_erp_action_1B_32 (erp, + sense); +#ifdef ERP_DEBUG + /* TBD */ +// cpcmd ("STOP", NULL, 0); +#endif + break; + + case 0x1D: /* state-change pending */ + DASD_MESSAGE (KERN_WARNING, device, + "%s", + "A State change pending condition exists " + "for the subsystem or device"); + + erp = dasd_3990_erp_action_4 (erp, + sense); +// cpcmd ("STOP", NULL, 0); + break; + + default: /* all others errors */ + printk (KERN_WARNING PRINTK_HEADER + "default ERP taken\n"); + } + } + + return erp; + +} /* end dasd_3990_erp_inspect_32 */ + +/* + ***************************************************************************** + * main ERP control fuctions (24 and 32 byte sense) + ***************************************************************************** + */ + +/* + * DASD_3990_ERP_INSPECT + * + * DESCRIPTION + * Does a detailed inspection for sense data by calling either + * the 24-byte or the 32-byte inspection routine. + * + * PARAMETER + * erp pointer to the currently created default ERP + * RETURN VALUES + * erp_new contens was possibly modified + */ +ccw_req_t * +dasd_3990_erp_inspect (ccw_req_t * erp) +{ + ccw_req_t *erp_new = NULL; + /* sense data are located in the refers record of the */ + /* already set up new ERP ! */ + char *sense = erp->refers->dstat->ii.sense.data; + + /* distinguish between 24 and 32 byte sense data */ + if (sense[27] & DASD_SENSE_BIT_0) { + + /* inspect the 24 byte sense data */ + erp_new = dasd_3990_erp_inspect_24 (erp, + sense); + + } else { + + /* inspect the 32 byte sense data */ + erp_new = dasd_3990_erp_inspect_32 (erp, + sense); + + } /* end distinguish between 24 and 32 byte sense data */ + + return erp_new; + +} /* END dasd_3990_erp_inspect */ + +/* + * DASD_3990_ERP_ADD_ERP + * + * DESCRIPTION + * This funtion adds an additional request block (ERP) to the head of + * the given cqr (or erp). + * This erp is initialized as an default erp (retry TIC) + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_add_erp (ccw_req_t * cqr) +{ + /* allocate additional request block */ + ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0); + if ( !erp ) { + printk( KERN_WARNING PRINTK_HEADER + "unable to allocate ERP request\n" ); + return NULL; + } + + /* initialize request with default TIC to current ERP/CQR */ + erp->cpaddr->cmd_code = CCW_CMD_TIC; + erp->cpaddr->cda = ((__u32) cqr->cpaddr); + erp->function = dasd_3990_erp_add_erp; + erp->refers = cqr; + erp->device = cqr->device; + erp->magic = cqr->magic; + erp->lpm = 0xFF; + erp->expires = 0; + erp->retries = 255; + + atomic_set(&erp->status, + CQR_STATUS_FILLED); + + return erp; +} + +/* + * DASD_3990_ERP_ADDITIONAL_ERP + * + * DESCRIPTION + * An additional ERP is needed to handle the current error. + * Add ERP to the head of the ERP-chain containing the ERP processing + * determined based on the sense data. + * + * PARAMETER + * cqr head of the current ERP-chain (or single cqr if + * first error) + * + * RETURN VALUES + * erp pointer to new ERP-chain head + */ +ccw_req_t * +dasd_3990_erp_additional_erp (ccw_req_t * cqr) +{ + + ccw_req_t *erp = NULL; + + /* add erp and initialize with default TIC */ + erp = dasd_3990_erp_add_erp (cqr); + + /* inspect sense, determine specific ERP if possible */ + erp = dasd_3990_erp_inspect (erp); + + return erp; + +} /* end dasd_3990_erp_additional_erp */ + +/* + * DASD_3990_ERP_ERROR_MATCH + * + * DESCRIPTION + * check if the the device status of the given cqr is the same. + * This means that the failed CCW and the relevant sense data + * must match. + * I don't distinguish between 24 and 32 byte sense becaus in case of + * 24 byte sense byte 25 and 27 is set as well. + * + * PARAMETER + * cqr1 first cqr, which will be compared with the + * cqr2 second cqr. + * + * RETURN VALUES + * match 'boolean' for match found + * returns 1 if match found, otherwise 0. + */ +int +dasd_3990_erp_error_match (ccw_req_t * cqr1, + ccw_req_t * cqr2) +{ + /* check failed CCW */ + if (cqr1->dstat->cpa != + cqr2->dstat->cpa) { + return 0; /* CCW doesn't match */ + + } + /* check sense data; byte 0-2,25,27 */ + if (!((strncmp (cqr1->dstat->ii.sense.data, + cqr2->dstat->ii.sense.data, + 3) == 0) && + (cqr1->dstat->ii.sense.data[27] == + cqr2->dstat->ii.sense.data[27] ) && + (cqr1->dstat->ii.sense.data[25] == + cqr2->dstat->ii.sense.data[25] ) )) { + + return 0; /* sense doesn't match */ + } + return 1; /* match */ + +} /* end dasd_3990_erp_error_match */ + +/* + * DASD_3990_ERP_IN_ERP + * + * DESCRIPTION + * check if the current error already happened before. + * quick exit if current cqr is not an ERP (cqr->refers=NULL) + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the already defined error recovery procedure OR + * NULL if a 'new' error occured. + */ +ccw_req_t * +dasd_3990_erp_in_erp (ccw_req_t * cqr) +{ + ccw_req_t *erp_head = cqr, /* save erp chain head */ + *erp_match = NULL; /* save erp chain head */ + int match = 0; /* 'boolean' for matching error found */ + + if (cqr->refers == NULL) { /* return if not in erp */ + return NULL; + } + /* check the erp/cqr chain for current error */ + do { + match = dasd_3990_erp_error_match (erp_head, + cqr->refers); + erp_match = cqr; /* save possible matching erp */ + cqr = cqr->refers; /* check next erp/cqr in queue */ + } while ((cqr->refers != NULL) && + (match == 0)); + + if (match) { + /* TBD */ + printk(KERN_WARNING PRINTK_HEADER + "dasd_3990_erp_in_erp: return matching erp\n"); + return erp_match; /* retrun address of matching erp */ + } else { + printk(KERN_WARNING PRINTK_HEADER + "dasd_3990_erp_in_erp: return no match\n"); + return NULL; /* return NULL to indicate that no match + was found */ + } + +} /* END dasd_3990_erp_in_erp */ + +/* + * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense) + * + * DESCRIPTION + * No retry is left for the current ERP. Check what has to be done + * with the ERP. + * - do further defined ERP action or + * - wait for interrupt or + * - exit with permanent error + * + * PARAMETER + * erp ERP which is in progress wiht no retry left + * + * RETURN VALUES + * erp modified/additional ERP + */ +ccw_req_t * +dasd_3990_erp_further_erp (ccw_req_t * erp) +{ + dasd_device_t *device = erp->device; + + /* check for 24 byte sense ERP */ + if ((erp->function == dasd_3990_erp_action_1) || + (erp->function == dasd_3990_erp_action_4) ){ + + erp = dasd_3990_erp_action_1 (erp); + + } else { + /* no retry left and no additional special handling necessary */ + DASD_MESSAGE (KERN_WARNING, device, + "no retries left for erp %p - " + "set status to FAILED", + erp); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + + return erp; + +} /* end dasd_3990_erp_further_erp */ + +/* + * DASD_3990_ERP_HANDLE_MATCH_ERP + * + * DESCRIPTION + * An error occured again and an ERP has been detected which is already + * used to handle this error (e.g. retries). + * All prior ERP's are set to status DONE and the retry counter is + * decremented. + * If retry counter is already 0, it has to checked if further action + * is needed (besides retry) or if the ERP has failed. + * + * PARAMETER + * erp_head first ERP in ERP-chain + * erp_match ERP that handles the actual error. + * + * RETURN VALUES + * none + */ +void +dasd_3990_erp_handle_match_erp (ccw_req_t * erp_head, + ccw_req_t * erp_match) +{ + + dasd_device_t *device = erp_head->device; + ccw_req_t *erp_done = erp_head; + + /* loop over successful ERPs and remove them from chanq */ + while ((erp_done != erp_match) && + (erp_done != NULL)) { + +#ifdef ERP_DEBUG + printk (KERN_WARNING PRINTK_HEADER + "successful ERP - dequeue and free request %p\n", + (void *) erp_done); +#endif + atomic_compare_and_swap_debug (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + /* remove the request from the device queue */ + dasd_chanq_deq (&device->queue, + erp_done); + + /* free the finished erp request */ + dasd_free_request (erp_done); + + erp_done = erp_done->refers; + } + + if (erp_done == NULL) /* erp_done should never be NULL! */ + panic (PRINTK_HEADER "Programming error in ERP! The original " + "request was lost\n"); + +#ifdef ERP_DEBUG + /* handle matching ERP */ + printk (KERN_WARNING PRINTK_HEADER + "handle matching erp %p\n", + (void *) erp_done); +#endif + + if (erp_done->retries > 0) { + + /* check for special retries */ + if (erp_done->function == dasd_3990_erp_action_4) { + char *sense = erp_done->dstat->ii.sense.data; + erp_done = dasd_3990_erp_action_4 (erp_done, + sense); + + } else { + /* simple retry */ + printk (KERN_WARNING PRINTK_HEADER + "%i retries left for erp %p\n", + erp_done->retries, + (void *) erp_done); + + /* handle the request again... */ + atomic_compare_and_swap_debug (&erp_done->status, + CQR_STATUS_ERROR, + CQR_STATUS_QUEUED); + } + } else { + /* no retry left - check for further necessary action */ + /* if no further actions, handle rest as permanent error */ + erp_done = dasd_3990_erp_further_erp (erp_done); + } + + erp_head = erp_done; + +} /* end dasd_3990_erp_handle_match_erp */ + +/* + * DASD_3990_ERP_ACTION + * + * DESCRIPTION + * controll routine for 3990 erp actions. + * Has to be called with the queue lock (namely the s390_irq_lock) acquired. + * + * PARAMETER + * cqr failed cqr (either original cqr or already an erp) + * + * RETURN VALUES + * erp erp-pointer to the head of the ERP action chain. + * This means: + * - either a ptr to an additional ERP cqr or + * - the original given cqr (which's status might be modified) + */ +ccw_req_t * +dasd_3990_erp_action (ccw_req_t *cqr) +{ + ccw_req_t *erp = NULL; + dasd_device_t *device = cqr->device; + +#ifdef ERP_DEBUG + + printk (KERN_WARNING PRINTK_HEADER + "entering 3990 ERP for " + "0x%04X on sch %d = /dev/%s \n", + device->devinfo.devno, + device->devinfo.irq, + device->name); + + /* print current erp_chain */ + printk(KERN_WARNING PRINTK_HEADER + "ERP chain at BEGINNING of ERP-ACTION\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif + + /* double-check if current erp/cqr was successfull */ + if ((cqr->dstat->cstat == 0x00) && + (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called for successful request %p" + " - NO ERP necessary", + cqr); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + + return cqr; + } + /* check if sense data are available */ + if (!cqr->dstat->ii.sense.data) { + DASD_MESSAGE (KERN_WARNING, device, + "ERP called witout sense data avail ..." + "request %p - NO ERP possible", + cqr); + + atomic_compare_and_swap_debug (&erp->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + + return cqr; + + } + + /* check if error happened before */ + erp = dasd_3990_erp_in_erp (cqr); + + if (erp == NULL) { + /* no matching erp found - set up erp */ + erp = dasd_3990_erp_additional_erp (cqr); + } else { + /* matching erp found - set all leading erp's to DONE */ + dasd_3990_erp_handle_match_erp (cqr, erp); + erp = cqr; + } + +#ifdef ERP_DEBUG + /* print current erp_chain */ + printk(KERN_WARNING PRINTK_HEADER + "ERP chain at END of ERP-ACTION\n"); + { + ccw_req_t *temp_erp = NULL; + for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){ + printk(KERN_WARNING PRINTK_HEADER + " erp %p refers to %p \n", + temp_erp, + temp_erp->refers); + } + } +#endif - } /* end distinguish between 24 and 32 byte sense data */ + return erp; -} /* END dasd_3990_erp_examine */ +} /* end dasd_3990_erp_action */ /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/s390/block/dasd_3990_erp.h b/drivers/s390/block/dasd_3990_erp.h new file mode 100644 index 000000000000..c7199f45ecf7 --- /dev/null +++ b/drivers/s390/block/dasd_3990_erp.h @@ -0,0 +1,21 @@ +/* + * File...........: linux/drivers/s390/block/dasd_3990_erp.h + * Author(s)......: Horst Hummel + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts Jul 2000) + */ + +#ifndef DASD_3990_ERP_H +#define DASD_3990_ERP_H + + +dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *); + +ccw_req_t *dasd_3990_erp_action (ccw_req_t *); +ccw_req_t *dasd_2105_erp_action (ccw_req_t *); + +void dasd_3990_erp_restart_queue (unsigned long); + +#endif /* DASD_3990_ERP_H */ diff --git a/drivers/s390/block/dasd_9343_erp.h b/drivers/s390/block/dasd_9343_erp.h new file mode 100644 index 000000000000..b3cf273cf85a --- /dev/null +++ b/drivers/s390/block/dasd_9343_erp.h @@ -0,0 +1,18 @@ +/* + * File...........: linux/drivers/s390/block/dasd_9343_erp.h + * Author(s)......: Horst Hummel + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_9343_ERP_H +#define DASD_9343_ERP_H + + +dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *); + +ccw_req_t *dasd_9343_erp_action (ccw_req_t *); + +#endif /* DASD_9343_ERP_H */ diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index afb82c4b6f3b..daeca010893a 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -268,13 +268,14 @@ dasd_diag_check_characteristics (struct dasd_device_t *device) "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL); if ( device->private == NULL ) { - device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL); - if ( device->private == NULL ) { - printk ( KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk ( KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_diag_private_t *)device->private; rdc_data = (void *)&(private->rdc_data); @@ -318,7 +319,7 @@ dasd_diag_check_characteristics (struct dasd_device_t *device) if (rc > 4) { continue; } - cqr = ccw_alloc_request (dasd_diag_discipline.name, 2,0); + cqr = dasd_alloc_request (dasd_diag_discipline.name, 2,0); if ( cqr == NULL ) { printk ( KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -501,7 +502,7 @@ dasd_diag_build_cp_from_req (dasd_device_t *device, struct request *req) } } else { PRINT_WARN ("Cannot fulfill request smaller than block\n"); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 1d6adbe01b63..f36fbd5d8c40 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -12,6 +12,7 @@ * 08/07/00 added some bits to define_extent for ESS support * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF) * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages) + * 01/23/00 fixed kmalloc in dump_sense to be GFP_ATOMIC */ #include @@ -49,22 +50,6 @@ #define ECKD_F7(i) (i->factor7) #define ECKD_F8(i) (i->factor8) -#define DASD_ECKD_CCW_WRITE 0x05 -#define DASD_ECKD_CCW_READ 0x06 -#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 -#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a -#define DASD_ECKD_CCW_READ_COUNT 0x12 -#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 -#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 -#define DASD_ECKD_CCW_WRITE_CKD 0x1d -#define DASD_ECKD_CCW_READ_CKD 0x1e -#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 -#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 -#define DASD_ECKD_CCW_WRITE_MT 0x85 -#define DASD_ECKD_CCW_READ_MT 0x86 -#define DASD_ECKD_CCW_READ_CKD_MT 0x9e -#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d - dasd_discipline_t dasd_eckd_discipline; typedef struct @@ -374,9 +359,9 @@ static int dasd_eckd_check_characteristics (struct dasd_device_t *device) { int rc = -ENODEV; - void *conf_data; + void *conf_data=NULL; void *rdc_data; - int conf_len; + int conf_len=0; dasd_eckd_private_t *private; if ( device == NULL ) { @@ -384,13 +369,14 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device) "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL); if ( device->private == NULL ) { - device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL); - if ( device->private == NULL ) { - printk ( KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk ( KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_eckd_private_t *)device->private; rdc_data = (void *)&(private->rdc_data); @@ -450,7 +436,7 @@ dasd_eckd_init_analysis (struct dasd_device_t *device) LO_eckd_data_t *LO_data; eckd_count_t *count_data = &(((dasd_eckd_private_t *)(device->private))->count_area); - cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); + cqr = dasd_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t)); if ( cqr == NULL ) { printk ( KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); @@ -624,9 +610,9 @@ dasd_eckd_format_device (dasd_device_t *device, format_data_t *fdata) datasize += sizeof(eckd_home_t); } } - fcp = ccw_alloc_request (dasd_eckd_discipline.name, - wrccws + 2, - datasize+rpt*sizeof(eckd_count_t)); + fcp = dasd_alloc_request (dasd_eckd_discipline.name, + wrccws + 2, + datasize+rpt*sizeof(eckd_count_t)); if ( fcp != NULL ) { fcp->device = device; fcp->retries = 2; /* set retry counter to enable ERP */ @@ -751,21 +737,26 @@ dasd_eckd_examine_error (ccw_req_t *cqr, devstat_t * stat) } } -static dasd_erp_action_fn_t -dasd_eckd_erp_action ( ccw_req_t * cqr ) +static dasd_erp_action_fn_t +dasd_eckd_erp_action (ccw_req_t * cqr) { - return default_erp_action; + dasd_device_t *device = (dasd_device_t *) cqr->device; + + switch (device->devinfo.sid_data.cu_type) { + case 0x3990: + case 0x2105: + return dasd_3990_erp_action; + case 0x9343: + /* return dasd_9343_erp_action; */ + default: + return default_erp_action; + } } static dasd_erp_postaction_fn_t dasd_eckd_erp_postaction (ccw_req_t * cqr) { - if ( cqr -> function == default_erp_action) - return default_erp_postaction; - printk ( KERN_WARNING PRINTK_HEADER - "unknown ERP action %p\n", - cqr -> function); - return NULL; + return default_erp_postaction; } static ccw_req_t * @@ -844,7 +835,7 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req) } if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } ccw->flags = CCW_FLAG_CC; @@ -862,7 +853,7 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req) static char * dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req) { - char *page = (char *)get_free_page(GFP_KERNEL); + char *page = (char *)get_free_page(GFP_ATOMIC); devstat_t *stat = &device->dev_status; char *sense = stat->ii.sense.data; int len,sl,sct; diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 36c505a185ca..ddf9c97a11ab 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -1,6 +1,25 @@ #ifndef DASD_ECKD_H #define DASD_ECKD_H +#include "dasd_3990_erp.h" +#include "dasd_9343_erp.h" + +#define DASD_ECKD_CCW_WRITE 0x05 +#define DASD_ECKD_CCW_READ 0x06 +#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 +#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a +#define DASD_ECKD_CCW_READ_COUNT 0x12 +#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 +#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 +#define DASD_ECKD_CCW_WRITE_CKD 0x1d +#define DASD_ECKD_CCW_READ_CKD 0x1e +#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 +#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 +#define DASD_ECKD_CCW_WRITE_MT 0x85 +#define DASD_ECKD_CCW_READ_MT 0x86 +#define DASD_ECKD_CCW_READ_CKD_MT 0x9e +#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d + typedef struct eckd_count_t { __u16 cyl; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index eeec40c2e2fd..43f6ddcdaf88 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -117,13 +117,14 @@ dasd_fba_check_characteristics (struct dasd_device_t *device) "Null device pointer passed to characteristics checker\n"); return -ENODEV; } + if ( device->private != NULL ) { + kfree(device->private); + } + device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL); if ( device->private == NULL ) { - device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL); - if ( device->private == NULL ) { - printk ( KERN_WARNING PRINTK_HEADER - "memory allocation failed for private data\n"); - return -ENOMEM; - } + printk ( KERN_WARNING PRINTK_HEADER + "memory allocation failed for private data\n"); + return -ENOMEM; } private = (dasd_fba_private_t *)device->private; rdc_data = (void *)&(private->rdc_data); @@ -306,7 +307,7 @@ dasd_fba_build_cp_from_req (dasd_device_t *device, struct request *req) ccw->flags = CCW_FLAG_DC; } else { PRINT_WARN ("Cannot chain chunks smaller than one block\n"); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } ccw->cmd_code = rw_cmd; @@ -318,7 +319,7 @@ dasd_fba_build_cp_from_req (dasd_device_t *device, struct request *req) ccw->flags = CCW_FLAG_CC; if (size != byt_per_blk) { PRINT_WARN ("Cannot fulfill request smaller than block\n"); - ccw_free_request (rw_cp); + dasd_free_request (rw_cp); return NULL; } } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index db32ec9c6aac..ea121053e23f 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -413,7 +413,7 @@ long xpram_page_in (unsigned long page_addr, unsigned long xpage_index) " .long 0xb22e0012 \n" /* pgin r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ - " srl %0,28(0) \n" /* cc into least significant bits */ + " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lhi %0,2 \n" /* return unused condition code 2 */ @@ -456,7 +456,7 @@ long xpram_page_out (unsigned long page_addr, unsigned long xpage_index) " .long 0xb22f0012 \n" /* pgout r1,r2 */ /* copy page from expanded memory */ "0: ipm %0 \n" /* save status (cc & program mask */ - " srl %0,28(0) \n" /* cc into least significant bits */ + " srl %0,28 \n" /* cc into least significant bits */ "1: \n" /* we are done */ ".section .fixup,\"ax\"\n" /* start of fix up section */ "2: lhi %0,2 \n" /* return unused condition code 2 */ diff --git a/drivers/s390/ccwcache.c b/drivers/s390/ccwcache.c index a4713da55119..6adf48882cf6 100644 --- a/drivers/s390/ccwcache.c +++ b/drivers/s390/ccwcache.c @@ -8,6 +8,7 @@ * 07/10/00 moved ccwcache.h from linux/ to asm/ */ +#include #include #include #include @@ -15,19 +16,14 @@ #include #include -#ifdef PRINTK_HEADER -#undef PRINTK_HEADER -#endif +#undef PRINTK_HEADER #define PRINTK_HEADER "ccwcache" -#ifdef MODULE MODULE_AUTHOR ("Holger Smolinski "); MODULE_DESCRIPTION ("Linux on S/390 CCW cache," "Copyright 2000 IBM Corporation"); -EXPORT_NO_SYMBOLS; EXPORT_SYMBOL(ccw_alloc_request); EXPORT_SYMBOL(ccw_free_request); -#endif /* MODULE */ /* pointer to list of allocated requests */ @@ -314,8 +310,7 @@ ccwcache_init (void) } else { printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area ); } - debug_register_view(debug_area,&debug_hex_view); - debug_register_view(debug_area,&debug_ebcdic_view); + debug_register_view(debug_area,&debug_hex_ascii_view); debug_text_event ( debug_area, 0, "INIT"); /* First allocate the kmem caches */ @@ -389,3 +384,4 @@ cleanup_module ( void ) ccwcache_cleanup(); } #endif /* MODULE */ + diff --git a/drivers/s390/char/hwc.h b/drivers/s390/char/hwc.h index ed46a4a85a30..4e5893696538 100644 --- a/drivers/s390/char/hwc.h +++ b/drivers/s390/char/hwc.h @@ -39,6 +39,8 @@ #define HWC_BUSY 2 #define HWC_NOT_OPERATIONAL 3 +#define hwc_cmdw_t u32; + #define HWC_CMDW_READDATA 0x00770005 #define HWC_CMDW_WRITEDATA 0x00760005 @@ -207,10 +209,26 @@ static init_hwcb_t init_hwcb_template = 0x0000, 0x0000, sizeof (_hwcb_mask_t), - ET_OpCmd_Mask | ET_PMsgCmd_Mask, - ET_Msg_Mask + ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask, + ET_Msg_Mask | ET_PMsgCmd_Mask }; +typedef struct { + _EBUF_HEADER + u8 validity_hwc_active_facility_mask:1; + u8 validity_hwc_receive_mask:1; + u8 validity_hwc_send_mask:1; + u8 validity_read_data_function_mask:1; + u16 _zeros:12; + u16 mask_length; + u64 hwc_active_facility_mask; + _hwcb_mask_t hwc_receive_mask; + _hwcb_mask_t hwc_send_mask; + u32 read_data_function_mask; +} __attribute__ ((packed)) + +statechangebuf_t; + #define _GDS_VECTOR_HEADER u16 length; \ u16 gds_id; diff --git a/drivers/s390/char/hwc_rw.c b/drivers/s390/char/hwc_rw.c index 07a0ea50a3b3..4655b01faf13 100644 --- a/drivers/s390/char/hwc_rw.c +++ b/drivers/s390/char/hwc_rw.c @@ -29,9 +29,13 @@ #include #ifndef MIN -#define MIN(a,b) ((amsgbuf.type = ET_PMsgCmd; - return 0; } @@ -375,7 +379,7 @@ sane_write_hwcb (void) #ifdef DUMP_HWC_WRITE_LIST_ERROR __asm__ ("LHI 1,0xe30\n\t" - "LRA 2,0(0,%0) \n\t" + "LRA 2,0(%0) \n\t" "J .+0 \n\t" : : "a" (bad_addr) @@ -437,8 +441,8 @@ reuse_write_hwcb (void) if (hwc_data.hwcb_count < 2) #ifdef DUMP_HWC_WRITE_LIST_ERROR __asm__ ("LHI 1,0xe31\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "LRA 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0 \n\t" : : "a" (BUF_HWCB), "a" (OUT_HWCB) @@ -658,32 +662,65 @@ add_mto ( return count; } +static int write_event_data_1 (void); + +static void +do_poll_hwc (unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave (&hwc_data.lock, flags); + + write_event_data_1 (); + + spin_unlock_irqrestore (&hwc_data.lock, flags); +} + +void +start_poll_hwc (void) +{ + init_timer (&hwc_data.poll_timer); + hwc_data.poll_timer.function = do_poll_hwc; + hwc_data.poll_timer.data = (unsigned long) NULL; + hwc_data.poll_timer.expires = jiffies + 2 * HZ; + add_timer (&hwc_data.poll_timer); + hwc_data.flags |= HWC_PTIMER_RUNS; +} + static int write_event_data_1 (void) { unsigned short int condition_code; int retval; + write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB; - if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio)) - return -EPERM; + if ((!hwc_data.write_prio) && + (!hwc_data.write_nonprio) && + hwc_data.read_statechange) + return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; retval = sane_write_hwcb (); if (retval < 0) - return retval; + return -EIO; if (!OUT_HWCB_MTO) return -ENODATA; + if (!hwc_data.write_nonprio && hwc_data.write_prio) + hwcb->msgbuf.type = ET_PMsgCmd; + else + hwcb->msgbuf.type = ET_Msg; + condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB); #ifdef DUMP_HWC_WRITE_ERROR if (condition_code != HWC_COMMAND_INITIATED) __asm__ ("LHI 1,0xe20\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "L 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0 \n\t" : : "a" (&condition_code), "a" (OUT_HWCB) @@ -702,6 +739,8 @@ write_event_data_1 (void) case HWC_BUSY: retval = -EBUSY; break; + case HWC_NOT_OPERATIONAL: + start_poll_hwc (); default: retval = -EIO; } @@ -724,7 +763,7 @@ static int write_event_data_2 (void) { write_hwcb_t *hwcb; - int retval; + int retval = 0; #ifdef DUMP_HWC_WRITE_ERROR unsigned char *param; @@ -734,7 +773,7 @@ write_event_data_2 (void) internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER - "write_event_mask_2 : " + "write_event_data_2 : " "HWCB address does not fit " "(expected: 0x%x, got: 0x%x).\n", hwc_data.current_hwcb, @@ -748,10 +787,10 @@ write_event_data_2 (void) #ifdef DUMP_HWC_WRITE_LIST_ERROR if (((unsigned char *) hwcb) != hwc_data.current_hwcb) { __asm__ ("LHI 1,0xe22\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" + "LRA 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" + "LRA 4,0(%2)\n\t" + "LRA 5,0(%3)\n\t" "J .+0 \n\t" : : "a" (OUT_HWCB), @@ -765,11 +804,11 @@ write_event_data_2 (void) #ifdef DUMP_HWC_WRITE_ERROR if (hwcb->response_code != 0x0020) { __asm__ ("LHI 1,0xe21\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LH 5,0(0,%3)\n\t" - "SRL 5,8(0)\n\t" + "LRA 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" + "LRA 4,0(%2)\n\t" + "LH 5,0(%3)\n\t" + "SRL 5,8\n\t" "J .+0 \n\t" : : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb), @@ -779,11 +818,22 @@ write_event_data_2 (void) } #endif - if (hwcb->response_code == 0x0020) { + switch (hwcb->response_code) { + case 0x0020: retval = OUT_HWCB_CHAR; release_write_hwcb (); - } else { + break; + case 0x0040: + case 0x0340: + case 0x40F0: + if (!hwc_data.read_statechange) { + hwcb->response_code = 0; + start_poll_hwc (); + } + retval = -EIO; + break; + default: internal_print ( DELAYED_WRITE, HWC_RW_PRINT_HEADER @@ -796,6 +846,13 @@ write_event_data_2 (void) retval = -EIO; } + if (retval == -EIO) { + + hwcb->control_mask[0] = 0; + hwcb->control_mask[1] = 0; + hwcb->control_mask[2] = 0; + hwcb->response_code = 0; + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -819,10 +876,10 @@ do_put_line ( #ifdef DUMP_HWC_WRITE_LIST_ERROR if (add_mto (message, count) != count) __asm__ ("LHI 1,0xe32\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" + "LRA 2,0(%0)\n\t" + "L 3,0(%1)\n\t" + "LRA 4,0(%2)\n\t" + "LRA 5,0(%3)\n\t" "J .+0 \n\t" : : "a" (message), "a" (&hwc_data.kmem_pages), @@ -840,9 +897,9 @@ put_line ( unsigned short count) { - if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) { + if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) { del_timer (&hwc_data.write_timer); - hwc_data.flags &= ~HWC_TIMER_RUNS; + hwc_data.flags &= ~HWC_WTIMER_RUNS; } hwc_data.obuf_start += count; @@ -888,13 +945,12 @@ do_hwc_write ( int from_user, unsigned char *msg, unsigned int count, - unsigned char code, unsigned char write_time) { unsigned int i_msg = 0; unsigned short int spaces = 0; unsigned int processed_characters = 0; - unsigned char ch, orig_ch; + unsigned char ch; unsigned short int obuf_count; unsigned short int obuf_cursor; unsigned short int obuf_columns; @@ -911,15 +967,10 @@ do_hwc_write ( } for (i_msg = 0; i_msg < count; i_msg++) { - if (from_user) - get_user (orig_ch, msg + i_msg); + get_user (ch, msg + i_msg); else - orig_ch = msg[i_msg]; - if (code == CODE_EBCDIC) - ch = (MACHINE_IS_VM ? _ebcasc[orig_ch] : _ebcasc_500[orig_ch]); - else - ch = orig_ch; + ch = msg[i_msg]; processed_characters++; @@ -957,7 +1008,7 @@ do_hwc_write ( if (obuf_cursor < obuf_columns) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor] - = 0x20; + = HWC_ASCEBC (' '); obuf_cursor++; } else break; @@ -975,7 +1026,7 @@ do_hwc_write ( while (spaces) { hwc_data.obuf[hwc_data.obuf_start + obuf_cursor - spaces] - = 0x20; + = HWC_ASCEBC (' '); spaces--; } @@ -1005,11 +1056,7 @@ do_hwc_write ( if (isprint (ch)) hwc_data.obuf[hwc_data.obuf_start + obuf_cursor++] - = (code == CODE_ASCII) ? - (MACHINE_IS_VM ? - _ascebc[orig_ch] : - _ascebc_500[orig_ch]) : - orig_ch; + = HWC_ASCEBC (ch); } if (obuf_cursor > obuf_count) obuf_count = obuf_cursor; @@ -1028,11 +1075,10 @@ do_hwc_write ( if (hwc_data.ioctls.final_nl > 0) { - if (hwc_data.flags & HWC_TIMER_RUNS) { + if (hwc_data.flags & HWC_WTIMER_RUNS) { - hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl * HZ / 10; + mod_timer (&hwc_data.write_timer, + jiffies + hwc_data.ioctls.final_nl * HZ / 10); } else { init_timer (&hwc_data.write_timer); @@ -1044,7 +1090,7 @@ do_hwc_write ( jiffies + hwc_data.ioctls.final_nl * HZ / 10; add_timer (&hwc_data.write_timer); - hwc_data.flags |= HWC_TIMER_RUNS; + hwc_data.flags |= HWC_WTIMER_RUNS; } } else; @@ -1072,8 +1118,7 @@ hwc_write (int from_user, const unsigned char *msg, unsigned int count) spin_lock_irqsave (&hwc_data.lock, flags); retval = do_hwc_write (from_user, (unsigned char *) msg, - count, hwc_data.ioctls.code, - IMMEDIATE_WRITE); + count, IMMEDIATE_WRITE); spin_unlock_irqrestore (&hwc_data.lock, flags); @@ -1329,15 +1374,11 @@ get_input (void *start, void *end) if (hwc_data.ioctls.delim) count = seperate_cases (start, count); + HWC_EBCASC_STR (start, count); + if (hwc_data.ioctls.echo) - do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE); + do_hwc_write (0, start, count, IMMEDIATE_WRITE); - if (hwc_data.ioctls.code == CODE_ASCII) { - if (MACHINE_IS_VM) - EBCASC (start, count); - else - EBCASC_500 (start, count); - } if (hwc_data.calls != NULL) if (hwc_data.calls->move_input != NULL) (hwc_data.calls->move_input) (start, count); @@ -1440,7 +1481,7 @@ eval_mdsmu (gds_vector_t * start, void *end) return retval; } -inline static int +static int eval_evbuf (gds_vector_t * start, void *end) { gds_vector_t *vec; @@ -1458,6 +1499,128 @@ eval_evbuf (gds_vector_t * start, void *end) return retval; } +static inline int +eval_hwc_receive_mask (_hwcb_mask_t mask) +{ + + hwc_data.write_nonprio + = ((mask & ET_Msg_Mask) == ET_Msg_Mask); + + hwc_data.write_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + + if (hwc_data.write_prio || hwc_data.write_nonprio) { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can write messages\n"); + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not write messages\n"); + return -1; + } +} + +static inline int +eval_hwc_send_mask (_hwcb_mask_t mask) +{ + + hwc_data.read_statechange + = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask); + if (hwc_data.read_statechange) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read state change notifications\n"); + else + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read state change notifications\n"); + + hwc_data.read_nonprio + = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask); + if (hwc_data.read_nonprio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read commands\n"); + + hwc_data.read_prio + = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask); + if (hwc_data.read_prio) + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can read priority commands\n"); + + if (hwc_data.read_prio || hwc_data.read_nonprio) { + return 0; + } else { + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "can not read commands from operator\n"); + return -1; + } +} + +static int +eval_statechangebuf (statechangebuf_t * scbuf) +{ + int retval = 0; + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "HWC state change detected\n"); + + if (scbuf->validity_hwc_active_facility_mask) { + + } + if (scbuf->validity_hwc_receive_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe50\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_receive_mask + (scbuf->hwc_receive_mask); + } + } + if (scbuf->validity_hwc_send_mask) { + + if (scbuf->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe51\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (scbuf) + : "1", "2"); +#endif + } else { + + retval += eval_hwc_send_mask + (scbuf->hwc_send_mask); + } + } + if (scbuf->validity_read_data_function_mask) { + + } + return retval; +} + static int process_evbufs (void *start, void *end) { @@ -1490,17 +1653,17 @@ process_evbufs (void *start, void *end) retval += eval_evbuf (evbuf_data, evbuf_end); break; case ET_StateChange: - - retval = -ENOSYS; + retval += eval_statechangebuf + ((statechangebuf_t *) evbuf); break; default: - printk ( - KERN_WARNING - HWC_RW_PRINT_HEADER - "unconditional read: " - "unknown event buffer found, " - "type 0x%x", - evbuf->type); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " + "unknown event buffer found, " + "type 0x%x", + evbuf->type); retval = -ENOSYS; } evbuf = (evbuf_t *) evbuf_end; @@ -1515,11 +1678,14 @@ unconditional_read_1 (void) read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; int retval; +#if 0 + if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio)) return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; +#endif memset (hwcb, 0x00, PAGE_SIZE); memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t)); @@ -1529,8 +1695,8 @@ unconditional_read_1 (void) #ifdef DUMP_HWC_READ_ERROR if (condition_code == HWC_NOT_OPERATIONAL) __asm__ ("LHI 1,0xe40\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "L 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0 \n\t" : : "a" (&condition_code), "a" (hwc_data.page) @@ -1564,8 +1730,8 @@ unconditional_read_2 (void) (hwcb->response_code != 0x60F0) && (hwcb->response_code != 0x62F0)) __asm__ ("LHI 1,0xe41\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" + "LRA 2,0(%0)\n\t" + "L 3,0(%1)\n\t" "J .+0\n\t" : : "a" (hwc_data.page), "a" (&(hwcb->response_code)) @@ -1625,26 +1791,21 @@ unconditional_read_2 (void) internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: invalid function code - this " - "must not occur in a correct driver, please contact " - "author\n"); + "unconditional read: invalid function code\n"); return -EIO; case 0x70F0: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: invalid selection mask - this " - "must not occur in a correct driver, please contact " - "author\n"); + "unconditional read: invalid selection mask\n"); return -EIO; case 0x0040: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER - "unconditional read: HWC equipment check - don't " - "know how to handle this case\n"); + "unconditional read: HWC equipment check\n"); return -EIO; default: @@ -1671,8 +1832,8 @@ write_event_mask_1 (void) if (condition_code == HWC_NOT_OPERATIONAL) __asm__ ("LHI 1,0xe10\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" + "L 2,0(%0)\n\t" + "LRA 3,0(%1)\n\t" "J .+0\n\t" : : "a" (&condition_code), "a" (hwc_data.page) @@ -1701,38 +1862,34 @@ write_event_mask_2 (void) init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page; int retval = 0; - if (hwcb->hwc_receive_mask & ET_Msg_Mask) - hwc_data.write_nonprio = 1; - - if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask) - hwc_data.write_prio = 1; - - if (hwcb->hwc_send_mask & ET_OpCmd_Mask) { - internal_print (DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "capable of receipt of commands\n"); - hwc_data.read_nonprio = 1; - } - if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) { - internal_print (DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "capable of receipt of priority commands\n"); - hwc_data.read_nonprio = 1; - } - if ((hwcb->response_code != 0x0020) || - (!hwc_data.write_nonprio) || - ((!hwc_data.read_nonprio) && (!hwc_data.read_prio))) + if (hwcb->response_code != 0x0020) { #ifdef DUMP_HWC_INIT_ERROR __asm__ ("LHI 1,0xe11\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" + "LRA 2,0(%0)\n\t" + "L 3,0(%1)\n\t" "J .+0\n\t" : : "a" (hwcb), "a" (&(hwcb->response_code)) : "1", "2", "3"); #else - retval = -EIO; + retval = -1; +#endif + } else { + if (hwcb->mask_length != 4) { +#ifdef DUMP_HWC_INIT_ERROR + __asm__ ("LHI 1,0xe52\n\t" + "LRA 2,0(%0)\n\t" + "J .+0 \n\t" + : + : "a" (hwcb) + : "1", "2"); #endif + } else { + retval += eval_hwc_receive_mask + (hwcb->hwc_receive_mask); + retval += eval_hwc_send_mask (hwcb->hwc_send_mask); + } + } hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -1764,18 +1921,6 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct) } else tmp.columns = ioctls->columns; - switch (ioctls->code) { - case CODE_EBCDIC: - case CODE_ASCII: - tmp.code = ioctls->code; - break; - default: - if (correct) - tmp.code = CODE_ASCII; - else - retval = -EINVAL; - } - tmp.final_nl = ioctls->final_nl; if (ioctls->max_hwcb < 2) { @@ -1915,7 +2060,7 @@ hwc_init (unsigned long *kmem_start) HWC_RW_PRINT_HEADER "use %i bytes for buffering.\n", hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); - for (i = 0; i < 500; i++) { + for (i = 0; i < 2000; i++) { hwcb = (init_hwcb_t *) BUF_HWCB; internal_print ( DELAYED_WRITE, @@ -1975,6 +2120,10 @@ do_hwc_interrupt (struct pt_regs *regs, __u16 code) } else { spin_lock (&hwc_data.lock); + if (hwc_data.flags & HWC_PTIMER_RUNS) { + del_timer (&hwc_data.poll_timer); + hwc_data.flags &= ~HWC_PTIMER_RUNS; + } if (!hwc_data.current_servc) { unconditional_read_1 (); @@ -2064,12 +2213,6 @@ hwc_ioctl (unsigned int cmd, unsigned long arg) goto fault; break; - case TIOCHWCSCODE: - if (get_user (tmp.code, (ioctl_code_t *) arg)) - goto fault; - - break; - case TIOCHWCSNL: if (get_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; @@ -2128,12 +2271,6 @@ hwc_ioctl (unsigned int cmd, unsigned long arg) goto fault; break; - case TIOCHWCGCODE: - if (put_user (tmp.code, (ioctl_code_t *) arg)) - goto fault; - - break; - case TIOCHWCGNL: if (put_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; diff --git a/drivers/s390/char/hwc_rw.h b/drivers/s390/char/hwc_rw.h index 6ef3b23ebeaa..912024158436 100644 --- a/drivers/s390/char/hwc_rw.h +++ b/drivers/s390/char/hwc_rw.h @@ -26,7 +26,6 @@ typedef struct { typedef unsigned short int ioctl_htab_t; typedef unsigned char ioctl_echo_t; typedef unsigned short int ioctl_cols_t; -typedef unsigned char ioctl_code_t; typedef signed char ioctl_nl_t; typedef unsigned short int ioctl_obuf_t; typedef unsigned char ioctl_case_t; @@ -37,7 +36,6 @@ typedef struct { ioctl_htab_t width_htab; ioctl_echo_t echo; ioctl_cols_t columns; - ioctl_code_t code; ioctl_nl_t final_nl; ioctl_obuf_t max_hwcb; ioctl_obuf_t kmem_hwcb; @@ -58,8 +56,6 @@ static hwc_ioctls_t _hwc_ioctls; #define TIOCHWCSCOLS _IOW(HWC_IOCTL_LETTER, 2, _hwc_ioctls.columns) -#define TIOCHWCSCODE _IOW(HWC_IOCTL_LETTER, 3, _hwc_ioctls.code) - #define TIOCHWCSNL _IOW(HWC_IOCTL_LETTER, 4, _hwc_ioctls.final_nl) #define TIOCHWCSOBUF _IOW(HWC_IOCTL_LETTER, 5, _hwc_ioctls.max_hwcb) @@ -78,8 +74,6 @@ static hwc_ioctls_t _hwc_ioctls; #define TIOCHWCGCOLS _IOR(HWC_IOCTL_LETTER, 12, _hwc_ioctls.columns) -#define TIOCHWCGCODE _IOR(HWC_IOCTL_LETTER, 13, _hwc_ioctls.code) - #define TIOCHWCGNL _IOR(HWC_IOCTL_LETTER, 14, _hwc_ioctls.final_nl) #define TIOCHWCGOBUF _IOR(HWC_IOCTL_LETTER, 15, _hwc_ioctls.max_hwcb) @@ -100,9 +94,6 @@ static hwc_ioctls_t _hwc_ioctls; #define TIOCHWCGMEASS _IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls) -#define CODE_ASCII 0x0 -#define CODE_EBCDIC 0x1 - #ifndef __HWC_RW_C__ extern int hwc_init (unsigned long *); diff --git a/drivers/s390/idals.c b/drivers/s390/idals.c index cd81d8ffe866..235f003cc524 100644 --- a/drivers/s390/idals.c +++ b/drivers/s390/idals.c @@ -9,71 +9,36 @@ */ #include + #include #include -#include - -#ifdef PRINTK_HEADER -#undef PRINTK_HEADER -#endif -#define PRINTK_HEADER "idals:" - -/* a name template for the cache-names */ -static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */ -/* the cache's names */ -static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1]; -/* the caches itself*/ -static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES]; -void -free_idal ( ccw1_t *cp ) +#ifdef CONFIG_ARCH_S390X +void +set_normalized_cda ( ccw1_t * cp, unsigned long address ) { + int nridaws; idaw_t *idal; - unsigned long upper2k,lower2k; - int nridaws,cacheind; - if ( cp -> flags & CCW_FLAG_IDA ) { - idal = cp -> cda; - lower2k = *idal & 0xfffffffffffff800; - upper2k = (*idal + cp -> count - 1) & 0xfffffffffffff800; - nridaws = ((upper2k - lower2k) >> 11) + 1; - for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ ); - kmem_cache_free ( idal_cache[cacheind], idal ); - } -} - -int -idal_support_init ( void ) -{ - int rc=0; - int cachind; - - for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { - int slabsize = 8 << cachind; - sprintf ( idal_cache_name[cachind], - "%s%d%c", idal_name_template, slabsize, 0); - idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind], - slabsize, 0, - SLAB_HWCACHE_ALIGN | SLAB_DMA, - NULL, NULL ); - if ( ! idal_cache [cachind] ) { - printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n"); - } + int count = cp->count; + + if (cp->flags & CCW_FLAG_IDA) + BUG(); + if (((address + count) >> 31) == 0) + cp -> cda = address; + return; + nridaws = ((address & 2047L) + count + 2047L) >> 11; + idal = idal_alloc(nridaws); + if ( idal == NULL ) { + /* probably we should have a fallback here */ + panic ("Cannot allocate memory for IDAL\n"); } - - return rc; -} - -void idal_support_cleanup ( void ) -{ - int cachind; - - /* Shrink the caches, if available */ - for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { - if ( idal_cache[cachind] ) { - if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) { - idal_cache[cachind] = NULL; - } - } - } - + cp->flags |= CCW_FLAG_IDA; + cp->cda = (__u32)(unsigned long)(idaw_t *)idal; + do { + *idal++ = address; + address = (address & -2048L) + 2048; + nridaws --; + } while ( nridaws > 0 ); + return; } +#endif diff --git a/drivers/s390/misc/Makefile b/drivers/s390/misc/Makefile index 6489b0f3c11c..281a18b50b22 100644 --- a/drivers/s390/misc/Makefile +++ b/drivers/s390/misc/Makefile @@ -2,7 +2,8 @@ all: s390-misc.o CFLAFS += O_TARGET := s390-misc.o -O_OBJS := +O_OBJS := +OX_OBJS := M_OBJS := include $(TOPDIR)/Rules.make diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 25b01cbcfea7..0983402f73c3 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -2,7 +2,8 @@ all: s390-net.o CFLAFS += O_TARGET := s390-net.o -O_OBJS := iucv.o +O_OBJS := +OX_OBJS := iucv.o M_OBJS := ifeq ($(CONFIG_CTC),y) diff --git a/drivers/s390/net/ctc.c b/drivers/s390/net/ctc.c index 20ea4fe7b77e..a2472548f6f9 100644 --- a/drivers/s390/net/ctc.c +++ b/drivers/s390/net/ctc.c @@ -1,5 +1,5 @@ /* - * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $ + * $Id: ctc.c,v 1.29 2001/01/25 22:28:21 uweigand Exp $ * * drivers/s390/net/ctc.c * CTC / ESCON network driver @@ -22,12 +22,13 @@ * order or doesn't want to have automatic channel selection on, you can do * this with the "ctc= kernel keyword". * - * ctc=0,0xrrrr,0xwwww,ddddd + * ctc=prid,0xrrrr,0xwwww,ddddd * * Where: * - * "rrrr" is the read channel address - * "wwww" is the write channel address + * "prid" is the protocol id (must always be 0) + * "rrrr" is the read channel address (hexadecimal) + * "wwww" is the write channel address (hexadecimal) * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 * to escon7 for ESCON channels). * @@ -38,24 +39,39 @@ * ctc=noauto * * $Log: ctc.c,v $ - * Revision 1.25.2.5 2000/10/11 15:08:59 bird - * ctc_tx(): Quick fix of possible underflow when calculating free block space + * Revision 1.29 2001/01/25 22:28:21 uweigand + * Minor 2.2.18 fix. * - * Revision 1.25.2.4 2000/09/25 16:40:56 bird - * Some more debug information + * Revision 1.28 2001/01/18 13:04:47 tonn + * upgrade to 2.2.18 * - * Revision 1.25.2.3 2000/09/20 13:28:19 bird - * - ctc_open(): fixed bug - * - ctc_release(): added timer for terminating in case of halt_io()-hang + * Revision 1.27 2000/10/26 16:16:07 bird + * Merged in changes from Revision 1.25.2.1 to Revision 1.25.2.6: * - * Revision 1.25.2.2 2000/09/20 09:48:27 bird - * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in - * instead of direct waiting on a wait queue - * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check(): - * print more debug information + * Revision 1.25.2.6 2000/10/25 16:11:55 bird + * Set size of empty block to BLOCK_HEADER_LENGTH (used to be 0) * - * Revision 1.25.2.1 2000/09/19 09:09:56 bird - * Merged in changes from 1.25 to 1.26 + * Revision 1.25.2.5 2000/10/11 15:08:59 bird + * ctc_tx(): Quick fix of possible underflow when calculating free block space + * + * Revision 1.25.2.4 2000/09/25 16:40:56 bird + * Some more debug information + * + * Revision 1.25.2.3 2000/09/20 13:28:19 bird + * - ctc_open(): fixed bug + * - ctc_release(): added timer for terminating in case of halt_io()-hang + * + * Revision 1.25.2.2 2000/09/20 09:48:27 bird + * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in + * instead of direct waiting on a wait queue + * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check(): + * print more debug information + * + * Revision 1.25.2.1 2000/09/19 09:09:56 bird + * Merged in changes from 1.25 to 1.26 + * + * Revision 1.26 2000/09/15 12:29:32 weigand + * Some 2.3 diffs merged and other fixes. * * Revision 1.25 2000/09/08 09:22:11 bird * Proper cleanup and bugfixes in ctc_probe() @@ -317,9 +333,9 @@ struct channel { #define CTC_BH_ACTIVE 0 __u8 last_dstat; __u8 flag; -#define CTC_WRITE 0x01 /* - Set if this is a write channel */ +#define CTC_WRITE 0x01 /* - Set if this is a write channel */ #define CTC_WAKEUP 0x02 /* - Set if this channel should wake up from waiting for an event */ -#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ +#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ }; @@ -350,6 +366,8 @@ struct block { __u16 length; struct packet data; }; +#define BLOCK_PAGES_POW 4 /* 2^4 = 16 pages per block (64k) */ +#define BLOCK_MAX_DATA 65535 /* maximal amount of data a block can hold */ #if LINUX_VERSION_CODE>=0x02032D #define ctc_protect_busy(dev) \ @@ -483,7 +501,7 @@ static void channel_sort(struct devicelist list[], int n); */ static void print_banner(void) { static int printed = 0; - char vbuf[] = "$Revision: 1.25.2.5 $"; + char vbuf[] = "$Revision: 1.29 $"; char *version = vbuf; if (printed) @@ -761,12 +779,12 @@ static int ctc_buffer_alloc(struct channel *ctc) { else { p->next = NULL; p->packets = 0; - p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4); + p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, BLOCK_PAGES_POW); if (p->block == NULL) { kfree(p); return -ENOMEM; } - p->block->length = 0; + p->block->length = BLOCK_HEADER_LENGTH; /* empty block */ } if (ctc->free_anchor == NULL) @@ -1107,7 +1125,7 @@ static void inline ccw_check_unit_check (net_device *dev, char sense, char *call } - + static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) { int rc = 0; @@ -1194,7 +1212,6 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) wake_up(&ctc->wait); /* wake up ctc_release */ return; - case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_HALT_IO"); @@ -1226,7 +1243,6 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) return; ctc->state = CTC_START_SELECT; - case CTC_START_SELECT: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SELECT"); @@ -1239,7 +1255,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) } if (!(ctc->flag & CTC_WRITE)) { ctc->state = CTC_START_READ_TEST; - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); @@ -1251,7 +1267,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) } else { ctc->state = CTC_START_WRITE_TEST; /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; @@ -1261,7 +1277,6 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) } return; - case CTC_START_READ_TEST: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ_TEST"); @@ -1298,8 +1313,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ - - case CTC_START_READ: + case CTC_START_READ: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ"); #endif @@ -1331,7 +1345,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); if (ctc->free_anchor != NULL) { - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); @@ -1350,7 +1364,6 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) } return; - case CTC_START_WRITE_TEST: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE_TEST"); @@ -1376,7 +1389,6 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ return; - case CTC_START_WRITE: #ifdef DEBUG printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE"); @@ -1392,7 +1404,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) privptr->stats.tx_packets += ctc->proc_anchor->packets; } - ctc->proc_anchor->block->length = 0; + ctc->proc_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev); ctc_clearbit_busy(TB_NOBUFFER, dev); if (ctc->proc_anchor != NULL) { @@ -1414,7 +1426,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr); return; } - if (ctc->free_anchor->block->length != 0) { + if (ctc->free_anchor->block->length != BLOCK_HEADER_LENGTH) { /* non-empty block */ if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { /* set transmission to busy */ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); @@ -1468,15 +1480,17 @@ static void ctc_irq_bh (void *data) while (ctc->proc_anchor != NULL) { block = ctc->proc_anchor->block; - if (block->length < BLOCK_HEADER_LENGTH) { - if(block->length == 0 && !ctc->initial_block_received) - ctc->initial_block_received = 1; - else + + if ((block->length < BLOCK_HEADER_LENGTH) + || (block->length == BLOCK_HEADER_LENGTH && ctc->initial_block_received)) { printk(KERN_INFO "%s: %s(): discarding block at 0x%p: " - "block length=%d<%d=block header length\n", + "block length=%d<=%d=block header length\n", dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH); } - else { + else if(block->length == BLOCK_HEADER_LENGTH && !ctc->initial_block_received) { + ctc->initial_block_received = 1; + } + else { /* there is valid data in the buffer */ lp = &block->data; while ((__u8 *) lp < (__u8 *) block + block->length) { if(lp->length < PACKET_HEADER_LENGTH) { @@ -1557,6 +1571,7 @@ static void ctc_read_retry (unsigned long data) dev->name, ctc->state); #endif s390irq_spin_lock_irqsave(ctc->irq, saveflags); + if (ctc->state != CTC_STOP) { if (!ctc->free_anchor) { s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); @@ -1566,7 +1581,7 @@ static void ctc_read_retry (unsigned long data) return; } - ctc->free_anchor->block->length = 0; + ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */ ctc->ccw[1].cda = __pa(ctc->free_anchor->block); parm = (__u32)(long) ctc; rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags); @@ -1634,7 +1649,6 @@ static int ctc_open(net_device *dev) struct ctc_priv *privptr; struct timer_list timer; - ctc_set_busy(dev); privptr = (struct ctc_priv *) (dev->priv); @@ -1696,13 +1710,13 @@ static int ctc_open(net_device *dev) rc = halt_IO(privptr->channel[i].irq, parm, flags); s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); - - del_timer(&timer); - if(rc != 0) ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); + + del_timer(&timer); + if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */ for (ii=0; ii<=i; ii++) { @@ -1718,7 +1732,7 @@ static int ctc_open(net_device *dev) return -ERESTARTSYS; } } - + if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) { @@ -1781,7 +1795,7 @@ static int ctc_release(net_device *dev) ctc_setbit_busy(TB_STOP,dev); ctc_unprotect_busy_irqrestore(dev, saveflags); - for (i = 0; i < 2; i++) { + for (i = 0; i < 2; i++) { privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER); init_timer(&timer); timer.function = ctc_timer; @@ -1803,7 +1817,7 @@ static int ctc_release(net_device *dev) if (rc != 0) { ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); } - + if(privptr->channel[i].flag & CTC_TIMER) { printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n", @@ -1872,7 +1886,7 @@ static int ctc_tx(struct sk_buff *skb, net_device *dev) goto Done; } - if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) { + if (privptr->channel[WRITE].free_anchor->block->length + PACKET_HEADER_LENGTH + skb->len > BLOCK_MAX_DATA) { #ifdef DEBUG printk(KERN_DEBUG "%s: early swap\n", dev->name); #endif @@ -1885,15 +1899,14 @@ static int ctc_tx(struct sk_buff *skb, net_device *dev) } } - if (privptr->channel[WRITE].free_anchor->block->length == 0) { - privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; + if (privptr->channel[WRITE].free_anchor->block->length == BLOCK_HEADER_LENGTH) { /* empty block */ privptr->channel[WRITE].free_anchor->packets = 0; } (__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length; - privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH; - lp->length = skb->len + PACKET_HEADER_LENGTH; + privptr->channel[WRITE].free_anchor->block->length += PACKET_HEADER_LENGTH + skb->len; + lp->length = PACKET_HEADER_LENGTH + skb->len; lp->type = 0x0800; lp->unused = 0; memcpy(&lp->data, skb->data, skb->len); diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c index a5b8e20eb008..d1151b9d086a 100644 --- a/drivers/s390/net/iucv.c +++ b/drivers/s390/net/iucv.c @@ -9,6 +9,8 @@ * Alan Altmark (Alan_Altmark@us.ibm.com) */ +#include +#include #include #include #include @@ -28,8 +30,6 @@ //#define DEBUG /* Turns Printk's on */ //#define DEBUG2 /* This prints the parameter list before and */ /* after the b2f0 call to cp */ -#define EXPORT_SYMTAB -#include #undef NULL #define NULL 0 #define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */ @@ -1533,7 +1533,7 @@ top_half_interrupt (struct pt_regs *regs, __u16 code) { iucv_packet *pkt; pkt = (iucv_packet *) kmalloc - (sizeof (iucv_packet), GFP_KERNEL | GFP_ATOMIC); + (sizeof (iucv_packet), GFP_ATOMIC); if (pkt == NULL) { printk (KERN_DEBUG "out of memory\n"); return; @@ -1869,15 +1869,16 @@ iucv_register_program (uchar pgmname[16], new_handler->size = ADDED_STOR; /* Allocate storage for pathid table */ new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL); - memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong)); if (new_handler->start == NULL) { #ifdef DEBUG printk (KERN_DEBUG "IUCV: returned NULL address for pathid table," " exiting\n"); #endif + kfree(new_handler); return NULL; } + memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong)); new_handler->end = (*new_handler).start + ADDED_STOR; new_handler->next = 0; new_handler->prev = 0; diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index efc0c0051585..f7fa5c1313a4 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -493,7 +493,7 @@ message_pending (iucv_MessagePending * mpi, ulong pgm_data) pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid, buffer_length); - buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA); + buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA); if (buffer == NULL) { p->stats.rx_dropped++; return; diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c index 8a5c22f8107e..d40597dca12b 100644 --- a/drivers/usb/hid.c +++ b/drivers/usb/hid.c @@ -698,7 +698,7 @@ static __inline__ __s32 snto32(__u32 value, unsigned n) static __inline__ __u32 s32ton(__s32 value, unsigned n) { __s32 a = value >> (n - 1); - if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1; + if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; return value & ((1 << n) - 1); } @@ -1016,9 +1016,15 @@ static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u __s32 max = field->logical_maximum; __s32 value[count]; /* WARNING: gcc specific */ - for (n = 0; n < count; n++) + for (n = 0; n < count; n++) { value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : extract(data, offset + n * size, size); + /* Handle the ErrorRollOver code (1) by simply ignoring this report */ + if (!(field->flags & HID_MAIN_ITEM_VARIABLE) + && value[n] >= min && value[n] <= max + && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) + return; + } for (n = 0; n < count; n++) { @@ -1231,7 +1237,7 @@ static int hid_find_field(struct hid_device *hid, unsigned int type, unsigned in static int hid_submit_out(struct hid_device *hid) { - hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; + hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length); hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); hid->urbout.dev = hid->dev; @@ -1271,8 +1277,8 @@ static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code hid_set_field(field, offset, value); hid_output_report(field->report, hid->out[hid->outhead].buffer); - hid->out[hid->outhead].dr.value = 0x200 | field->report->id; - hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1; + hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | field->report->id); + hid->out[hid->outhead].dr.length = cpu_to_le16((field->report->size + 7) >> 3); hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); @@ -1448,7 +1454,7 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE; hid->out[n].dr.request = USB_REQ_SET_REPORT; - hid->out[n].dr.index = hid->ifnum; + hid->out[n].dr.index = cpu_to_le16(hid->ifnum); } hid->input.name = hid->name; diff --git a/drivers/usb/serial/Config.in b/drivers/usb/serial/Config.in index 626df43c4d64..e4e168269178 100644 --- a/drivers/usb/serial/Config.in +++ b/drivers/usb/serial/Config.in @@ -22,6 +22,7 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19 bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W + bool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W fi dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL fi diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 165572238ad9..5fc3d7f395c6 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -501,12 +501,17 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum) tmp = tmp->next; down(&driver->serialize); + if (usb_interface_claimed(interface)) { + up(&driver->serialize); + return -1; + } private = driver->probe(dev, ifnum); - up(&driver->serialize); - if (!private) + if (!private) { + up(&driver->serialize); continue; + } usb_driver_claim_interface(driver, interface, private); - + up(&driver->serialize); return 0; } @@ -754,7 +759,7 @@ static void usb_find_drivers(struct usb_device *dev) dbg("unhandled interfaces on device"); if (!claimed) { - warn("USB device %d (prod/vend 0x%x/0x%x) is not claimed by any active driver.", + warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.", dev->devnum, dev->descriptor.idVendor, dev->descriptor.idProduct); diff --git a/drivers/video/promcon.c b/drivers/video/promcon.c index 984edab98e19..b0c1fbba4d4d 100644 --- a/drivers/video/promcon.c +++ b/drivers/video/promcon.c @@ -1,4 +1,4 @@ -/* $Id: promcon.c,v 1.15 1999/04/22 06:35:32 davem Exp $ +/* $Id: promcon.c,v 1.14 1999/03/09 14:02:42 davem Exp $ * Console driver utilizing PROM sun terminal emulation * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) diff --git a/fs/proc/array.c b/fs/proc/array.c index 98c7ec7b7a01..52ba9168fe39 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -1329,7 +1329,7 @@ extern int get_module_list(char *); extern int get_ksyms_list(char *, char **, off_t, int); #endif extern int get_device_list(char *); -extern int get_partition_list(char *); +extern int get_partition_list(char *, char **, off_t, int); extern int get_filesystem_list(char *); extern int get_filesystem_info( char * ); #ifndef CONFIG_ARCH_S390 @@ -1397,7 +1397,7 @@ static long get_root_array(char * page, int type, char **start, return get_device_list(page); case PROC_PARTITIONS: - return get_partition_list(page); + return get_partition_list(page, start, offset, length); #ifndef CONFIG_ARCH_S390 case PROC_INTERRUPTS: return get_irq_list(page); diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index b8cc1919d4fe..fe96954bccaf 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h @@ -495,9 +495,9 @@ extern __inline__ int test_and_set_bit_simple(int nr, volatile void * addr) " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -521,9 +521,9 @@ extern __inline__ int test_and_clear_bit_simple(int nr, volatile void * addr) " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -547,9 +547,9 @@ extern __inline__ int test_and_change_bit_simple(int nr, volatile void * addr) " lhi 2,7\n" " xr 1,%1\n" " nr 2,1\n" - " srl 1,3(0)\n" + " srl 1,3\n" " la 1,0(1,%2)\n" - " ic %0,0(0,1)\n" + " ic %0,0(1)\n" " srl %0,0(2)\n" " n %0,%4\n" " la 2,0(2,%3)\n" @@ -632,7 +632,7 @@ extern __inline__ int find_first_zero_bit(void * addr, unsigned size) " lr 2,%1\n" " j 4f\n" "1: l 1,0(2,%2)\n" - " sll 2,3(0)\n" + " sll 2,3\n" " tml 1,0xFFFF\n" " jno 2f\n" " ahi 2,16\n" @@ -804,7 +804,7 @@ extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size) " lr 2,%1\n" " j 4f\n" "1: l 1,0(2,%2)\n" - " sll 2,3(0)\n" + " sll 2,3\n" " lhi 0,0xff\n" " ahi 2,24\n" " tmh 1,0xFFFF\n" diff --git a/include/asm-s390/ccwcache.h b/include/asm-s390/ccwcache.h index ffbd4baeb930..aae53de150fa 100644 --- a/include/asm-s390/ccwcache.h +++ b/include/asm-s390/ccwcache.h @@ -1,5 +1,5 @@ /* - * File...........: linux/drivers/s390/block/ccwcache.c + * File...........: linux/include/asm-s390/ccwcache.h * Author(s)......: Holger Smolinski * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 @@ -34,7 +34,8 @@ typedef struct ccw_req_t { devstat_t *dstat; /* The device status in case of an error */ /* these are important for recovering erroneous requests */ - int retries; /* A retry counter to be set when filling */ + short retries; /* A retry counter to be set when filling */ + char lpm; /* logical path mask */ devstat_t *devstat; /* Keeping the device status */ struct ccw_req_t *refers; /* Does this request refer to another one? */ void *function; /* refers to the originating ERP action */ ; @@ -64,6 +65,7 @@ typedef struct ccw_req_t { #define CQR_STATUS_DONE 0x08 /* request is completed sucessfully */ #define CQR_STATUS_ERROR 0x10 /* request is completed with error */ #define CQR_STATUS_FAILED 0x20 /* request is finally failed */ +#define CQR_STATUS_PENDING 0x07 /* request is waiting for interrupt - ERP only */ #define CQR_STATUS_FINISHED 0x40 /* request is ready for cleanup */ #ifdef __KERNEL__ diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h index 0c5b942746cd..0e5c1538c152 100644 --- a/include/asm-s390/dasd.h +++ b/include/asm-s390/dasd.h @@ -2,12 +2,15 @@ #ifndef DASD_H #define DASD_H +#undef ERP_DEBUG /* enable debug messages */ + /* First of all the external stuff */ #include #include #include #include #include +#include #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) #include #endif @@ -65,6 +68,12 @@ typedef enum { dasd_era_recover = 2 /* recovery action recommended */ } dasd_era_t; +/* BIT DEFINITIONS FOR SENSE DATA */ +#define DASD_SENSE_BIT_0 0x80 +#define DASD_SENSE_BIT_1 0x40 +#define DASD_SENSE_BIT_2 0x20 +#define DASD_SENSE_BIT_3 0x10 + /* * struct dasd_sizes_t * represents all data needed to access dasd with properly set up sectors @@ -97,7 +106,7 @@ struct dasd_chanq_t { struct dasd_device_t; typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); -typedef int (*dasd_erp_postaction_fn_t) (ccw_req_t * cqr, int); +typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); typedef int (*dasd_ck_id_fn_t) (dev_info_t *); typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); @@ -165,6 +174,7 @@ typedef struct dasd_device_t { struct wait_queue wait; struct wait_queue *wait_q; #endif /* LINUX_IS_24 */ + struct timer_list timer; /* HUM new */ dasd_sizes_t sizes; devstat_t dev_status; char *characteristics; @@ -231,6 +241,24 @@ void dasd_discipline_enq (dasd_discipline_t *); int dasd_discipline_deq(dasd_discipline_t *); int dasd_start_IO (ccw_req_t *); void dasd_int_handler (int , void *, struct pt_regs *); +ccw_req_t *default_erp_action (ccw_req_t *); +ccw_req_t *default_erp_postaction (ccw_req_t *); +int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); +ccw_req_t *dasd_alloc_request (char *, int, int); +void dasd_free_request (ccw_req_t *); + + +#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ +do { \ + int d_devno = d_device->devinfo.devno; \ + int d_irq = d_device->devinfo.irq; \ + char *d_name = d_device->name; \ + int d_major = MAJOR(d_device->kdev); \ + int d_minor = MINOR(d_device->kdev); \ + printk(d_loglevel PRINTK_HEADER \ + "/dev/%s(%d:%d), 0x%04X on SCH 0x%x: " \ + d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ +} while(0) #endif /* __KERNEL__ */ diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h index ec722074811f..6de9551b9629 100644 --- a/include/asm-s390/debug.h +++ b/include/asm-s390/debug.h @@ -9,42 +9,59 @@ #ifndef DEBUG_H #define DEBUG_H -#ifdef __KERNEL__ +/* Note: + * struct __debug_entry must be defined outside of #ifdef __KERNEL__ + * in order to allow a user program to analyze the 'raw'-view. + */ + +struct __debug_entry{ + union { + struct { + unsigned long long clock:52; + unsigned long long exception:1; + unsigned long long level:3; + unsigned long long cpuid:8; + } fields; + + unsigned long long stck; + } id; + void* caller; +} __attribute__((packed)); -#include + +#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */ + +#ifdef __KERNEL__ +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + #include +#else + #include +#endif /* LINUX_VERSION_CODE */ #include #include #include -#define DEBUG_MAX_AREAS 16 /* max number of allowed registers */ #define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */ +#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ #define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ +#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */ + /* the entry information */ + #define STCK(x) asm volatile ("STCK %0":"=m" (x)) -typedef struct { - union { - struct { - unsigned long long clock:52; - unsigned long long unused:2; - unsigned long long cpuid:8; - unsigned long long exception:1; - unsigned long long used:1; - } fields; - - unsigned long long stck; - } id; - void* caller; - char data[4]; -} debug_entry_t; +typedef struct __debug_entry debug_entry_t; struct debug_view; -typedef struct { +typedef struct debug_info { + struct debug_info* next; + struct debug_info* prev; atomic_t ref_count; spinlock_t lock; int level; @@ -54,7 +71,7 @@ typedef struct { int entry_size; debug_entry_t** areas; int active_area; - int active_entry[DEBUG_MAX_AREAS]; + int *active_entry; struct proc_dir_entry* proc_root_entry; struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS]; struct debug_view* views[DEBUG_MAX_VIEWS]; @@ -87,29 +104,97 @@ struct debug_view { debug_header_proc_t* header_proc; debug_format_proc_t* format_proc; debug_input_proc_t* input_proc; + void* private_data; }; -extern struct debug_view debug_ascii_view; -extern struct debug_view debug_ebcdic_view; -extern struct debug_view debug_hex_view; +extern struct debug_view debug_hex_ascii_view; +extern struct debug_view debug_raw_view; +extern struct debug_view debug_sprintf_view; + +/* do NOT use the _common functions */ + +debug_entry_t* debug_event_common(debug_info_t* id, int level, + const void* data, int length); + +debug_entry_t* debug_exception_common(debug_info_t* id, int level, + const void* data, int length); + +/* Debug Feature API: */ debug_info_t* debug_register(char* name, int pages_index, int nr_areas, - int buf_size); + int buf_size); + void debug_unregister(debug_info_t* id); -debug_entry_t* debug_event(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_event(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_event(debug_info_t* id, int level, - const char* txt); - -debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, - int length); -debug_entry_t* debug_int_exception(debug_info_t* id, int level, - unsigned int tag); -debug_entry_t* debug_text_exception(debug_info_t* id, int level, - const char* txt); +void debug_set_level(debug_info_t* id, int new_level); + +extern inline debug_entry_t* +debug_event(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_event(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * +debug_long_event (debug_info_t* id, int level, unsigned long tag) +{ + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_event(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_event_common(id,level,txt,strlen(txt)); +} + +extern debug_entry_t * +debug_sprintf_event(debug_info_t* id,int level,char *string,...); + + +extern inline debug_entry_t* +debug_exception(debug_info_t* id, int level, void* data, int length) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,data,length); +} + +extern inline debug_entry_t* +debug_int_exception(debug_info_t* id, int level, unsigned int tag) +{ + unsigned int t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned int)); +} + +extern inline debug_entry_t * +debug_long_exception (debug_info_t* id, int level, unsigned long tag) +{ + unsigned long t=tag; + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,&t,sizeof(unsigned long)); +} + +extern inline debug_entry_t* +debug_text_exception(debug_info_t* id, int level, const char* txt) +{ + if ((!id) || (level > id->level)) return NULL; + return debug_exception_common(id,level,txt,strlen(txt)); +} + + +extern debug_entry_t * +debug_sprintf_exception(debug_info_t* id,int level,char *string,...); int debug_register_view(debug_info_t* id, struct debug_view* view); int debug_unregister_view(debug_info_t* id, struct debug_view* view); diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index 60a08aaae64a..e665ec85b26b 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -22,7 +22,8 @@ typedef s390_regs elf_gregset_t; /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(x) ((x) == EM_S390) +#define elf_check_arch(x) \ + ((x) == EM_S390 || (x) == EM_S390_OLD) /* * These are used to set parameters in the core dumps. diff --git a/include/asm-s390/idals.h b/include/asm-s390/idals.h index 362e91d276f8..4daebfa66c1e 100644 --- a/include/asm-s390/idals.h +++ b/include/asm-s390/idals.h @@ -7,19 +7,50 @@ * History of changes * 07/24/00 new file */ - -#define IDAL_NUMBER_CACHES 7 +#include typedef unsigned long idaw_t; -#ifdef CONFIG_ARCH_S390 -extern inline int -normalize_cpa(ccw1_t * ccw, unsigned long address) +static inline idaw_t * +idal_alloc ( int nridaws ) +{ + if ( nridaws > 33 ) + BUG(); + return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA ); +} + +static inline void +idal_free ( idaw_t *idal ) { - return address; + kfree (idal); } + +/* + * Function: set_normalized_cda + * sets the address of the data in CCW + * if necessary it allocates an IDAL and sets sthe appropriate flags + */ +#if defined (CONFIG_ARCH_S390) +static inline void +set_normalized_cda(ccw1_t * ccw, unsigned long address) +{ + ccw->cda = address; +} +#elif defined (CONFIG_ARCH_S390X) +extern void set_normalized_cda(ccw1_t * ccw, unsigned long address); #endif -int idal_alloc ( int nridaws ); -void idal_release ( idaw_t *idal ); +/* + * Function: clear_normalized_cda + * releases any allocated IDAL related to the CCW + */ +static inline void +clear_normalized_cda ( ccw1_t * ccw ) +{ + if ( ccw -> flags & CCW_FLAG_IDA ) { + idal_free ( (idaw_t *) (ccw -> cda )); + ccw -> flags &= ~CCW_FLAG_IDA; + } + ccw -> cda = 0; +} diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h index d609616f43e9..eda48f080f0f 100644 --- a/include/asm-s390/io.h +++ b/include/asm-s390/io.h @@ -25,7 +25,7 @@ extern inline unsigned long virt_to_phys(volatile void * address) { unsigned long real_address; - __asm__ (" lra %0,0(0,%1)\n" + __asm__ (" lra %0,0(%1)\n" " jz 0f\n" " sr %0,%0\n" "0:" diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h index c3f3f602e8e5..5843fa6f37c7 100644 --- a/include/asm-s390/irq.h +++ b/include/asm-s390/irq.h @@ -183,6 +183,33 @@ typedef struct { #define SNS0_EQUIPMENT_CHECK 0x10 #define SNS0_DATA_CHECK 0x08 #define SNS0_OVERRUN 0x04 +/* 0x02 reserved */ +#define SNS0_INCOMPL_DOMAIN 0x01 + +/* + * architectured values for second sense byte + */ +#define SNS1_PERM_ERR 0x80 +#define SNS1_INV_TRACK_FORMAT 0x40 +#define SNS1_EOC 0x20 +#define SNS1_MESSAGE_TO_OPER 0x10 +#define SNS1_NO_REC_FOUND 0x08 +#define SNS1_FILE_PROTECTED 0x04 +#define SNS1_WRITE_INHIBITED 0x02 +#define SNS1_INPRECISE_END 0x01 + +/* + * architectured values for third sense byte + */ +#define SNS2_REQ_INH_WRITE 0x80 +#define SNS2_CORRECTABLE 0x40 +#define SNS2_FIRST_LOG_ERR 0x20 +#define SNS2_ENV_DATA_PRESENT 0x10 +/* 0x08 reserved */ +#define SNS2_INPRECISE_END 0x04 +/* 0x02 reserved */ +/* 0x01 reserved */ + /* * operation request block @@ -319,6 +346,7 @@ typedef struct _ciw { #define CIW_TYPE_SII 0x1 // set interface identifier #define CIW_TYPE_RNI 0x2 // read node identifier +#define MAX_CIWS 8 // // sense-id response buffer layout // @@ -331,7 +359,7 @@ typedef struct { __u8 dev_model; /* device model */ __u8 unused; /* padding byte */ /* extended part */ - ciw_t ciw[16]; /* variable # of CIWs */ + ciw_t ciw[MAX_CIWS]; /* variable # of CIWs */ } __attribute__ ((packed,aligned(4))) senseid_t; #endif /* __KERNEL__ */ @@ -383,6 +411,7 @@ typedef struct { #define DEVSTAT_FINAL_STATUS 0x80000000 #define INTPARM_STATUS_PENDING 0xFFFFFFFF + #ifdef __KERNEL__ typedef void (* io_handler_func1_t) ( int irq, @@ -543,7 +572,7 @@ int s390_request_irq_special( int irq, not_oper_handler_func_t not_oper_handler, unsigned long irqflags, const char *devname, - void *dev_id); + devstat_t *dev_id); extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *); @@ -809,7 +838,7 @@ static inline void s390_do_profile (unsigned long addr) { if (prof_buffer && current->pid) { addr &= 0x7fffffff; - addr -= (unsigned long)&_stext; + addr -= (unsigned long) &_stext; addr >>= prof_shift; /* * Don't ignore out-of-bounds EIP values silently, @@ -832,8 +861,10 @@ static inline void s390_do_profile (unsigned long addr) #define s390irq_spin_lock_irqsave(irq,flags) \ spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags) + #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) #endif /* __KERNEL__ */ + #endif diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index d8d927bc1d75..8c9c50892dc1 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -546,7 +546,7 @@ static inline void __flush_tlb_one(struct mm_struct *mm, extern __inline__ pgd_t* get_pgd_slow(void) { int i; - pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2); + pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,1); if (ret) for (i=0,pgd=ret;i global flush - * - * Fixme: To avoid this global flush we should - * use pdg_quicklist as fix lenght fifo list - * and not as stack - */ + pgtable_cache_size -= 2; } else ret = (unsigned long *)get_pgd_slow(); return (pgd_t *)ret; @@ -580,12 +570,12 @@ extern __inline__ void free_pgd_fast(pgd_t *pgd) { *(unsigned long *)pgd = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; - pgtable_cache_size++; + pgtable_cache_size += 2; } extern __inline__ void free_pgd_slow(pgd_t *pgd) { - free_pages((unsigned long)pgd,2); + free_pages((unsigned long)pgd, 1); } extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index bdcfe8b04beb..1b1a9f040712 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -33,14 +33,14 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) " nr 1,%0\n" /* isolate last 2 bits */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,8,%1\n" /* for ptr&3 == 0 */ - " stcm 0,8,%1\n" - " icm 1,4,%1\n" /* for ptr&3 == 1 */ - " stcm 0,4,%1\n" - " icm 1,2,%1\n" /* for ptr&3 == 2 */ - " stcm 0,2,%1\n" - " icm 1,1,%1\n" /* for ptr&3 == 3 */ - " stcm 0,1,%1\n" + " icm 1,8,3(%1)\n" /* for ptr&3 == 0 */ + " stcm 0,8,3(%1)\n" + " icm 1,4,3(%1)\n" /* for ptr&3 == 1 */ + " stcm 0,4,3(%1)\n" + " icm 1,2,3(%1)\n" /* for ptr&3 == 2 */ + " stcm 0,2,3(%1)\n" + " icm 1,1,3(%1)\n" /* for ptr&3 == 3 */ + " stcm 0,1,3(%1)\n" "0: sll 1,3\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -49,8 +49,9 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); + break; case 2: if(((__u32)ptr)&1) panic("misaligned (__u16 *) in __xchg\n"); @@ -59,10 +60,10 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) " nr 1,%0\n" /* isolate bit 2^1 */ " xr %0,1\n" /* align ptr */ " bras 2,0f\n" - " icm 1,12,%1\n" /* for ptr&2 == 0 */ - " stcm 0,12,%1\n" - " icm 1,3,%1\n" /* for ptr&2 == 1 */ - " stcm 0,3,%1\n" + " icm 1,12,2(%1)\n" /* for ptr&2 == 0 */ + " stcm 0,12,2(%1)\n" + " icm 1,3,2(%1)\n" /* for ptr&2 == 1 */ + " stcm 0,3,2(%1)\n" "0: sll 1,2\n" " la 2,0(1,2)\n" /* r2 points to an icm */ " l 0,0(%0)\n" /* get fullword */ @@ -71,7 +72,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr), "+m" (x) : + : "+a&" (ptr) : "a" (&x) : "memory", "0", "1", "2"); break; case 4: diff --git a/include/asm-s390/todclk.h b/include/asm-s390/todclk.h new file mode 100644 index 000000000000..92a27a9d4af8 --- /dev/null +++ b/include/asm-s390/todclk.h @@ -0,0 +1,19 @@ +/* + * File...........: linux/include/asm/todclk.h + * Author(s)......: Holger Smolinski + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * + * History of changes (starts July 2000) + */ + +#ifndef __ASM_TODCLK_H +#define __ASM_TODCLK_H + +#define TOD_uSEC (0x1000ULL) +#define TOD_mSEC (1000 * TOD_uSEC) +#define TOD_SEC (1000 * TOD_mSEC) +#define TOD_MIN (60 * TOD_SEC) +#define TOD_HOUR (60 * TOD_MIN) + +#endif diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h index 57e46e7b02a6..a9fd8535beb2 100644 --- a/include/asm-sparc/page.h +++ b/include/asm-sparc/page.h @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.43 1998/05/11 08:40:11 davem Exp $ +/* $Id: page.h,v 1.43.2.1 2001/02/20 04:21:45 davem Exp $ * page.h: Various defines and such for MMU operations on the Sparc for * the Linux kernel. * @@ -28,6 +28,10 @@ #ifndef __ASSEMBLY__ +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; \ +} while (0) + #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index 0894bb90d09f..db67b4f0a66a 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */ +/* $Id: page.h,v 1.24.2.1 2001/02/20 04:21:45 davem Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H @@ -18,6 +18,8 @@ #ifndef __ASSEMBLY__ +#define BUG() __builtin_trap() + extern void clear_page(unsigned long page); extern void copy_page(unsigned long to, unsigned long from); diff --git a/include/linux/blk.h b/include/linux/blk.h index 0a22c3dadc70..ea964c4e6758 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -397,7 +397,7 @@ static void floppy_off(unsigned int nr); #define LOCAL_END_REQUEST #define DEVICE_NAME "dasd" #define DEVICE_REQUEST do_dasd_request -#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) +#define DEVICE_NR(device) (MINOR(device) >> DASD_PARTN_BITS) #define DEVICE_ON(device) #define DEVICE_OFF(device) diff --git a/include/linux/elf.h b/include/linux/elf.h index f1b9c9125d1b..4187d80e3b7c 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -68,6 +68,8 @@ typedef __u64 Elf64_Word; #define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_S390 22 /* IBM S/390 */ + /* * This is an interim value that we will use until the committee comes * up with a final number. @@ -75,9 +77,9 @@ typedef __u64 Elf64_Word; #define EM_ALPHA 0x9026 /* - * This is an interim value for S390 architecture + * This is the old interim value for S/390 architecture */ -#define EM_S390 0xA390 +#define EM_S390_OLD 0xA390 /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 diff --git a/init/main.c b/init/main.c index 155476ec365e..df269c22afa7 100644 --- a/init/main.c +++ b/init/main.c @@ -203,9 +203,6 @@ extern void con3215_setup(char *str, int *ints); #ifdef CONFIG_MDISK extern void mdisk_setup(char *str, int *ints); #endif -#ifdef CONFIG_DASD -extern void dasd_setup(char *str, int *ints); -#endif #ifdef CONFIG_BLK_DEV_XPRAM extern void xpram_setup(char *str, int *ints); #endif @@ -1111,9 +1108,6 @@ static struct kernel_param raw_params[] __initdata = { #ifdef CONFIG_MDISK { "mdisk=", mdisk_setup }, #endif -#ifdef CONFIG_DASD - { "dasd=", dasd_setup }, -#endif #ifdef CONFIG_BLK_DEV_XPRAM { "xpram_parts=", xpram_setup }, #endif diff --git a/net/core/filter.c b/net/core/filter.c index ffdca78403c0..8dd6aab09a41 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -196,7 +196,7 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen) case BPF_LD|BPF_W|BPF_ABS: k = fentry->k; load_w: - if(k+sizeof(u32) <= len) { + if((unsigned int)(k+sizeof(u32)) <= len) { A = ntohl(*(u32*)&data[k]); continue; } @@ -215,7 +215,7 @@ load_w: case BPF_LD|BPF_H|BPF_ABS: k = fentry->k; load_h: - if(k + sizeof(u16) <= len) { + if((unsigned int) (k + sizeof(u16)) <= len) { A = ntohs(*(u16*)&data[k]); continue; } @@ -234,7 +234,7 @@ load_h: case BPF_LD|BPF_B|BPF_ABS: k = fentry->k; load_b: - if(k < len) { + if((unsigned int)k < len) { A = data[k]; continue; } @@ -271,7 +271,7 @@ load_b: case BPF_LDX|BPF_B|BPF_MSH: k = fentry->k; - if(k >= len) + if((unsigned int)k >= len) return (0); X = (data[k] & 0xf) << 2; continue; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index c855d26920f6..6d52fa4e19b8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -230,6 +230,10 @@ addrform_done: if (optlen == 0) goto update; + + retv = -EINVAL; + if(optlen > 1024) + break; opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); retv = -ENOBUFS; diff --git a/scripts/makelst b/scripts/makelst index f341229df566..a76ca78b34ac 100644 --- a/scripts/makelst +++ b/scripts/makelst @@ -2,7 +2,8 @@ # A script to dump mixed source code & assembly # with correct relocations from System.map # Requires the following lines in Rules.make. -# +# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) +# William Stearns #%.lst: %.c # $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $< # $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP) @@ -16,6 +17,6 @@ t2=`echo $t1 | gawk '{ print $6 }'` t3=`grep $t2 $2/System.map` t4=`echo $t3 | gawk '{ print $1 }'` t5=`echo $t1 | gawk '{ print $1 }'` -t6=`echo $t4 - $t5 | sed s/a/A/g | sed s/b/B/g | sed s/c/C/g | sed s/d/D/g | sed s/e/E/g | sed s/f/F/g` +t6=`echo $t4 - $t5 | sed -e s/a/A/g -e s/b/B/g -e s/c/C/g -e s/d/D/g -e s/e/E/g -e s/f/F/g` t7=`( echo ibase=16 ; echo $t6 ) | bc` $3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst -- 2.39.5