URL to your translation for inclusion in future revisions of this
document.
-Last updated: June 11, 2000
+Last updated: August 12, 2000
Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
with pcmcia-cs.
o Gnu C 2.7.2.3 # gcc --version
+o Gnu make 3.77 # make --version
o binutils 2.9.1.0.22 # ld -v
-o util-linux 2.10g # chsh -v
+o util-linux 2.10o # kbdrate -v
o modutils 2.3.13 # insmod -V
o e2fsprogs 1.18 # /sbin/tune2fs --version
o pcmcia-cs 3.1.13 # cardmgr -V
have several options for gcc-derived compilers: gcc 2.7.2.3, various
versions of egcs, the new gcc 2.95 and upcoming gcc 3.0, and experimental
compilers like pgcc. For absolute stability, it is still recommended
-that gcc 2.7.2.3 be used to compile your kernel. egcs 1.12 should also
+that gcc 2.7.2.3 be used to compile your kernel. egcs 1.1.2 should also
work. gcc 2.95 is known to have problems, and using pgcc for your kernel
is just asking for trouble.
or derivatives, be sure not to use -fstrict-aliasing (which, depending on
your version of gcc 2.95, may necessitate using -fno-strict-aliasing).
+Make
+----
+
+You will need Gnu make 3.77 or later to build the kernel.
+
Binutils
--------
You do not have to mount it to use it as long as you can live with the
default maxima for shared memory and segments. If you wish to change
these variables, you have to mount it with the options nr_blocks
-and/or nr_inodes. POSIX shared memory is also now implemented via a
+and / or nr_inodes. POSIX shared memory is also now implemented via a
virtual filesystem. If you want to use it, you'll need to mount the
filesystem. The recommended mount location is /dev/shm, and adding the
following line to /etc/fstab should take care of things:
New versions of util-linux provide *fdisk support for larger disks,
support new options to mount, recognize more supported partition
-types, and similar goodies. You'll probably want to upgrade.
+types, have a fdformat which works with 2.4 kernels, and similar goodies.
+You'll probably want to upgrade.
Ksymoops
--------
Upgrade to recent modutils to fix various outstanding bugs which are
seen more frequently under 2.3.x, and to enable auto-loading of USB
-modules.
+modules. In addition, the layout of modules under
+/lib/modules/`uname -r`/ has been made more sane. This change also
+requires that you upgrade to a recent modutils.
+
+Mkinitrd
+--------
+
+These changes to the /lib/modules file tree layout also require that
+mkinitrd be upgraded.
E2fsprogs
---------
gcc 2.7.2.3
-----------
-o ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz
- <ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz>
-o ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz
- <ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz>
+o <ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz>
+o <ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz>
-egcs 1.12
+egcs 1.1.2
---------
-o ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2
- <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2>
-o ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2
- <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2>
-o ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.tar.bz2
- <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.tar.bz2>
+o <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2>
+o <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2>
+o <ftp://ftp.valinux.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.tar.bz2>
Binutils
********
2.9.1 series
------------
-o ftp://ftp.valinux.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz
- <ftp://ftp.valinux.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz>
+o <ftp://ftp.valinux.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz>
2.9.5 series
------------
-o ftp://ftp.valinux.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.gz
- <ftp://ftp.valinux.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.bz2>
+o <ftp://ftp.valinux.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.bz2>
System utilities
****************
Util-linux
----------
-o ftp://ftp.cwi.nl/pub/aeb/util-linux/util-linux-2.10g.tar.gz
- <ftp://ftp.cwi.nl/pub/aeb/util-linux/util-linux-2.10g.tar.gz>
+o <ftp://ftp.win.tue.nl/pub/linux-local/util-linux/util-linux-2.10o.tar.gz>
Ksymoops
--------
-o ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.3
- <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.3>
+o <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.3>
Modutils
--------
-o ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.3/modutils-2.3.13.tar.gz
- <ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.3/modutils-2.3.13.tar.gz>
+o <ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.3/modutils-2.3.13.tar.gz>
E2fsprogs
---------
-o http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.tar.gz
- <http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.tar.gz>
-o http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.src.rpm
- <http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.src.rpm>
+o <http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.tar.gz>
+o <http://web.mit.edu/tytso/www/linux/dist/e2fsprogs-1.18.src.rpm>
LVM toolset
-----------
-o http://linux.msede.com/lvm/ <http://linux.msede.com/lvm/>
+o <http://linux.msede.com/lvm/>
Pcmcia-cs
---------
-o ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.13.tar.gz
- <ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.13.tar.gz>
+o <ftp://sourceforge.org/pcmcia/pcmcia-cs-3.1.13.tar.gz>
Jade
----
-o ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz
- <ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz>
+o <ftp://ftp.jclark.com/pub/jade/jade-1.2.1.tar.gz>
DocBook Stylesheets
-------------------
-o http://nwalsh.com/docbook/dsssl/
- <http://nwalsh.com/docbook/dsssl/>
+o <http://nwalsh.com/docbook/dsssl/>
Intel P6 microcode
------------------
-o http://www.urbanmyth.org/microcode/
- <http://www.urbanmyth.org/microcode/>
+o <http://www.urbanmyth.org/microcode/>
Network
*******
PPP
---
-o ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz
- <ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz>
+o <ftp://linuxcare.com.au/pub/ppp/ppp-2.4.0b1.tar.gz>
Isdn4k-utils
------------
-o ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-
- utils.v3.1beta7.tar.gz
- <ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-
- utils.v3.1beta7.tar.gz>
+o <ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz>
Netfilter
---------
-o http://netfilter.filewatcher.org/iptables-1.1.1.tar.bz2
- <http://netfilter.filewatcher.org/iptables-1.1.1.tar.bz2>
-o http://www.samba.org/netfilter/iptables-1.1.1.tar.bz2
- <http://www.samba.org/netfilter/iptables-1.1.1.tar.bz2>
-o http://netfilter.kernelnotes.org/iptables-1.1.1.tar.bz2
- <http://netfilter.kernelnotes.org/iptables-1.1.1.tar.bz2>
+o <http://netfilter.filewatcher.org/iptables-1.1.1.tar.bz2>
+o <http://www.samba.org/netfilter/iptables-1.1.1.tar.bz2>
+o <http://netfilter.kernelnotes.org/iptables-1.1.1.tar.bz2>
Ip-route2
---------
-o ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz
- <ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz>
+o <ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz>
Suggestions and corrections
===========================
USB Digi International AccelePort USB Serial Driver
CONFIG_USB_SERIAL_DIGI_ACCELEPORT
- Say Y here if you want to use a Digi AccelePort USB 4 device,
- a 4 port USB serial converter. The Digi Acceleport USB 2 and
- 8 are not yet supported by this driver.
+ Say Y here if you want to use Digi AccelePort USB 2 or 4 devices,
+ 2 port (plus parallel port) and 4 port USB serial converters. The
+ parallel port on the USB 2 appears as a third serial port on Linux.
+ The Digi Acceleport USB 8 is not yet supported by this driver.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
Creative EMU10K1 based PCI sound cards
CONFIG_SOUND_EMU10K1
Say Y or M if you have a PCI sound card using the EMU10K1
- chipset, such as the Creative SBLive! or SB PCI512.
+ chipset, such as the Creative SBLive!, SB PCI512 or Emu-APS.
Ensoniq ES1370 based PCI sound cards
CONFIG_SOUND_ES1370
called sc.o. See Documentation/isdn/README.sc and
http://www.spellcast.com for more information.
-Eicon.Diehl active card support
+Eicon active card support
CONFIG_ISDN_DRV_EICON
Say Y here if you have an Eicon active ISDN card. In order to use
this card, additional firmware is necessary, which has to be loaded
latest isdn4k-utils package. Please read the file
Documentation/isdn/README.eicon for more information.
+Eicon Diva Server card support
+CONFIG_ISDN_DRV_EICON_PCI
+ Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card.
+ Please read Documentation/isdn/README.eicon for more information.
+
Eicon old-type card support
CONFIG_ISDN_DRV_EICON_ISA
Say Y here if you have an old-type Eicon active ISDN card. In order
the latest isdn4k-utils package. Please read the file
Documentation/isdn/README.eicon for more information.
+Eicon driver type standalone
+CONFIG_ISDN_DRV_EICON_STANDALONE
+ Enable this option if you want the eicon driver as standalone
+ version with no interface to the ISDN4Linux isdn module. If you
+ say Y here, the eicon module only supports the Diva Server PCI
+ cards and will provide its own IDI interface. You should say N
+ here.
+
Support AT-Fax Class 2 commands
CONFIG_ISDN_TTY_FAX
If you say Y here, the modem-emulator will support a subset of the
--- /dev/null
+The Intrinsyc CerfBoard is a StrongARM 1110-based computer on a board that measures
+approximately 2" square. It includes an Ethernet controller, an RS232-compatible serial port, a
+USB function port, and one CompactFlash+ slot on the back. Pictures can be found at the
+Intrinsyc website, http://www.intrinsyc.com.
+
+This document describes the support in the Linux kernel for the Intrinsyc CerfBoard as of
+version 2.4.0-test4-np1.
+
+Supported in this version:
+ - CompactFlash+ slot (select PCMCIA in General Setup and any options that may be required)
+ - Onboard Crystal CS8900 Ethernet controller (Cerf CS8900A support in Network Devices)
+ - Serial ports with a serial console (hardcoded to 38400 8N1)
+
+Not supported in this version (yet):
+ - LCD driver/touchscreen interface
+ - UDC (a driver exists right now, but is unstable and slow and only works with the Linux USB)
+
+In order to get this kernel onto your Cerf, you need a server that runs both BOOTP and
+TFTP. Detailed instructions should have come with your evaluation kit on how to use the
+bootloader. This series of commands will suffice:
+
+ make cerf_config
+ make xconfig
+ make dep
+ make zImage
+ cp arch/arm/boot/zImage <TFTP directory>
+
+The default config uses a 4MB RAM disk located at 0xc0500000 as root. Setting the board to
+mount root from a NFS partition works, too.
+
+
+I-Gene Leong, Intrinsyc Software Inc.
+ileong@intrinsyc.com
+
--- /dev/null
+nanoEngine
+----------
+
+"nanoEngine" is a SA1110 based single board computer from
+Bright Star Engineering Inc. See www.brightstareng.com/arm
+for more info.
+
+Ref: Stuart Adams <sja@brightstareng.com>
+
0 = transparent
1 = transparent with audio features (e.g. DSP)
2 = Fax G3 Class 2 commands (S14 has to be set to 11)
- 2 = Fax G3 Class 1 commands (S14 has to be set to 11)
+ 3 = Fax G3 Class 1 commands (S14 has to be set to 11)
16 250 Send-Packet-size/16
17 8 Window-size (not yet implemented)
18 4 Bit coded register, Service-Octet-1 to accept,
-$Id: README.eicon,v 1.7 2000/03/06 16:38:43 armin Exp $
+$Id: README.eicon,v 1.9 2000/06/08 08:50:25 armin Exp $
(c) 1999,2000 Armin Schindler (mac@melware.de)
(c) 1999,2000 Cytronics & Melware (info@melware.de)
------------------
- 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)
Example for a BRI card with E-DSS1 Protocol with PtP configuration.
- eiconctrl [-d DriverId] load etsi -n -t0 -s1
+ eiconctrl [-d DriverId] load etsi -n -t1 -s1
Example for loading and starting a PRI card with E-DSS1 Protocol.
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
Armin Schindler
mac@melware.de
http://www.melware.de
+
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.
3CCFE656 Cyclone CardBus
3CCFEM656 Cyclone CardBus
3c450 Cyclone/unknown
- 3Com Boomerang (unknown version)
Module parameters
If you are using the PCMCIA tools (cardmgr) then the options may be
placed in /etc/pcmcia/config.opts:
-module "3c59x" opts "debug=3 extra_reset=1"
+module "3c59x" opts "debug=3 rx_copybreak=300"
The supported parameters are:
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
- 16 (0x10) Bus-master enable bit (Old Vortex cards only)
+ 512 (0x200) Force full duplex mode.
+ 16 (0x10) Bus-master enable bit (Old Vortex cards only)
For example:
Similar to bit 9 of 'options'. Forces the corresponding card into
full-duplex mode.
+flow_ctrl=N1,N2,N3...
+
+ Use 802.3x MAC-layer flow control. The 3com cards only support the
+ PAUSE command, which means that they will stop sending packets for a
+ short period if they receive a PAUSE frame from the link partner.
+
+ The driver only allows flow control on a link which is operating in
+ full duplex mode.
+
+ This feature does not appear to work on the 3c905 - only 3c905B and
+ 3c905C have been tested.
+
+ The 3com cards appear to only respond to PAUSE frames which are
+ sent to the reserved destination address of 01:80:c2:00:00:01. They
+ do not honour PAUSE frames which are sent to the station MAC address.
+
rx_copybreak=M
The driver preallocates 32 full-sized (1536 byte) network buffers
is exceeded the interrupt service routine gives up and generates a
warning message "eth0: Too much work in interrupt".
-extra_reset=N
-
- Where N is 0 or 1 (default 0).
-
- Some network cards (notably 3CCFE575CT Cardbus) do not initialise
- correctly and need an extra transmitter reset. If you find that the
- card comes up receiving but not transmitting, try giving the module
- the 'extra_reset=1' option.
-
compaq_ioaddr=N
compaq_irq=N
compaq_device_id=N
Reporting and diagnosing problems
---------------------------------
-If the driver plays up, there are a number of things you can do analyse
-the problem and to help others do this:
+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.rutgers.edu. 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 <unassigned> [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
-- Turn on debugging in the driver
- Add 'debug=7' to /etc/modules.conf (/etc/conf.modules)
- Change 'vortex_debug' to 7 in the source code.
+ (The above may vary, depending upon which Linux distribution you use).
-- Send all kernel logs, starting with the first probe of the card.
+ o If your problem is reproducible then that's great. Try the
+ following:
-- Run 'mii-diag -v' to show the state of the Media Independent
- Interface. If the card sometimes works and sometimes doesn't, run
- 'mii-diag -v' in both states.
+ 1) Increase the debug level. Usually this is done via:
-- Please run 'vortex-diag -aaee' in both good and bad states. This
- show the NIC's registers and EEPROM contents.
+ a) modprobe driver.o debug=7
+ b) In /etc/conf.modules (or modules.conf):
+ options driver_name debug=7
-- Describe your setup: 10baseT, 100baseT, full/half duplex, etc.
+ 2) Recreate the problem with the higher debug level,
+ send all logs to the maintainer.
-- Note any additional module insertion commands you're using.
+ 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.
-- Try different media type settings (see above).
+ a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is
+ working correctly. Save the output.
-- Try inserting the module with 'extra_reset=1' (or compile this into
- the driver).
+ 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.
Digi AccelePort Driver
- This driver supports the Digi AccelePort USB 4 device, a 4 port
- USB serial converter. The driver does NOT yet support the Digi
- AccelePort USB 2 or 8.
-
- The driver supports open, close, read, write, termios settings (baud
- rate, word size, parity, stop bits, hardware/software flow control,
- CREAD), DTR/RTS, and TIOCMGET/SET/BIS/BIC ioctls. It has not been
- thoroughly tested, but it seems to be working reasonable well. There
- is more work to do, including flow control, ioctls, and support for
- the Digi AccelePort USB 2 and 8.
+ This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port
+ (plus a parallel port) and 4 port USB serial converters. The driver
+ does NOT yet support the Digi AccelePort USB 8.
+
+ The driver is generally working, though we still have a few more ioctls
+ to implement and final testing and debugging to do. The paralled port
+ on the USB 2 is supported as a serial to parallel converter; in other
+ words, it appears as another USB serial port on Linux, even though
+ physically it is really a parallel port. The Digi Acceleport USB 8
+ is not yet supported.
Please contact Peter Berger (pberger@brimson.com) or Al Borchers
(alborchers@steinerpoint.com) for questions or problems with this
#
# Special variables which should not be exported
#
-unexport EXTRA_ASFLAGS
+unexport EXTRA_AFLAGS
unexport EXTRA_CFLAGS
unexport EXTRA_LDFLAGS
unexport EXTRA_ARFLAGS
) > $(dir $@)/.$(notdir $@).flags
%.o: %.s
- $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $<
+ $(AS) $(AFLAGS) $(EXTRA_CFLAGS) -o $@ $<
+
+# Old makefiles define their own rules for compiling .S files,
+# but these standard rules are available for any Makefile that
+# wants to use them. Our plan is to incrementally convert all
+# the Makefiles to these standard rules. -- rmk, mec
+ifdef USE_STANDARD_AS_RULE
+
+%.s: %.S
+ $(CPP) $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$@) $< > $@
+
+%.o: %.S
+ $(CC) $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$@) -c -o $@ $<
+
+endif
#
#
#
ifeq ($(NEW_GCC),y)
CFLAGS += -mshort-load-bytes
-CFLAGS_PROC_CPU_26 := -mcpu=arm3 -Os
+CFLAGS_PROC_CPU_26 := -mcpu=arm3 -mapcs-26 -Os
CFLAGS_PROC_CPU_32v3 := -march=armv3
CFLAGS_PROC_CPU_32v4 := -march=armv4
CFLAGS_ARM6 := -mtune=arm6
HEAD := arch/arm/kernel/head-$(PROCESSOR).o \
arch/arm/kernel/init_task.o
SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \
- arch/arm/special arch/arm/nwfpe
+ arch/arm/nwfpe
CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC)
-DRIVERS += arch/arm/special/special.a
ifeq ($(CONFIG_NWFPE),y)
LIBS := arch/arm/nwfpe/math-emu.o $(LIBS)
# The following is a hack to get 'constants.h' up
# to date before starting compilation
-$(patsubst %, _dir_%, $(SUBDIRS)) : constants
+$(patsubst %, _dir_%, $(SUBDIRS)) init/main.o init/version.o : \
+ constants \
+ include/asm-arm/mach-types.h
+
+include/asm-arm/mach-types.h: \
+ arch/arm/tools/mach-types \
+ arch/arm/tools/gen-mach-types
+ @awk -f arch/arm/tools/gen-mach-types arch/arm/tools/mach-types > $@
constants: $(TOPDIR)/include/asm-arm/proc-fns.h dummy
@$(MAKE) -C arch/arm/lib constants.h
arch/arm/lib: dummy
$(MAKE) linuxsubdirs SUBDIRS=arch/arm/lib
-zImage zinstall Image install: vmlinux
+bzImage zImage zinstall Image bootpImage install: vmlinux
@$(MAKEBOOT) $@
archmrproper:
- @$(MAKE) -C arch/$(ARCH)/special mrproper
$(RM) include/asm-arm/arch include/asm-arm/proc
archclean:
@$(MAKEBOOT) clean
$(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds
+ $(RM) include/asm-arm/mach-types.h
archdep: symlinks
@$(MAKEBOOT) dep
#
# Configuration targets. Use these to select a
# configuration for your architecture
-#
-a5k_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/a5k arch/arm/defconfig
-
-ebsa110_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/ebsa110 arch/arm/defconfig
-
-footbridge_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/footbridge arch/arm/defconfig
-
-rpc_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/rpc arch/arm/defconfig
-
-brutus_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/brutus arch/arm/defconfig
-
-victor_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/victor arch/arm/defconfig
-
-empeg_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/empeg arch/arm/defconfig
-
-thinclient_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/thinclient arch/arm/defconfig
-
-assabet_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/assabet arch/arm/defconfig
-
-lart_config:
- $(RM) arch/arm/defconfig
- cp arch/arm/def-configs/lart arch/arm/defconfig
+CFGS= a5k_config ebsa110_config \
+ footbridge_config rpc_config \
+ brutus_config victor_config \
+ empeg_config thinclient_config \
+ assabet_config lart_config \
+ cerf_config
+
+$(CFGS):
+ @( \
+ CFG=$(@:_config=); \
+ if [ -f arch/arm/def-configs/$$CFG ]; then \
+ $(RM) arch/arm/defconfig; \
+ cp arch/arm/def-configs/$$CFG arch/arm/defconfig; \
+ echo "*** Default configuration for $$CFG installed"; \
+ echo "*** Next, you may run 'make oldconfig'"; \
+ else \
+ echo "$$CFG does not exist"; \
+ fi; \
+ )
l7200_config:
$(RM) arch/arm/defconfig
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
-# Copyright (C) 1995, 1996 Russell King
+# Copyright (C) 1995-2000 Russell King
#
SYSTEM =$(TOPDIR)/vmlinux
+ifeq ($(CONFIG_CPU_26),y)
+ZTEXTADDR = 0x02080000
+PARAMS_PHYS = 0x0207c000
+INITRD_PHYS = 0x02180000
+INITRD_VIRT = 0x02180000
+endif
+
+ifeq ($(CONFIG_ARCH_RPC),y)
+ZTEXTADDR = 0x10008000
+PARAMS_PHYS = 0x10000100
+INITRD_PHYS = 0x18000000
+INITRD_VIRT = 0xc8000000
+endif
+
+ifeq ($(CONFIG_ARCH_CLPS7500),y)
+ZTEXTADDR = 0x10008000
+endif
+
+ifeq ($(CONFIG_ARCH_EBSA110),y)
+ZTEXTADDR = 0x00008000
+PARAMS_PHYS = 0x00000400
+INITRD_PHYS = 0x00800000
+INITRD_VIRT = 0xc0800000
+endif
+
+ifeq ($(CONFIG_FOOTBRIDGE),y)
+ZTEXTADDR = 0x00008000
+PARAMS = 0x00000100
+INITRD_PHYS = 0x00800000
+INITRD_VIRT = 0xc0800000
+endif
+
+ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
+ZTEXTADDR = 0x40200000
+ZRELADDR = 0x40008000
+endif
+
+ifeq ($(CONFIG_ARCH_L7200),y)
+# RAM based kernel
+#ZTEXTADDR = 0xf0400000
+#ZRELADDR = 0xf0008000
+
+# FLASH based kernel
+ZTEXTADDR = 0x00010000
+ZRELADDR = 0xf0008000
+ZBSSADDR = 0xf03e0000
+endif
+
+ifeq ($(CONFIG_ARCH_SA1100),y)
+ZTEXTADDR = 0xc0008000
+ZRELADDR = 0xc0008000
+ifeq ($(CONFIG_SA1100_VICTOR),y)
+ ZTEXTADDR = 0x00002000
+ ZBSSADDR = 0xc0100000
+endif
+ifeq ($(CONFIG_SA1100_THINCLIENT),y)
+ ZTEXTADDR = 0xC0200000
+endif
+ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
+ ZTEXTADDR = 0xC0200000
+endif
+endif
+
+#
+# If you don't define ZRELADDR above,
+# then it defaults to ZTEXTADDR
+#
+ifeq ($(ZRELADDR),)
+ZRELADDR = $(ZTEXTADDR)
+endif
+
+export SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS INITRD_VIRT PARAMS_PHYS
+
Image: $(CONFIGURE) $(SYSTEM)
$(OBJCOPY) $(SYSTEM) $@
+bzImage: zImage
+
zImage: $(CONFIGURE) compressed/vmlinux
$(OBJCOPY) compressed/vmlinux $@
+bootpImage: bootp/bootp
+ $(OBJCOPY) bootp/bootp $@
+
compressed/vmlinux: $(TOPDIR)/vmlinux dep
@$(MAKE) -C compressed vmlinux
+bootp/bootp: zImage initrd
+ @$(MAKE) -C bootp bootp
+
+initrd:
+ @test "$(INITRD_VIRT)" != "" || (echo This architecture does not support INITRD; exit -1)
+ @test "$(INITRD)" != "" || (echo You must specify INITRD; exit -1)
+
install: $(CONFIGURE) Image
sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)"
sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
clean:
- rm -f Image zImage
+ $(RM) Image zImage bootpImage
@$(MAKE) -C compressed clean
+ @$(MAKE) -C bootp clean
dep:
--- /dev/null
+#
+# linux/arch/arm/boot/bootp/Makefile
+#
+
+ZSYSTEM =$(TOPDIR)/arch/arm/boot/zImage
+INITRD =$(ZSYSTEM)
+ZLDFLAGS =-p -X -T bootp.lds \
+ --defsym initrd_addr=$(INITRD_PHYS) \
+ --defsym initrd_virt=$(INITRD_VIRT) \
+ --defsym params=$(PARAMS_PHYS)
+
+all: bootp
+
+# Note that bootp.lds picks up kernel.o and initrd.o
+bootp: init.o kernel.o initrd.o bootp.lds
+ $(LD) $(ZLDFLAGS) -o $@ init.o
+
+kernel.o: $(ZSYSTEM)
+ $(LD) -r -s -o $@ -b binary $(ZSYSTEM)
+
+initrd.o: $(INITRD)
+ $(LD) -r -s -o $@ -b binary $(INITRD)
+
+.PHONY: $(INITRD) $(ZSYSTEM)
+
+clean:; $(RM) bootp bootp.lds
--- /dev/null
+/*
+ * Header file for splitting kernel + initrd. Note that we pass
+ * r0 through to r3 straight through.
+ */
+ .section .start,#alloc,#execinstr
+ .type _entry, #function
+_entry:
+kernel_addr: adr r10, initdata
+ ldmia r10, {r11, r12}
+ sub r11, r10, r11 @ work out exec offset
+ add r12, r12, r11 @ correct "splitify"
+ mov pc, r12 @ jump to splitify
+ .size _entry,. - _entry
+
+ .type initdata, #object
+initdata: .word initdata @ compiled address of this
+ .word splitify
+ .size initdata,. - initdata
+
+ .text
+splitify: adr r13, data
+ ldmia r13!, {r4-r6} @ move the kernel
+ add r4, r4, r11 @ correction
+ mov r12, r5
+ bl move
+
+ ldmia r13!, {r4-r6} @ then the initrd
+ add r4, r4, r11 @ correction
+ bl move
+
+ ldmib r13, {r5,r6,r7} @ get size and addr of initrd
+ add r7, r7, #16*4 @ offset of initrd_start in param_struct
+ stmia r7, {r5,r6} @ save in param_struct
+ mov pc, r12 @ call kernel
+
+move: ldmia r4!, {r7 - r10} @ move 32-bytes at a time
+ stmia r5!, {r7 - r10}
+ ldmia r4!, {r7 - r10}
+ stmia r5!, {r7 - r10}
+ subs r6, r6, #8 * 4
+ bcs move
+ mov pc, lr
+
+data: .word kernel_start
+ .word kernel_addr
+ .word kernel_len
+
+ .word initrd_start
+ .word initrd_addr
+ .word initrd_len
+
+ .word initrd_virt
+ .word initrd_len
+ .word params
+
+ .type kernel_start,#object
+ .type initrd_start,#object
# linux/arch/arm/boot/compressed/Makefile
#
# create a compressed vmlinuz image from the original vmlinux
+#
+# Note! SYSTEM, ZTEXTADDR, ZBSSADDR and ZRELADDR are now exported
+# from arch/arm/boot/Makefile
+#
HEAD = head.o
OBJS = misc.o
-SYSTEM = $(TOPDIR)/vmlinux
CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC)
FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c
ZLDFLAGS = -p -X -T vmlinux.lds
OBJS += ll_char_wr.o font.o
endif
-ifeq ($(CONFIG_CPU_26),y)
-ZTEXTADDR = 0x02080000
-endif
-
-ifeq ($(CONFIG_ARCH_RPC),y)
-ZTEXTADDR = 0x10008000
-endif
-
-ifeq ($(CONFIG_ARCH_CLPS7500),y)
-ZTEXTADDR = 0x10008000
-endif
-
-ifeq ($(CONFIG_ARCH_EBSA110),y)
-ZTEXTADDR = 0x00008000
-endif
-
-ifeq ($(CONFIG_FOOTBRIDGE),y)
-ZTEXTADDR = 0x00008000
-endif
-
ifeq ($(CONFIG_ARCH_NETWINDER),y)
OBJS += head-netwinder.o
endif
ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
HEAD = head-nexuspci.o
-ZTEXTADDR = 0x40200000
-ZRELADDR = 0x40008000
+endif
+
+ifeq ($(CONFIG_ARCH_L7200),y)
+OBJS += head-l7200.o
endif
ifeq ($(CONFIG_ARCH_SA1100),y)
OBJS += head-sa1100.o setup-sa1100.o
-ZTEXTADDR = 0xc0008000
-ZRELADDR = 0xc0008000
-ifeq ($(CONFIG_SA1100_VICTOR),y)
- ZTEXTADDR = 0x00002000
- ZBSSADDR = 0xc0100000
-endif
-ifeq ($(CONFIG_SA1100_THINCLIENT),y)
- ZTEXTADDR = 0xC0200000
-endif
-ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
- ZTEXTADDR = 0xC0200000
+ifeq ($(CONFIG_SA1100_NANOENGINE),y)
+ OBJS += hw-bse.o
endif
endif
-#
-# If you don't define ZRELADDR above,
-# then it defaults to ZTEXTADDR
-#
-ifeq ($(ZRELADDR),)
-ZRELADDR = $(ZTEXTADDR)
-endif
-
SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;
ifneq ($(ZBSSADDR),)
.PHONY: vmlinux.lds clean
misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c
+
+%.o: %.S
+ $(CC) $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$@) -c -o $@ $<
--- /dev/null
+/*
+ * linux/arch/arm/boot/compressed/head-l7200.S
+ *
+ * Copyright (C) 2000 Steve Hill <sjhill@cotw.com>
+ *
+ * Some code borrowed from Nicola Pitre's 'head-sa1100.S' file. This
+ * is merged with head.S by the linker.
+ */
+
+#include <linux/config.h>
+
+#ifndef CONFIG_ARCH_L7200
+#error What am I doing here...
+#endif
+
+ .section ".start", #alloc, #execinstr
+
+__L7200_start:
+
+ mov r0, #0x00100000 @ FLASH address of initrd
+ mov r2, #0xf1000000 @ RAM address of initrd
+ add r1, r2, #0x00700000 @ Size of initrd
+1:
+ ldmia r0!, {r3, r4, r5, r6}
+ stmia r2!, {r3, r4, r5, r6}
+ cmp r2, r1
+ ble 1b
+
+ mov r8, #0 @ Zero it out
+ mov r7, #19 @ Set architecture ID
+#define K(a,b,c) ((a) << 24 | (b) << 12 | (c))
+
.section ".start", #alloc, #execinstr
+ /*
+ * check to see if we are running from the correct address.
+ * If not, we move ourselves in a two stage process. Firstly,
+ * we copy the start of the kernel (which includes this code)
+ * to 0x8000, and then jump to this code to continue with the
+ * rest (since this code will get overwritten).
+ */
adr r2, 1f
- ldmdb r2, {r7, r8}
+ ldmdb r2, {r9, r10}
and r3, r2, #0xc000
- teq r3, #0x8000
- beq 2f
+ teq r3, #0x8000 @ correctly located?
+ beq 2f @ skip this code
bic r3, r2, #0xc000
orr r3, r3, #0x8000
- mov r0, r3
- mov r4, #64
- sub r5, r8, r7
+ mov r0, r3 @ new address if '1'
+ mov r4, #64 @ number of bytes to copy
+ sub r5, r10, r9 @ total number of bytes to copy
b 1f
.word _start
1:
.rept 4
- ldmia r2!, {r6, r7, r8, r9}
- stmia r3!, {r6, r7, r8, r9}
+ ldmia r2!, {r6, r9, r10, r11}
+ stmia r3!, {r6, r9, r10, r11}
.endr
subs r4, r4, #64
bcs 1b
- movs r4, r5
- mov r5, #0
- mov r1, #5 @ only here to fix NeTTroms which dont set r1
- movne pc, r0
-
- mov r0, #0
+ movs r4, r5 @ remaining length
+ mov r5, #0 @ no more to copy
+ movne pc, r0 @ jump back to 1 (in the newly copied
+ @ code)
+ mov r7, #5 @ only here to fix NeTTroms which dont
+ mov r8, #2 << 24 @ scheduled for removal in 2.5.xx
+ orr r8, r8, #5 << 12
2:
#include <linux/config.h>
#include <linux/linkage.h>
+#include <asm/mach-types.h>
#ifndef CONFIG_ARCH_SA1100
#error What am I doing here...
__SA1100_start:
- @ Preserve r0/r1 i.e. kernel entry values
- mov r8, r0
- mov r9, r1
-
-#if defined( CONFIG_SA1100_ASSABET ) || \
- defined( CONFIG_SA1100_BRUTUS ) || \
- defined( CONFIG_SA1100_THINCLIENT )
-@ Booting from Angel -- need to enter SVC mode
-#define angel_SWIreason_EnterSVC 0x17 /* from arm.h, in angel source */
-#define angel_SWI_ARM (0x123456)
- mov r0, #angel_SWIreason_EnterSVC
- swi #angel_SWI_ARM
-
- @ turn off interrupts to prevent the angel from running
- mrs r0, cpsr
- orr r0, r0, #0xc0
- msr cpsr_c, r0
-#endif
+ @ Preserve r8/r7 i.e. kernel entry values
#ifdef CONFIG_SA1100_VICTOR
- teq r9, #26 @ MACH_TYPE_VICTOR
+ teq r7, #MACH_TYPE_VICTOR
bne 10f
@ Copy cmdline to 0xc0000000
* Pause for a short time so that we give enough time
* for the host to start a terminal up.
*/
- mov r0, #0x02000000
+ mov r0, #0x00200000
1: subs r0, r0, #1
bne 1b
-
- @ Restore initial r0/r1
- mov r0, r8
- mov r1, r9
*
* Copyright (C) 1996-1999 Russell King
*/
+#include <linux/config.h>
#include <linux/linkage.h>
-
/*
* Debugging stuff
*/
b 1f
.word 0x016f2818 @ Magic numbers to help the loader
.word start
-1:
+1: mov r7, r1 @ save architecture ID
+ mov r8, r0 @ save r0
+#ifdef CONFIG_ANGELBOOT
+ /*
+ * Booting from Angel - need to enter SVC mode and disable
+ * FIQs/IRQs (numeric definitions from angel arm.h source)
+ */
+ mov r0, #0x17 @ angel_SWIreason_EnterSVC
+ swi 0x123456 @ angel_SWI_ARM
+ mrs r0, cpsr @ turn off interrupts to
+ orr r0, r0, #0xc0 @ prevent angel from running
+ msr cpsr_c, r0
+
+ /*
+ * Note that some cache flushing and other stuff may
+ * be needed here - is there an Angel SWI call for this?
+ */
+#endif
/*
* some architecture specific code can be inserted
- * by the linker here, but it should preserve r0, r1
- * and r8.
+ * by the linker here, but it should preserve r7 and r8.
*/
.text
-1: teq r0, #0
- bne 1b
- mov r7, r1 @ save architecture ID
- mrc p15, 0, r6, c0, c0 @ get processor ID
+1: mrc p15, 0, r6, c0, c0 @ get processor ID
adr r2, LC0
ldmia r2, {r2, r3, r4, r5, sp}
--- /dev/null
+/*
+ * Bright Star Engineering Inc.
+ *
+ * code for readng parameters from the
+ * parameter blocks of the boot block
+ * flash memory
+ *
+ */
+
+static int strcmp(const char *s1, const char *s2)
+{
+ while (*s1 != '\0' && *s1 == *s2)
+ {
+ s1++;
+ s2++;
+ }
+
+ return (*(unsigned char *) s1) - (*(unsigned char *) s2);
+}
+
+struct pblk_t {
+ char type;
+ unsigned short size;
+};
+
+static char *bse_getflashparam(char *name) {
+ unsigned int esize;
+ char *q,*r;
+ unsigned char *p,*e;
+ struct pblk_t *thepb = (struct pblk_t *) 0x00004000;
+ struct pblk_t *altpb = (struct pblk_t *) 0x00006000;
+ if (thepb->type&1) {
+ if (altpb->type&1) {
+ /* no valid param block */
+ return (char*)0;
+ } else {
+ /* altpb is valid */
+ struct pblk_t *tmp;
+ tmp = thepb;
+ thepb = altpb;
+ altpb = tmp;
+ }
+ }
+ p = (char*)thepb + sizeof(struct pblk_t);
+ e = p + thepb->size;
+ while (p < e) {
+ q = p;
+ esize = *p;
+ if (esize == 0xFF) break;
+ if (esize == 0) break;
+ if (esize > 127) {
+ esize = (esize&0x7F)<<8 | p[1];
+ q++;
+ }
+ q++;
+ r=q;
+ if (*r && ((name == 0) || (!strcmp(name,r)))) {
+ while (*q++) ;
+ return q;
+ }
+ p+=esize;
+ }
+ return (char*)0;
+}
+
+void bse_setup(void) {
+ /* extract the linux cmdline from flash */
+ char *name=bse_getflashparam("linuxboot");
+ char *x = (char *)0xc0000100;
+ if (name) {
+ while (*name) *x++=*name++;
+ }
+ *x=0;
+}
* Runtime test for Neponset added.
*/
-#define __ASSEMBLY__
#include <linux/linkage.h>
+#include <linux/config.h>
+#include <asm/mach-types.h>
.text
#define GPIO_2_9 0x3fc
+/*
+ * void sa1100_setup( int arch_id );
+ *
+ * This is called from decompress_kernel() with the arch_decomp_setup() macro.
+ */
+
ENTRY(sa1100_setup)
mov r3, r0 @ keep machine type in r3
@ (taken from "Intel StrongARM SA-1110 Microprocessor Development Board
@ User's Guide," p.4-9)
- teq r3, #25 @ MACH_TYPE_ASSABET
+ teq r3, #MACH_TYPE_ASSABET
bne skip_SCR
ldr r0, GPIO_BASE
skip_SCR:
@ Initialize UART (if bootloader has not done it yet)...
- teq r3, #16 @ MACH_TYPE_BRUTUS
- teqne r3, #25 @ MACH_TYPE_ASSABET
+ teq r3, #MACH_TYPE_BRUTUS
+ teqne r3, #MACH_TYPE_ASSABET
bne skip_uart
@ UART3 if Assabet is used with Neponset
@ At least for Brutus, the UART1 is used through
@ the alternate GPIO function...
- teq r3, #16 @ MACH_TYPE_BRUTUS
+ teq r3, #MACH_TYPE_BRUTUS
bne uart1
alt_GPIO_uart: ldr r0, GPIO_BASE
mov r1, #0xff @ flush status reg
str r1, [r0, #UTSR0]
skip_uart:
+
+ @ Extra specific setup calls
+ @ The machine type is passed in r0
+ mov r0, r3
+#ifdef CONFIG_SA1100_NANOENGINE
+ teq r0, #32 @ MACH_TYPE_NANOENGINE
+ beq SYMBOL_NAME(bse_setup)
+#endif
+
out: mov pc, lr
choice 'ARM system type' \
"Archimedes/A5000 CONFIG_ARCH_ARCA5K \
+ Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \
Co-EBSA285 CONFIG_ARCH_CO285 \
EBSA-110 CONFIG_ARCH_EBSA110 \
FootBridge CONFIG_ARCH_FOOTBRIDGE \
bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET
fi
bool ' Include support for Brutus' CONFIG_SA1100_BRUTUS
+ bool ' Include support for CerfBoard' CONFIG_SA1100_CERF
bool ' Include support for Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY
# bool ' Include support for Empeg' CONFIG_SA1100_EMPEG
# bool ' Include support for Itsy' CONFIG_SA1100_ITSY
# bool ' Include support for PLEB' CONFIG_SA1100_PLEB
bool ' Include support for ThinClient' CONFIG_SA1100_THINCLIENT
bool ' Include support for GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT
+ bool ' Include support for nanoEngine' CONFIG_SA1100_NANOENGINE
bool ' Include support for Victor' CONFIG_SA1100_VICTOR
# bool ' Include support for Tifon' CONFIG_SA1100_TIFON
-# bool ' Include support for XP860' CONFIG_SA1100_XP860
+ bool ' Include support for XP860' CONFIG_SA1100_XP860
+
+ bool ' Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT
+
+ # Determine if SA1111 support is required
+ if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \
+ "$CONFIG_SA1100_XP860" = "y" ]; then
+ define_bool CONFIG_SA1111 y
+ fi
+fi
+
+# Definitions to make life easier
+if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \
+ "$CONFIG_ARCH_RPC" = "y" ]; then
+ define_bool CONFIG_ARCH_ACORN y
+else
+ define_bool CONFIG_ARCH_ACORN n
+fi
+
+# see Documentation/arm/ConfigVars for a description of these
+if [ "$CONFIG_ARCH_CO285" = "y" -o \
+ "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then
+ define_bool CONFIG_FOOTBRIDGE y
+else
+ define_bool CONFIG_FOOTBRIDGE n
+fi
+if [ "$CONFIG_ARCH_CATS" = "y" -o \
+ "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \
+ "$CONFIG_ARCH_NETWINDER" = "y" -o \
+ "$CONFIG_ARCH_PERSONAL_SERVER" = "y" ]; then
+ define_bool CONFIG_FOOTBRIDGE_HOST y
+else
+ define_bool CONFIG_FOOTBRIDGE_HOST n
+fi
+if [ "$CONFIG_ARCH_CO285" = "y" -o \
+ "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then
+ define_bool CONFIG_FOOTBRIDGE_ADDIN y
+else
+ define_bool CONFIG_FOOTBRIDGE_ADDIN n
+fi
+if [ "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \
+ "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then
+ define_bool CONFIG_ARCH_EBSA285 y
fi
# Figure out whether this system uses 26-bit or 32-bit CPUs.
fi
# Select various configuration options depending on the machine type
-if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \
- "$CONFIG_ARCH_RPC" = "y" ]; then
- define_bool CONFIG_ARCH_ACORN y
-else
- define_bool CONFIG_ARCH_ACORN n
-fi
-
-if [ "$CONFIG_ARCH_CO285" = "y" -o \
- "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then
- define_bool CONFIG_FOOTBRIDGE y
-else
- define_bool CONFIG_FOOTBRIDGE n
-fi
-if [ "$CONFIG_ARCH_CATS" = "y" -o \
- "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \
- "$CONFIG_ARCH_NETWINDER" = "y" -o \
- "$CONFIG_ARCH_PERSONAL_SERVER" = "y" ]; then
- define_bool CONFIG_FOOTBRIDGE_HOST y
-else
- define_bool CONFIG_FOOTBRIDGE_HOST n
-fi
-if [ "$CONFIG_ARCH_CO285" = "y" -o \
- "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then
- define_bool CONFIG_FOOTBRIDGE_ADDIN y
-else
- define_bool CONFIG_FOOTBRIDGE_ADDIN n
-fi
-if [ "$CONFIG_ARCH_EBSA285_HOST" = "y" -o \
- "$CONFIG_ARCH_EBSA285_ADDIN" = "y" ]; then
- define_bool CONFIG_ARCH_EBSA285 y
-fi
-
if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
define_bool CONFIG_DISCONTIGMEM y
else
define_bool CONFIG_ISA n
define_bool CONFIG_ISA_DMA n
fi
+
+# Do we have a PC-type keyboard in this architecture?
+if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then
+ define_bool CONFIG_PC_KEYB y
+ define_bool CONFIG_PC_KEYMAP y
+fi
+if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then
+ define_bool CONFIG_PC_KEYMAP y
+fi
endmenu
mainmenu_option next_comment
fi
if [ "$CONFIG_ARCH_EBSA110" = "y" -o \
"$CONFIG_ARCH_SA1100" = "y" -o \
+ "$CONFIG_ARCH_CLPS7500" = "y" -o \
"$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \
"$CONFIG_ARCH_CATS" = "y" ]; then
string 'Default kernel command string' CONFIG_CMDLINE ""
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
+USE_STANDARD_AS_RULE := true
+
HEAD_OBJ = head-$(PROCESSOR).o
ENTRY_OBJ = entry-$(PROCESSOR).o
+AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
+AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional
+
O_OBJS_arc = dma-arc.o oldlatches.o
O_OBJS_rpc = dma-rpc.o
O_OBJS_footbridge = dma-footbridge.o hw-footbridge.o isa.o
all: kernel.o $(HEAD_OBJ) init_task.o
-$(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
- $(CC) $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
-
include $(TOPDIR)/Rules.make
-.S.o:
- $(CC) $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $<
-
# Spell out some dependencies that `make dep' doesn't spot
entry-armv.o: calls.S ../lib/constants.h
entry-armo.o: calls.S ../lib/constants.h
#include <asm/dec21285.h>
#include <asm/elf.h>
#include <asm/setup.h>
-#include <asm/system.h>
+#include <asm/mach-types.h>
#include "arch.h"
while (1);
}
+
+static void xp860_power_off(void)
+{
+ GPDR |= GPIO_GPIO20;
+ GPSR = GPIO_GPIO20;
+ mdelay(1000);
+ GPCR = GPIO_GPIO20;
+ while(1);
+}
+
+
extern void select_sa1100_io_desc(void);
#define SET_BANK(__nr,__start,__size) \
mi->bank[__nr].start = (__start), \
setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 );
}
+ else if (machine_is_cerf()) {
+ // 16Meg Ram.
+ SET_BANK( 0, 0xc0000000, 8*1024*1024 );
+ SET_BANK( 1, 0xc8000000, 8*1024*1024 ); // comment this out for 8MB Cerfs
+ mi->nr_banks = 2;
+
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ setup_ramdisk(1, 0, 0, 8192);
+ // Save 2Meg for RAMDisk
+ setup_initrd(0xc0500000, 3*1024*1024);
+ }
+
else if (machine_is_empeg()) {
SET_BANK( 0, 0xc0000000, 4*1024*1024 );
SET_BANK( 1, 0xc8000000, 4*1024*1024 );
setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
}
+ else if (machine_is_nanoengine()) {
+ SET_BANK( 0, 0xc0000000, 32*1024*1024 );
+ mi->nr_banks = 1;
+
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+ setup_ramdisk( 1, 0, 0, 8192 );
+ setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 );
+
+ /* Get command line parameters passed from the loader (if any) */
+ if( *((char*)0xc0000100) )
+ *cmdline = ((char *)0xc0000100);
+ }
else if (machine_is_tifon()) {
SET_BANK( 0, 0xc0000000, 16*1024*1024 );
SET_BANK( 1, 0xc8000000, 16*1024*1024 );
pm_power_off = victor_power_off;
}
+ else if (machine_is_xp860()) {
+ SET_BANK( 0, 0xc0000000, 32*1024*1024 );
+ mi->nr_banks = 1;
+
+ pm_power_off = xp860_power_off;
+ }
}
#ifdef CONFIG_SA1100_ASSABET
FIXUP(fixup_sa1100)
MACHINE_END
#endif
+#ifdef CONFIG_SA1100_CERF
+MACHINE_START(CERF, "Intrinsyc CerfBoard")
+ MAINTAINER("Pieter Truter")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
#ifdef CONFIG_SA1100_EMPEG
MACHINE_START(EMPEG, "empeg MP3 Car Audio Player")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
FIXUP(fixup_sa1100)
MACHINE_END
#endif
+#ifdef CONFIG_SA1100_NANOENGINE
+MACHINE_START(NANOENGINE, "BSE nanoEngine")
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sa1100)
+MACHINE_END
+#endif
#ifdef CONFIG_SA1100_PLEB
MACHINE_START(PLEB, "PLEB")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
+#include <asm/mach-types.h>
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
EXPORT_SYMBOL(__arch_copy_to_user);
EXPORT_SYMBOL(__arch_clear_user);
EXPORT_SYMBOL(__arch_strnlen_user);
-#elif defined(CONFIG_CPU_26)
-EXPORT_SYMBOL(uaccess_kernel);
-EXPORT_SYMBOL(uaccess_user);
-#endif
/* consistent area handling */
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(consistent_free);
EXPORT_SYMBOL(consistent_sync);
+#elif defined(CONFIG_CPU_26)
+EXPORT_SYMBOL(uaccess_kernel);
+EXPORT_SYMBOL(uaccess_user);
+#endif
+
/* gcc lib functions */
EXPORT_SYMBOL_NOVERS(__gcc_bcmp);
EXPORT_SYMBOL_NOVERS(__ashldi3);
#include <linux/init.h>
#include <asm/irq.h>
-#include <asm/system.h>
+#include <asm/mach-types.h>
#include "bios32.h"
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
- unsigned long where, size;
- u32 reg;
+ u32 val, check;
+ int reg;
if (debug_pci)
printk("PCI: Assigning %3s %08lx to %s\n",
res->flags & IORESOURCE_IO ? "IO" : "MEM",
res->start, dev->name);
- where = PCI_BASE_ADDRESS_0 + resource * 4;
- size = res->end - res->start;
-
- pci_read_config_dword(dev, where, ®);
- reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
- pci_write_config_dword(dev, where, reg);
+ val = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+ if (resource < 6) {
+ reg = PCI_BASE_ADDRESS_0 + 4*resource;
+ } else if (resource == PCI_ROM_RESOURCE) {
+ res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ val |= PCI_ROM_ADDRESS_ENABLE;
+ reg = dev->rom_base_reg;
+ } else {
+ /* Somebody might have asked allocation of a
+ * non-standard resource.
+ */
+ return;
+ }
+ pci_write_config_dword(dev, reg, val);
+ pci_read_config_dword(dev, reg, &check);
+ if ((val ^ check) & ((val & PCI_BASE_ADDRESS_SPACE_IO) ?
+ PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+ printk(KERN_ERR "PCI: Error while updating region "
+ "%s/%d (%08x != %08x)\n", dev->slot_name,
+ resource, val, check);
+ }
}
void __init pcibios_update_irq(struct pci_dev *dev, int irq)
#elif defined(CONFIG_ARCH_L7200)
- .macro addruart,rx
+ .equ io_virt, IO_BASE
+ .equ io_phys, IO_START
+ .macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
- moveq \rx, #0x80000000 @ physical base address
- movne \rx, #0xd0000000 @ virtual address
+ moveq \rx, #io_phys @ physical base address
+ movne \rx, #io_virt @ virtual address
add \rx, \rx, #0x00044000 @ Ser1
@ add \rx, \rx, #0x00045000 @ Ser2
.endm
cfn_mode = __footbridge_cfn_mode();
- printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX in "
+ printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in "
"%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ?
"central function" : "addin");
#include <asm/fiq.h>
#include <asm/io.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include "dma.h"
/*
* This is virtual DMA - we don't need anything here.
*/
-static int sound_enable_disable_dma(dmach_t channel, dma_t *dma)
+static void sound_enable_disable_dma(dmach_t channel, dma_t *dma)
{
}
return -EINVAL;
}
-static int no_dma(void)
+int get_dma_residue(dmach_t channel)
{
return 0;
}
#define GLOBAL_ALIAS(_a,_b) asm (".set " #_a "," #_b "; .globl " #_a)
-GLOBAL_ALIAS(disable_dma, no_dma);
-GLOBAL_ALIAS(enable_dma, no_dma);
-GLOBAL_ALIAS(free_dma, no_dma);
-GLOBAL_ALIAS(get_dma_residue, no_dma);
-GLOBAL_ALIAS(get_dma_list, no_dma);
-GLOBAL_ALIAS(set_dma_mode, no_dma);
-GLOBAL_ALIAS(set_dma_page, no_dma);
-GLOBAL_ALIAS(set_dma_count, no_dma);
-GLOBAL_ALIAS(set_dma_addr, no_dma);
-GLOBAL_ALIAS(set_dma_sg, no_dma);
-GLOBAL_ALIAS(set_dma_speed, no_dma);
-GLOBAL_ALIAS(init_dma, no_dma);
+GLOBAL_ALIAS(disable_dma, get_dma_residue);
+GLOBAL_ALIAS(enable_dma, get_dma_residue);
+GLOBAL_ALIAS(free_dma, get_dma_residue);
+GLOBAL_ALIAS(get_dma_list, get_dma_residue);
+GLOBAL_ALIAS(set_dma_mode, get_dma_residue);
+GLOBAL_ALIAS(set_dma_page, get_dma_residue);
+GLOBAL_ALIAS(set_dma_count, get_dma_residue);
+GLOBAL_ALIAS(set_dma_addr, get_dma_residue);
+GLOBAL_ALIAS(set_dma_sg, get_dma_residue);
+GLOBAL_ALIAS(set_dma_speed, get_dma_residue);
+GLOBAL_ALIAS(init_dma, get_dma_residue);
#endif
* Set up the expansion card
* daemon's environment.
*/
-static void
-ecard_init_task(void)
+static void ecard_init_task(int force)
{
/* We want to set up the page tables for the following mapping:
* Virtual Physical
pgd_t *src_pgd, *dst_pgd;
unsigned int dst_addr = IO_START;
- exec_mmap();
+ if (!force)
+ exec_mmap();
src_pgd = pgd_offset(current->mm, IO_BASE);
dst_pgd = pgd_offset(current->mm, dst_addr);
static int
ecard_task(void * unused)
{
- current->session = 1;
- current->pgrp = 1;
+ struct task_struct *tsk = current;
+
+ tsk->session = 1;
+ tsk->pgrp = 1;
/*
* We don't want /any/ signals, not even SIGKILL
*/
- sigfillset(¤t->blocked);
- sigemptyset(¤t->signal);
+ sigfillset(&tsk->blocked);
+ sigemptyset(&tsk->signal);
+ recalc_sigpending(tsk);
- strcpy(current->comm, "kecardd");
+ strcpy(tsk->comm, "kecardd");
/*
* Set up the environment
*/
- ecard_init_task();
+ ecard_init_task(0);
while (1) {
struct ecard_request *req;
req = xchg(&ecard_req, NULL);
if (req == NULL) {
- sigemptyset(¤t->signal);
+ sigemptyset(&tsk->signal);
interruptible_sleep_on(&ecard_wait);
}
} while (req == NULL);
*/
if ((current == &init_task || in_interrupt()) &&
req->req == req_reset && req->ec == NULL) {
- ecard_init_task();
+ ecard_init_task(1);
ecard_task_reset(req);
} else {
if (ecard_pid <= 0)
.text
-@ Offsets into task structure
-@ ---------------------------
-@
-#define STATE 0
-#define COUNTER 4
-#define PRIORITY 8
-#define FLAGS 12
-#define SIGPENDING 16
-
-#define PF_TRACESYS 0x20
-
@ Bad Abort numbers
@ -----------------
@
#define BAD_IRQ 3
#define BAD_UNDEFINSTR 4
-@ OS version number used in SWIs
-@ RISC OS is 0
-@ RISC iX is 8
-@
-#define OS_NUMBER 9
-
@
@ Stack format (ensured by USER_* and SVC_*)
@
orr lr, lr, #0x08000003 @ Force SVC
bne do_IRQ
mov r4, #0
+ get_current_task r5
b ret_with_reschedule
irq_prio_table
.text
-#define PT_TRACESYS 0x00000002
-
@ Bad Abort numbers
@ -----------------
@
#define BAD_IRQ 3
#define BAD_UNDEFINSTR 4
-@ OS version number used in SWIs
-@ RISC OS is 0
-@ RISC iX is 8
-@
-#define OS_NUMBER 9
-
@
@ Stack format (ensured by USER_* and SVC_*)
@
.endm
#elif defined(CONFIG_ARCH_L7200)
-/* Don't use fast interrupts */
+
+ .equ irq_base_addr, IO_BASE_2
+
.macro disable_fiq
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base
- ldr r4, =0xe0001000 @ Virt addr status reg
+ mov r4, #irq_base_addr @ Virt addr IRQ regs
+ add r4, r4, #0x00001000 @ Status reg
ldr \irqstat, [r4] @ get interrupts
mov \irqnr, #0
1001: tst \irqstat, #1
@
bne do_IRQ
mov r4, #0
+ get_current_task r5
b ret_with_reschedule
.align 5
#include <linux/config.h>
+
+#define PT_TRACESYS 0x00000002
+
+@ OS version number used in SWIs
+@ RISC OS is 0
+@ RISC iX is 8
+@
+#define OS_NUMBER 9
+
/*============================================================================
* All exits to user mode from the kernel go through this code.
*/
add sp, sp, #S_OFF
ret_from_sys_call: @ external entry
get_softirq r0
+ get_current_task r5
ldmia r0, {r0, r1} @ softirq_active, softirq_mask
mov r4, #1 @ flag this as being syscall return
tst r0, r1
blne SYMBOL_NAME(do_softirq)
-ret_with_reschedule: @ external entry (__irq_usr)
- get_current_task r5
+ret_with_reschedule: @ external entry (r5 must be set) (__irq_usr)
ldr r0, [r5, #TSK_NEED_RESCHED]
ldr r1, [r5, #TSK_SIGPENDING]
teq r0, #0
bne ret_reschedule
teq r1, #0 @ check for signals
- bne ret_signal
-
+ blne ret_signal
ret_from_all: restore_user_regs @ internal
ret_signal: mov r1, sp @ internal
- adrsvc al, lr, ret_from_all
mov r2, r4
- b SYMBOL_NAME(do_signal)
+ b SYMBOL_NAME(do_signal) @ note the bl above sets lr
ret_reschedule: adrsvc al, lr, ret_with_reschedule @ internal
b SYMBOL_NAME(schedule)
.globl ret_from_exception
ret_from_exception: @ external entry
get_softirq r0
+ get_current_task r5
ldmia r0, {r0, r1} @ softirq_active, softirq_mask
mov r4, #0
tst r0, r1
+ ldr r6, [sp, #S_PSR]
blne SYMBOL_NAME(do_softirq)
- ldr r0, [sp, #S_PSR]
- tst r0, #3 @ returning to user mode?
+ tst r6, #3 @ returning to user mode?
beq ret_with_reschedule
b ret_from_all
return 0;
}
-static struct fiq_handler default_owner =
- { NULL, "default", fiq_def_op, NULL };
+static struct fiq_handler default_owner = {
+ name: "default",
+ fiq_op: fiq_def_op,
+};
+
static struct fiq_handler *current_fiq = &default_owner;
int get_fiq_list(char *buf)
/*
* linux/arch/arm/kernel/head-armo.S
*
- * Copyright (C) 1994, 1995, 1996, 1997 Russell King
+ * Copyright (C) 1994-2000 Russell King
*
* 26-bit kernel startup code
*/
+#include <linux/config.h>
#include <linux/linkage.h>
+#include <asm/mach-types.h>
.globl SYMBOL_NAME(swapper_pg_dir)
.equ SYMBOL_NAME(swapper_pg_dir), 0x0207d000
ENTRY(stext)
ENTRY(_stext)
__entry: cmp pc, #0x02000000
- ldrlt pc, LC1 @ if 0x01800000, call at 0x02080000
+ ldrlt pc, LC0 @ if 0x01800000, call at 0x02080000
teq r0, #0 @ Check for old calling method
- blne Loldparams @ Move page if old
- adr r5, LC0
- ldmia r5, {r5, r6, sl, sp} @ Setup stack
- mov r4, #0
-1: cmp r5, sl @ Clear BSS
- strcc r4, [r5], #4
+ blne oldparams @ Move page if old
+ adr r0, LC0
+ ldmib r0, {r2-r5, sp} @ Setup stack
+ mov r0, #0
+1: cmp r2, r3 @ Clear BSS
+ strcc r0, [r2], #4
bcc 1b
- mov r0, #0xea000000 @ Point undef instr to continuation
- adr r5, Lcontinue - 12
- orr r5, r0, r5, lsr #2
- str r5, [r4, #4]
- mov r2, r4
- ldr r5, Larm2_id
- swp r0, r0, [r2] @ check for swp (ARM2 can't)
- ldr r5, Larm250_id
- mrc 15, 0, r0, c0, c0 @ check for CP#15 (ARM250 can't)
- mov r5, r0 @ Use processor ID if we do have CP#15
-Lcontinue: str r5, [r6]
- mov r5, #0xeb000000 @ Point undef instr vector to itself
- sub r5, r5, #2
- str r5, [r4, #4]
+
+ bl detect_proc_type
+ str r0, [r4]
+ bl detect_arch_type
+ str r0, [r5]
+
mov fp, #0
b SYMBOL_NAME(start_kernel)
-LC1: .word SYMBOL_NAME(_stext)
-LC0: .word SYMBOL_NAME(__bss_start)
- .word SYMBOL_NAME(processor_id)
- .word SYMBOL_NAME(_end)
- .word SYMBOL_NAME(init_task_union)+8192
-Larm2_id: .long 0x41560200
-Larm250_id: .long 0x41560250
+LC0: .word SYMBOL_NAME(_stext)
+ .word SYMBOL_NAME(__bss_start) @ r2
+ .word SYMBOL_NAME(_end) @ r3
+ .word SYMBOL_NAME(processor_id) @ r4
+ .word SYMBOL_NAME(__machine_arch_type) @ r5
+ .word SYMBOL_NAME(init_task_union)+8192 @ sp
+arm2_id: .long 0x41560200
+arm250_id: .long 0x41560250
.align
-Loldparams: mov r4, #0x02000000
+oldparams: mov r4, #0x02000000
add r3, r4, #0x00080000
add r4, r4, #0x0007c000
1: ldmia r0!, {r5 - r12}
stmia r4!, {r5 - r12}
cmp r4, r3
blt 1b
- movs pc, lr
+ mov pc, lr
+
+/*
+ * We need some way to automatically detect the difference between
+ * these two machines. Unfortunately, it is not possible to detect
+ * the presence of the SuperIO chip, because that will hang the old
+ * Archimedes machines solid.
+ */
+/* DAG: Outdated, these have been combined !!!!!!! */
+detect_arch_type:
+#if defined(CONFIG_ARCH_ARC)
+ mov r0, #MACH_TYPE_ARCHIMEDES
+#elif defined(CONFIG_ARCH_A5K)
+ mov r0, #MACH_TYPE_A5K
+#endif
+ mov pc, lr
+
+detect_proc_type:
+ mov r2, #0xea000000 @ Point undef instr to continuation
+ adr r0, continue - 12
+ orr r0, r2, r0, lsr #2
+ mov r1, #0
+ str r0, [r1, #4]
+ ldr r0, arm2_id
+ swp r2, r2, [r1] @ check for swp (ARM2 can't)
+ ldr r0, arm250_id
+ mrc 15, 0, r0, c0, c0 @ check for CP#15 (ARM250 can't)
+continue: mov r2, #0xeb000000 @ Make undef vector loop
+ sub r2, r2, #2
+ str r2, [r1, #4]
+ mov pc, lr
#endif
#define SWAPPER_PGDIR_OFFSET 0x4000
+#define K(a,b,c) ((a) << 24 | (b) << 12 | (c))
.globl SYMBOL_NAME(swapper_pg_dir)
.equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x8000 + SWAPPER_PGDIR_OFFSET
.type stext, #function
ENTRY(stext)
ENTRY(_stext)
-
+/*
+ * Entry point. The general rules are:
+ * should be called with r0 == 0
+ * r1 contains the unique architecture number
+ * with MMU is off, I-cache may be on or off, D-cache should be off.
+ * See linux/arch/arm/kernel/arch.c and linux/include/asm-arm/system.h
+ * for the complete list of numbers for r1. If you require a new number,
+ * please follow the instructions given towards the end of
+ * linux/Documentation/arm/README.
+ */
+ mov r12, r0
+/*
+ * NOTE! Any code which is placed here should be done for one of
+ * the following reasons:
+ *
+ * 1. Compatability with old production boot firmware (ie, users
+ * actually have and are booting the kernel with the old firmware)
+ * and therefore will be eventually removed.
+ * 2. Cover the case when there is no boot firmware. This is not
+ * ideal, but in this case, it should ONLY set r0 and r1 to the
+ * appropriate value.
+ */
#ifdef CONFIG_ARCH_NETWINDER
/*
* Compatability cruft for old NetWinder NeTTroms. This
mov r5, #0
movne pc, r0
- mov r0, #0 @ catch old NeTTroms
mov r1, #5 @ (will go in 2.5)
+ mov r12, #2 << 24 @ scheduled for removal in 2.5.xx
+ orr r12, r12, #5 << 12
#endif
#ifdef CONFIG_ARCH_L7200
/*
* FIXME - No bootloader, so manually set 'r1' with our architecture number.
*/
- mov r0, #0
mov r1, #19
#endif
-/*
- * Entry point. Entry *must* be called with r0 == 0, with the MMU off.
- * r1 contains the unique architecture number. See
- * linux/arch/arm/kernel/arch.c and linux/include/asm-arm/system.h for
- * the complete list. If you require a new number, please follow the
- * instructions given towards the end of Documentation/arm/README.
- */
-__entry: teq r0, #0 @ wrong register vals?
- movne r0, #'i' @ yes, error 'i'
- bne __error
- bl __lookup_processor_type
+__entry: bl __lookup_processor_type
teq r10, #0 @ invalid processor?
moveq r0, #'p' @ yes, error 'p'
beq __error
@ (return control reg)
__switch_data: .long __mmap_switched
+ .long SYMBOL_NAME(compat)
.long SYMBOL_NAME(__bss_start)
.long SYMBOL_NAME(_end)
.long SYMBOL_NAME(processor_id)
.align 5
__mmap_switched:
adr r3, __switch_data + 4
- ldmia r3, {r4, r5, r6, r7, r8, sp} @ r4 = __bss_start
+ ldmia r3, {r2, r4, r5, r6, r7, r8, sp}@ r2 = compat
@ sp = stack pointer
+ str r12, [r2]
mov fp, #0 @ Clear BSS
1: cmp r4, r5
#include <asm/io.h>
#include <asm/leds.h>
-#include <asm/system.h>
+#include <asm/mach-types.h>
#define IRDA_IO_BASE 0x180
#define GP1_IO_BASE 0x338
#include <asm/delay.h>
#include <asm/hardware.h>
-
+#include <asm/mach-types.h>
/*
* SA1100 GPIO edge detection for IRQs:
* any other SA-1111 functional blocks must be enabled separately
* using the SKPCR.
*/
+
+ {
+ /*
+ * SA1111 DMA bus master setup
+ */
+ int cas;
+
+ /* SA1111 side */
+ switch ( (MDCNFG>>12) & 0x03 ) {
+ case 0x02:
+ cas = 0; break;
+ case 0x03:
+ cas = 1; break;
+ default:
+ cas = 1; break;
+ }
+ SMCR = 1 /* 1: memory is SDRAM */
+ | ( 1 << 1 ) /* 1:MBGNT is enable */
+ | ( ((MDCNFG >> 4) & 0x07) << 2 ) /* row address lines */
+ | ( cas << 5 ); /* CAS latency */
+
+ /* SA1110 side */
+ GPDR |= 1<<21;
+ GPDR &= ~(1<<22);
+ GAFR |= ( (1<<21) | (1<<22) );
+
+ TUCR |= (1<<10);
+ }
}
#endif
-static void __init hw_sa1100_init(void)
+static int __init hw_sa1100_init(void)
{
if( machine_is_assabet() ){
if(machine_has_neponset()){
"hasn't been configured in the kernel\n" );
#endif
}
+ } else if (machine_is_xp860()) {
+ sa1111_init();
}
+ return 0;
}
module_init(hw_sa1100_init);
#include <asm/io.h>
#include <asm/system.h>
-#ifndef cliIF
-#define cliIF()
-#endif
-
/*
- * Maximum IRQ count. Currently, this is arbitary.
- * However, it should not be set too low to prevent
- * false triggering. Conversely, if it is set too
- * high, then you could miss a stuck IRQ.
+ * Maximum IRQ count. Currently, this is arbitary. However, it should
+ * not be set too low to prevent false triggering. Conversely, if it
+ * is set too high, then you could miss a stuck IRQ.
*
- * Maybe we ought to set a timer and re-enable the
- * IRQ at a later time?
+ * Maybe we ought to set a timer and re-enable the IRQ at a later time?
*/
#define MAX_IRQ_CNT 100000
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
- cliIF();
irq_desc[irq].enabled = 0;
irq_desc[irq].mask(irq);
spin_unlock_irqrestore(&irq_controller_lock, flags);
unsigned long flags;
spin_lock_irqsave(&irq_controller_lock, flags);
- cliIF();
irq_desc[irq].probing = 0;
irq_desc[irq].triggered = 0;
irq_desc[irq].enabled = 1;
#include <asm/hardware.h>
#include <asm/leds.h>
+#include <asm/mach-types.h>
#include <asm/system.h>
#define LED_STATE_ENABLED 1
static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED;
extern spinlock_t gpio_lock;
-#ifdef CONFIG_FOOTBRIDGE
+#if defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_CO285)
static void ebsa285_leds_event(led_event_t evt)
{
#ifdef CONFIG_LEDS_CPU
case led_idle_start:
if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state |= XBUS_LED_RED;
+ hw_led_state |= XBUS_LED_AMBER;
break;
case led_idle_end:
if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state &= ~XBUS_LED_RED;
+ hw_led_state &= ~XBUS_LED_AMBER;
break;
#endif
+ case led_halted:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~XBUS_LED_RED;
+ break;
+
case led_green_on:
if (led_state & LED_STATE_CLAIMED)
hw_led_state &= ~XBUS_LED_GREEN;
break;
#endif
+ case led_halted:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= GPIO_RED_LED;
+ break;
+
case led_green_on:
if (led_state & LED_STATE_CLAIMED)
hw_led_state |= GPIO_GREEN_LED;
static int __init leds_init(void)
{
-#ifdef CONFIG_FOOTBRIDGE
+#if defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_CO285)
if (machine_is_ebsa285() || machine_is_co285())
leds_event = ebsa285_leds_event;
#endif
#include <asm/hardware.h>
#include <asm/leds.h>
+#include <asm/mach-types.h>
#include <asm/system.h>
break;
#endif
+ case led_halted:
+ break;
+
case led_green_on:
if (led_state & LED_STATE_CLAIMED)
hw_led_state &= ~BCR_LED_GREEN;
#endif /* CONFIG_SA1100_LART */
+#ifdef CONFIG_SA1100_CERF
+#define LED_D0 GPIO_GPIO(0)
+#define LED_D1 GPIO_GPIO(1)
+#define LED_D2 GPIO_GPIO(2)
+#define LED_D3 GPIO_GPIO(3)
+#define LED_MASK (LED_D0|LED_D1|LED_D2|LED_D3)
+
+static void cerf_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+
+ save_flags_cli(flags);
+
+ switch (evt) {
+ case led_start:
+ hw_led_state = LED_MASK;
+ led_state = LED_STATE_ENABLED;
+ break;
+
+ case led_stop:
+ led_state &= ~LED_STATE_ENABLED;
+ break;
+
+ case led_claim:
+ led_state |= LED_STATE_CLAIMED;
+ hw_led_state = LED_MASK;
+ break;
+ case led_release:
+ led_state &= ~LED_STATE_CLAIMED;
+ hw_led_state = LED_MASK;
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state ^= LED_D0;
+ break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+ case led_idle_start:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D1;
+ break;
+
+ case led_idle_end:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D1;
+ break;
+#endif
+ case led_green_on:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D2;
+ break;
+
+ case led_green_off:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D2;
+ break;
+
+ case led_amber_on:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D3;
+ break;
+
+ case led_amber_off:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D3;
+ break;
+
+ case led_red_on:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D1;
+ break;
+
+ case led_red_off:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (led_state & LED_STATE_ENABLED) {
+ GPSR = hw_led_state;
+ GPCR = hw_led_state ^ LED_MASK;
+ }
+
+ restore_flags(flags);
+}
+
+#endif /* CONFIG_SA1100_CERF */
+
static void dummy_leds_event(led_event_t evt)
{
}
if (machine_is_lart())
leds_event = lart_leds_event;
#endif
-
+#ifdef CONFIG_SA1100_CERF
+ if (machine_is_cerf())
+ {
+ //GPDR |= 0x0000000F;
+ leds_event = cerf_leds_event;
+ }
+#endif
leds_event(led_start);
return 0;
}
/* Support for the latches on the old Archimedes which control the floppy,
* hard disc and printer
*
- * (c) David Alan Gilbert 1995/1996
+ * (c) David Alan Gilbert 1995/1996,2000
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <asm/io.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/oldlatches.h>
static unsigned char latch_a_copy;
static unsigned char latch_b_copy;
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/leds.h>
#include <asm/uaccess.h>
/*
#define IDLE_CLOCK_SLOW 2
#define IDLE_CLOCK_FAST 3
-extern char *processor_modes[];
+extern const char *processor_modes[];
extern void setup_mm_for_reboot(char mode);
asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
void machine_halt(void)
{
+ leds_event(led_halted);
}
void machine_power_off(void)
{
+ leds_event(led_halted);
if (pm_power_off)
pm_power_off();
}
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_UNINTERRUPTIBLE;
- add_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
sem->sleepers++;
*/
if (!atomic_add_negative(sleepers - 1, &sem->count)) {
sem->sleepers = 0;
- wake_up(&sem->wait);
break;
}
sem->sleepers = 1; /* us - see -1 above */
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_UNINTERRUPTIBLE;
+ tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
remove_wait_queue(&sem->wait, &wait);
tsk->state = TASK_RUNNING;
+ wake_up(&sem->wait);
}
int __down_interruptible(struct semaphore * sem)
{
- int retval;
+ int retval = 0;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_INTERRUPTIBLE;
- add_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
sem->sleepers ++;
* it has contention. Just correct the count
* and exit.
*/
- retval = -EINTR;
if (signal_pending(current)) {
+ retval = -EINTR;
sem->sleepers = 0;
- if (atomic_add_negative(sleepers, &sem->count))
- break;
- wake_up(&sem->wait);
+ atomic_add(sleepers, &sem->count);
break;
}
* the lock.
*/
if (!atomic_add_negative(sleepers - 1, &sem->count)) {
- wake_up(&sem->wait);
- retval = 0;
sem->sleepers = 0;
break;
}
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_INTERRUPTIBLE;
+ tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
tsk->state = TASK_RUNNING;
remove_wait_queue(&sem->wait, &wait);
+ wake_up(&sem->wait);
return retval;
}
int __down_trylock(struct semaphore * sem)
{
int sleepers;
+ unsigned long flags;
- spin_lock_irq(&semaphore_lock);
+ spin_lock_irqsave(&semaphore_lock, flags);
sleepers = sem->sleepers + 1;
sem->sleepers = 0;
if (!atomic_add_negative(sleepers, &sem->count))
wake_up(&sem->wait);
- spin_unlock_irq(&semaphore_lock);
+ spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
while (atomic_read(&sem->count) < 0) {
set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
if (atomic_read(&sem->count) >= 0)
- break; /* we must attempt to aquire or bias the lock */ schedule();
+ break; /* we must attempt to aquire or bias the lock */
+ schedule();
}
remove_wait_queue(&sem->wait, &wait);
* registers (r0 to r3 and lr), but not ip, as we use it as a return
* value in some cases..
*/
+#ifdef CONFIG_CPU_26
+asm(" .section .text.lock, \"ax\"
+ .align 5
+ .globl __down_failed
+__down_failed:
+ stmfd sp!, {r0 - r3, lr}
+ mov r0, ip
+ bl __down
+ ldmfd sp!, {r0 - r3, pc}^
+
+ .align 5
+ .globl __down_interruptible_failed
+__down_interruptible_failed:
+ stmfd sp!, {r0 - r3, lr}
+ mov r0, ip
+ bl __down_interruptible
+ mov ip, r0
+ ldmfd sp!, {r0 - r3, pc}^
+
+ .align 5
+ .globl __down_trylock_failed
+__down_trylock_failed:
+ stmfd sp!, {r0 - r3, lr}
+ mov r0, ip
+ bl __down_trylock
+ mov ip, r0
+ ldmfd sp!, {r0 - r3, pc}^
+
+ .align 5
+ .globl __up_wakeup
+__up_wakeup:
+ stmfd sp!, {r0 - r3, lr}
+ mov r0, ip
+ bl __up
+ ldmfd sp!, {r0 - r3, pc}^
+
+ .align 5
+ .globl __down_read_failed
+__down_read_failed:
+ stmfd sp!, {r0 - r3, lr}
+ mov r0, ip
+ bcc 1f
+1: bl down_read_failed_biased
+ ldmfd sp!, {r0 - r3, pc}^
+2: bl down_read_failed
+ mov r1, pc
+ orr r2, r1, #
+ teqp r2, #0
+
+ ldr r3, [r0]
+ subs r3, r3, #1
+ str r3, [r0]
+ ldmplfd sp!, {r0 - r3, pc}^
+ orrcs r1, r1, #0x20000000 @ Set carry
+ teqp r1, #0
+ bcc 2b
+ b 1b
+
+ .align 5
+ .globl __down_write_failed
+__down_write_failed:
+ stmfd sp!, {r0 - r3, lr}
+ mov r0, ip
+ bcc 1f
+1: bl down_write_failed_biased
+ ldmfd sp!, {r0 - r3, pc}^
+2: bl down_write_failed
+ mov r1, pc
+ orr r2, r1, #128
+ teqp r2, #0
+
+ ldr r3, [r0]
+ subs r3, r3, #"RW_LOCK_BIAS_STR"
+ str r3, [r0]
+ ldmeqfd sp!, {r0 - r3, pc}^
+ orrcs r1, r1, #0x20000000 @ Set carry
+ teqp r1, #0
+ bcc 2b
+ b 1b
+
+ .align 5
+ .globl __rwsem_wake
+__rwsem_wake:
+ stmfd sp!, {r0 - r3, lr}
+ mov r0, ip
+ beq 1f
+ bl rwsem_wake_readers
+ ldmfd sp!, {r0 - r3, pc}^
+1: bl rwsem_wake_writer
+ ldmfd sp!, {r0 - r3, pc}^
+
+ .previous
+ ");
+
+#else
+/* 32 bit version */
asm(" .section .text.lock, \"ax\"
.align 5
.globl __down_failed
.previous
");
+#endif
#include <asm/io.h>
#include <asm/procinfo.h>
#include <asm/setup.h>
-#include <asm/system.h>
+#include <asm/mach-types.h>
#include "arch.h"
extern int _stext, _text, _etext, _edata, _end;
unsigned int processor_id;
+unsigned int compat;
unsigned int __machine_arch_type;
unsigned int system_rev;
unsigned int system_serial_low;
}
printk("Architecture: %s\n", list->name);
+ if (compat)
+ printk(KERN_WARNING "Using compatability code "
+ "scheduled for removal in v%d.%d.%d\n",
+ compat >> 24, (compat >> 12) & 0x3ff,
+ compat & 0x3ff);
return list;
}
memset(&meminfo, 0, sizeof(meminfo));
-#if defined(CONFIG_ARCH_ARC)
- __machine_arch_type = MACH_TYPE_ARCHIMEDES;
-#elif defined(CONFIG_ARCH_A5K)
- __machine_arch_type = MACH_TYPE_A5K;
-#endif
-
setup_processor();
ROOT_DEV = MKDEV(0, 255);
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
+ int err = -EFAULT;;
+
if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
- return -EFAULT;
+ goto out;
+
if (from->si_code < 0)
return __copy_to_user(to, from, sizeof(siginfo_t));
- else {
- int err;
-
- /* If you change siginfo_t structure, please be sure
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
- /* First 32bits of unions are always present. */
- err |= __put_user(from->si_pid, &to->si_pid);
- switch (from->si_code >> 16) {
- case __SI_FAULT >> 16:
- break;
- case __SI_CHLD >> 16:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- default:
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- /* case __SI_RT: This is not generated by the kernel as of now. */
- }
- return err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
}
+out:
+ return err;
}
/*
{
int err = 0;
- err |= __get_user(regs->ARM_r0, &sc->arm_r0);
- err |= __get_user(regs->ARM_r1, &sc->arm_r1);
- err |= __get_user(regs->ARM_r2, &sc->arm_r2);
- err |= __get_user(regs->ARM_r3, &sc->arm_r3);
- err |= __get_user(regs->ARM_r4, &sc->arm_r4);
- err |= __get_user(regs->ARM_r5, &sc->arm_r5);
- err |= __get_user(regs->ARM_r6, &sc->arm_r6);
- err |= __get_user(regs->ARM_r7, &sc->arm_r7);
- err |= __get_user(regs->ARM_r8, &sc->arm_r8);
- err |= __get_user(regs->ARM_r9, &sc->arm_r9);
- err |= __get_user(regs->ARM_r10, &sc->arm_r10);
- err |= __get_user(regs->ARM_fp, &sc->arm_fp);
- err |= __get_user(regs->ARM_ip, &sc->arm_ip);
- err |= __get_user(regs->ARM_sp, &sc->arm_sp);
- err |= __get_user(regs->ARM_lr, &sc->arm_lr);
- err |= __get_user(regs->ARM_pc, &sc->arm_pc);
+ __get_user_error(regs->ARM_r0, &sc->arm_r0, err);
+ __get_user_error(regs->ARM_r1, &sc->arm_r1, err);
+ __get_user_error(regs->ARM_r2, &sc->arm_r2, err);
+ __get_user_error(regs->ARM_r3, &sc->arm_r3, err);
+ __get_user_error(regs->ARM_r4, &sc->arm_r4, err);
+ __get_user_error(regs->ARM_r5, &sc->arm_r5, err);
+ __get_user_error(regs->ARM_r6, &sc->arm_r6, err);
+ __get_user_error(regs->ARM_r7, &sc->arm_r7, err);
+ __get_user_error(regs->ARM_r8, &sc->arm_r8, err);
+ __get_user_error(regs->ARM_r9, &sc->arm_r9, err);
+ __get_user_error(regs->ARM_r10, &sc->arm_r10, err);
+ __get_user_error(regs->ARM_fp, &sc->arm_fp, err);
+ __get_user_error(regs->ARM_ip, &sc->arm_ip, err);
+ __get_user_error(regs->ARM_sp, &sc->arm_sp, err);
+ __get_user_error(regs->ARM_lr, &sc->arm_lr, err);
+ __get_user_error(regs->ARM_pc, &sc->arm_pc, err);
#ifdef CONFIG_CPU_32
- err |= __get_user(regs->ARM_cpsr, &sc->arm_cpsr);
+ __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err);
#endif
err |= !valid_user_regs(regs);
{
int err = 0;
- err |= __put_user (regs->ARM_r0, &sc->arm_r0);
- err |= __put_user (regs->ARM_r1, &sc->arm_r1);
- err |= __put_user (regs->ARM_r2, &sc->arm_r2);
- err |= __put_user (regs->ARM_r3, &sc->arm_r3);
- err |= __put_user (regs->ARM_r4, &sc->arm_r4);
- err |= __put_user (regs->ARM_r5, &sc->arm_r5);
- err |= __put_user (regs->ARM_r6, &sc->arm_r6);
- err |= __put_user (regs->ARM_r7, &sc->arm_r7);
- err |= __put_user (regs->ARM_r8, &sc->arm_r8);
- err |= __put_user (regs->ARM_r9, &sc->arm_r9);
- err |= __put_user (regs->ARM_r10, &sc->arm_r10);
- err |= __put_user (regs->ARM_fp, &sc->arm_fp);
- err |= __put_user (regs->ARM_ip, &sc->arm_ip);
- err |= __put_user (regs->ARM_sp, &sc->arm_sp);
- err |= __put_user (regs->ARM_lr, &sc->arm_lr);
- err |= __put_user (regs->ARM_pc, &sc->arm_pc);
+ __put_user_error(regs->ARM_r0, &sc->arm_r0, err);
+ __put_user_error(regs->ARM_r1, &sc->arm_r1, err);
+ __put_user_error(regs->ARM_r2, &sc->arm_r2, err);
+ __put_user_error(regs->ARM_r3, &sc->arm_r3, err);
+ __put_user_error(regs->ARM_r4, &sc->arm_r4, err);
+ __put_user_error(regs->ARM_r5, &sc->arm_r5, err);
+ __put_user_error(regs->ARM_r6, &sc->arm_r6, err);
+ __put_user_error(regs->ARM_r7, &sc->arm_r7, err);
+ __put_user_error(regs->ARM_r8, &sc->arm_r8, err);
+ __put_user_error(regs->ARM_r9, &sc->arm_r9, err);
+ __put_user_error(regs->ARM_r10, &sc->arm_r10, err);
+ __put_user_error(regs->ARM_fp, &sc->arm_fp, err);
+ __put_user_error(regs->ARM_ip, &sc->arm_ip, err);
+ __put_user_error(regs->ARM_sp, &sc->arm_sp, err);
+ __put_user_error(regs->ARM_lr, &sc->arm_lr, err);
+ __put_user_error(regs->ARM_pc, &sc->arm_pc, err);
#ifdef CONFIG_CPU_32
- err |= __put_user (regs->ARM_cpsr, &sc->arm_cpsr);
+ __put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err);
#endif
- err |= __put_user (current->thread.trap_no, &sc->trap_no);
- err |= __put_user (current->thread.error_code, &sc->error_code);
- err |= __put_user (current->thread.address, &sc->fault_address);
- err |= __put_user (mask, &sc->oldmask);
+ __put_user_error(current->thread.trap_no, &sc->trap_no, err);
+ __put_user_error(current->thread.error_code, &sc->error_code, err);
+ __put_user_error(current->thread.address, &sc->fault_address, err);
+ __put_user_error(mask, &sc->oldmask, err);
return err;
}
extern void c_backtrace (unsigned long fp, int pmode);
-char *processor_modes[]=
+const char *processor_modes[]=
{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
"UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
"USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
if (data)
printk(KERN_CRIT" - extra data = %p", data);
printk("\n");
- BUG();
+ *(int *)0 = 0;
}
void __readwrite_bug(const char *fn)
# Copyright (C) 1995-1999 Russell King
#
+USE_STANDARD_AS_RULE := true
+
L_TARGET := lib.a
L_OBJS := changebit.o csumipv6.o csumpartial.o csumpartialcopy.o \
csumpartialcopyuser.o clearbit.o copy_page.o findbit.o \
include $(TOPDIR)/Rules.make
-.S.o:
- $(CC) $(AFLAGS) -traditional -c -o $*.o $<
-
constants.h: getconsdata.o extractconstants.pl
$(PERL) extractconstants.pl $(OBJDUMP) > $@
blt .c2u_0rem8lp
.c2u_0cpy8lp: ldmia r1!, {r3 - r6}
- stmia r0!, {r3 - r6} @ Shouldn't fault
+ stmia r0!, {r3 - r6} @ Shouldnt fault
ldmia r1!, {r3 - r6}
- stmia r0!, {r3 - r6} @ Shouldn't fault
+ stmia r0!, {r3 - r6} @ Shouldnt fault
subs ip, ip, #32
bpl .c2u_0cpy8lp
.c2u_0rem8lp: cmn ip, #16
ldmgeia r1!, {r3 - r6}
- stmgeia r0!, {r3 - r6} @ Shouldn't fault
+ stmgeia r0!, {r3 - r6} @ Shouldnt fault
tst ip, #8
ldmneia r1!, {r3 - r4}
- stmneia r0!, {r3 - r4} @ Shouldn't fault
+ stmneia r0!, {r3 - r4} @ Shouldnt fault
tst ip, #4
ldrne r3, [r1], #4
- strnet r3, [r0], #4 @ Shouldn't fault
+ strnet r3, [r0], #4 @ Shouldnt fault
ands ip, ip, #3
beq .c2u_0fupi
.c2u_0nowords: teq ip, #0
orr r5, r5, r6, lsl #24
mov r6, r6, lsr #8
orr r6, r6, r7, lsl #24
- stmia r0!, {r3 - r6} @ Shouldn't fault
+ stmia r0!, {r3 - r6} @ Shouldnt fault
subs ip, ip, #16
bpl .c2u_1cpy8lp
.c2u_1rem8lp: tst ip, #8
orrne r3, r3, r4, lsl #24
movne r4, r4, lsr #8
orrne r4, r4, r7, lsl #24
- stmneia r0!, {r3 - r4} @ Shouldn't fault
+ stmneia r0!, {r3 - r4} @ Shouldnt fault
tst ip, #4
movne r3, r7, lsr #8
ldrne r7, [r1], #4
orrne r3, r3, r7, lsl #24
- strnet r3, [r0], #4 @ Shouldn't fault
+ strnet r3, [r0], #4 @ Shouldnt fault
ands ip, ip, #3
beq .c2u_1fupi
.c2u_1nowords: mov r3, r7, lsr #8
orr r5, r5, r6, lsl #16
mov r6, r6, lsr #16
orr r6, r6, r7, lsl #16
- stmia r0!, {r3 - r6} @ Shouldn't fault
+ stmia r0!, {r3 - r6} @ Shouldnt fault
subs ip, ip, #16
bpl .c2u_2cpy8lp
.c2u_2rem8lp: tst ip, #8
orrne r3, r3, r4, lsl #16
movne r4, r4, lsr #16
orrne r4, r4, r7, lsl #16
- stmneia r0!, {r3 - r4} @ Shouldn't fault
+ stmneia r0!, {r3 - r4} @ Shouldnt fault
tst ip, #4
movne r3, r7, lsr #16
ldrne r7, [r1], #4
orrne r3, r3, r7, lsl #16
- strnet r3, [r0], #4 @ Shouldn't fault
+ strnet r3, [r0], #4 @ Shouldnt fault
ands ip, ip, #3
beq .c2u_2fupi
.c2u_2nowords: mov r3, r7, lsr #16
orr r5, r5, r6, lsl #8
mov r6, r6, lsr #24
orr r6, r6, r7, lsl #8
- stmia r0!, {r3 - r6} @ Shouldn't fault
+ stmia r0!, {r3 - r6} @ Shouldnt fault
subs ip, ip, #16
bpl .c2u_3cpy8lp
.c2u_3rem8lp: tst ip, #8
orrne r3, r3, r4, lsl #8
movne r4, r4, lsr #24
orrne r4, r4, r7, lsl #8
- stmneia r0!, {r3 - r4} @ Shouldn't fault
+ stmneia r0!, {r3 - r4} @ Shouldnt fault
tst ip, #4
movne r3, r7, lsr #24
ldrne r7, [r1], #4
orrne r3, r3, r7, lsl #8
- strnet r3, [r0], #4 @ Shouldn't fault
+ strnet r3, [r0], #4 @ Shouldnt fault
ands ip, ip, #3
beq .c2u_3fupi
.c2u_3nowords: mov r3, r7, lsr #24
subs ip, ip, #32
blt .cfu_0rem8lp
-.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldn't fault
+.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
stmia r0!, {r3 - r6}
- ldmia r1!, {r3 - r6} @ Shouldn't fault
+ ldmia r1!, {r3 - r6} @ Shouldnt fault
stmia r0!, {r3 - r6}
subs ip, ip, #32
bpl .cfu_0cpy8lp
.cfu_0rem8lp: cmn ip, #16
- ldmgeia r1!, {r3 - r6} @ Shouldn't fault
+ ldmgeia r1!, {r3 - r6} @ Shouldnt fault
stmgeia r0!, {r3 - r6}
tst ip, #8
- ldmneia r1!, {r3 - r4} @ Shouldn't fault
+ ldmneia r1!, {r3 - r4} @ Shouldnt fault
stmneia r0!, {r3 - r4}
tst ip, #4
- ldrnet r3, [r1], #4 @ Shouldn't fault
+ ldrnet r3, [r1], #4 @ Shouldnt fault
strne r3, [r0], #4
ands ip, ip, #3
beq .cfu_0fupi
blt .cfu_1rem8lp
.cfu_1cpy8lp: mov r3, r7, lsr #8
- ldmia r1!, {r4 - r7} @ Shouldn't fault
+ ldmia r1!, {r4 - r7} @ Shouldnt fault
orr r3, r3, r4, lsl #24
mov r4, r4, lsr #8
orr r4, r4, r5, lsl #24
bpl .cfu_1cpy8lp
.cfu_1rem8lp: tst ip, #8
movne r3, r7, lsr #8
- ldmneia r1!, {r4, r7} @ Shouldn't fault
+ ldmneia r1!, {r4, r7} @ Shouldnt fault
orrne r3, r3, r4, lsl #24
movne r4, r4, lsr #8
orrne r4, r4, r7, lsl #24
blt .cfu_2rem8lp
.cfu_2cpy8lp: mov r3, r7, lsr #16
- ldmia r1!, {r4 - r7} @ Shouldn't fault
+ ldmia r1!, {r4 - r7} @ Shouldnt fault
orr r3, r3, r4, lsl #16
mov r4, r4, lsr #16
orr r4, r4, r5, lsl #16
bpl .cfu_2cpy8lp
.cfu_2rem8lp: tst ip, #8
movne r3, r7, lsr #16
- ldmneia r1!, {r4, r7} @ Shouldn't fault
+ ldmneia r1!, {r4, r7} @ Shouldnt fault
orrne r3, r3, r4, lsl #16
movne r4, r4, lsr #16
orrne r4, r4, r7, lsl #16
blt .cfu_3rem8lp
.cfu_3cpy8lp: mov r3, r7, lsr #24
- ldmia r1!, {r4 - r7} @ Shouldn't fault
+ ldmia r1!, {r4 - r7} @ Shouldnt fault
orr r3, r3, r4, lsl #8
mov r4, r4, lsr #24
orr r4, r4, r5, lsl #8
bpl .cfu_3cpy8lp
.cfu_3rem8lp: tst ip, #8
movne r3, r7, lsr #24
- ldmneia r1!, {r4, r7} @ Shouldn't fault
+ ldmneia r1!, {r4, r7} @ Shouldnt fault
orrne r3, r3, r4, lsl #8
movne r4, r4, lsr #24
orrne r4, r4, r7, lsl #8
* or zero on exception, or n + 1 if too long
*/
ENTRY(__arch_strnlen_user)
- stmfd sp!, {lr}
+ str lr, [sp, #-4]!
mov r2, r0
1:
USER( ldrbt r3, [r0], #1)
* Returns : number of characters copied
*/
ENTRY(__arch_strncpy_from_user)
- stmfd sp!, {lr}
+ str lr, [sp, #-4]!
add ip, r1, #1
1: subs r2, r2, #1
bmi 2f
#
# Note 2! The CFLAGS definition is now in the main makefile...
+USE_STANDARD_AS_RULE := true
+
O_TARGET := mm.o
-O_OBJS := consistent.o extable.o fault-$(PROCESSOR).o init.o \
+O_OBJS := extable.o fault-$(PROCESSOR).o init.o \
mm-$(PROCESSOR).o small_page.o
ifeq ($(CONFIG_CPU_26),y)
ifeq ($(CONFIG_CPU_SA1100),y)
P_OBJS += proc-sa110.o
endif
- O_OBJS += mm-$(MACHINE).o ioremap.o $(sort $(P_OBJS))
+ O_OBJS += mm-$(MACHINE).o consistent.o ioremap.o $(sort $(P_OBJS))
endif
include $(TOPDIR)/Rules.make
-.S.o:
- $(CC) $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $<
-
# Special dependencies
fault-armv.o: fault-common.c
fault-armo.o: fault-common.c
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/bootmem.h>
-#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h>
-#endif
-#include <asm/system.h>
#include <asm/segment.h>
+#include <asm/mach-types.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
#include <asm/hardware.h>
end = page + NODE_DATA(node)->node_size;
do {
- if (PageSkip(page)) {
- page = page->next_hash;
- if (page == NULL)
- break;
- }
+/* This is currently broken
+ * PG_skip is used on sparc/sparc64 architectures to "skip" certain
+ * parts of the address space.
+ *
+ * #define PG_skip 10
+ * #define PageSkip(page) (machine_is_riscpc() && test_bit(PG_skip, &(page)->flags))
+ * if (PageSkip(page)) {
+ * page = page->next_hash;
+ * if (page == NULL)
+ * break;
+ * }
+ */
total++;
if (PageReserved(page))
reserved++;
initpages = &__init_end - &__init_begin;
high_memory = (void *)__va(meminfo.end);
- max_mapnr = MAP_NR(high_memory);
+ max_mapnr = virt_to_page(high_memory) - mem_map;
/*
* We may have non-contiguous memory.
static inline void free_area(unsigned long addr, unsigned long end, char *s)
{
unsigned int size = (end - addr) >> 10;
- struct page *page = virt_to_page(addr);
- for (; addr < end; addr += PAGE_SIZE, page ++) {
+ for (; addr < end; addr += PAGE_SIZE) {
+ struct page *page = virt_to_page(addr);
ClearPageReserved(page);
set_page_count(page, 1);
free_page(addr);
}
if (size)
- printk(" %dk %s", size, s);
+ printk("Freeing %s memory: %dK\n", s, size);
}
void free_initmem(void)
{
- printk("Freeing unused kernel memory:");
-
free_area((unsigned long)(&__init_begin),
(unsigned long)(&__init_end),
"init");
-
- printk("\n");
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- unsigned long addr;
-
- if (!keep_initrd) {
- for (addr = start; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- set_page_count(virt_to_page(addr), 1);
- free_page(addr);
- totalram_pages++;
- }
- printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
- }
+ if (!keep_initrd)
+ free_area(start, end, "initrd");
}
static int __init keepinitrd_setup(char *__unused)
#else
+/*
+ * The mapping when the footbridge is in add-in mode.
+ */
+#define MAPPING \
+ { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
+ { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
+ { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
+ { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
+ { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
+ { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }
+
+#endif
+
+struct map_desc io_desc[] __initdata = {
+ MAPPING
+};
+
+unsigned int __initdata io_desc_size = SIZE(io_desc);
+
+
+#ifdef CONFIG_FOOTBRIDGE_ADDIN
+
/*
* These two functions convert virtual addresses to PCI addresses
* and PCI addresses to virtual addresses. Note that it is only
return res;
}
-/*
- * The mapping when the footbridge is in add-in mode.
- */
-#define MAPPING \
- { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
- { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
- { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
- { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
- { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \
- { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }
-
#endif
-
-struct map_desc io_desc[] __initdata = {
- MAPPING
-};
-
-unsigned int __initdata io_desc_size = SIZE(io_desc);
-
/*
* arch/arm/mm/mm-lusl7200.c
*
- * Extra MM routines for LUSL7200 architecture
+ * Extra MM routines for L7200 architecture
*
- * Copyright (C) 2000 Steven J. Hill
+ * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
*/
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/pgtable.h>
#include <asm/page.h>
+#include <asm/mach-types.h>
#include "map.h"
#endif
};
+static struct map_desc nanoengine_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_NANOENGINE
+ { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+ { 0xd4000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
+ { 0xdc000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */
+ SA1100_STD_IO_MAPPING
+#endif
+};
+
static struct map_desc bitsy_io_desc[] __initdata = {
#ifdef CONFIG_SA1100_BITSY
{ 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
#endif
};
+static struct map_desc cerf_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_CERF
+ { 0xd8000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Chip */
+ { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+ SA1100_STD_IO_MAPPING
+#endif
+};
+
static struct map_desc empeg_io_desc[] __initdata = {
#ifdef CONFIG_SA1100_EMPEG
{ EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */
#endif
};
+static struct map_desc lart_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_LART
+ { 0xd0000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */
+ { 0xd8000000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */
+ SA1100_STD_IO_MAPPING
+#endif
+};
+
static struct map_desc thinclient_io_desc[] __initdata = {
#ifdef CONFIG_SA1100_THINCLIENT
#if 0
#endif
};
+static struct map_desc xp860_io_desc[] __initdata = {
+#ifdef CONFIG_SA1100_XP860
+ { 0xd8000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
+ { 0xda000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */
+ { 0xdc000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */
+ SA1100_STD_IO_MAPPING
+#endif
+};
static struct map_desc default_io_desc[] __initdata = {
SA1100_STD_IO_MAPPING
if( machine_is_assabet() ) {
memcpy( io_desc, assabet_io_desc, sizeof(assabet_io_desc) );
io_desc_size = SIZE(assabet_io_desc);
+ } else if( machine_is_nanoengine() ) {
+ memcpy( io_desc, nanoengine_io_desc, sizeof(nanoengine_io_desc) );
+ io_desc_size = SIZE(nanoengine_io_desc);
} else if( machine_is_bitsy() ) {
memcpy( io_desc, bitsy_io_desc, sizeof(bitsy_io_desc) );
io_desc_size = SIZE(bitsy_io_desc);
+ } else if( machine_is_cerf() ) {
+ memcpy( io_desc, cerf_io_desc, sizeof(cerf_io_desc) );
+ io_desc_size = SIZE(cerf_io_desc);
} else if( machine_is_empeg() ) {
memcpy( io_desc, empeg_io_desc, sizeof(empeg_io_desc) );
io_desc_size = SIZE(empeg_io_desc);
} else if( machine_is_graphicsclient() ) {
memcpy( io_desc, graphicsclient_io_desc, sizeof(graphicsclient_io_desc) );
io_desc_size = SIZE(graphicsclient_io_desc);
+ } else if( machine_is_lart() ) {
+ memcpy( io_desc, lart_io_desc, sizeof(lart_io_desc) );
+ io_desc_size = SIZE(lart_io_desc);
} else if( machine_is_thinclient() ) {
memcpy( io_desc, thinclient_io_desc, sizeof(thinclient_io_desc) );
io_desc_size = SIZE(thinclient_io_desc);
} else if( machine_is_victor() ) {
memcpy( io_desc, victor_io_desc, sizeof(victor_io_desc) );
io_desc_size = SIZE(victor_io_desc);
+ } else if( machine_is_xp860() ) {
+ memcpy( io_desc, xp860_io_desc, sizeof(xp860_io_desc) );
+ io_desc_size = SIZE(xp860_io_desc);
} else {
memcpy( io_desc, default_io_desc, sizeof(default_io_desc) );
io_desc_size = SIZE(default_io_desc);
* Changelog:
* 05-09-2000 SJH Created by moving 720 specific functions
* out of 'proc-arm6,7.S' per RSK discussion
+ * 07-25-2000 SJH Added idle function.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/procinfo.h>
#include <asm/errno.h>
+#include <asm/hardware.h>
#include "../lib/constants.h"
/*
add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine
movs pc, lr
- b Ldata_unknown
- b Ldata_unknown
+ b Ldata_lateldrhpost @ ldrh rd, [rn], #m/rm
+ b Ldata_lateldrhpre @ ldrh rd, [rn, #m/rm]
b Ldata_unknown
b Ldata_unknown
b Ldata_lateldrpostconst @ ldr rd, [rn], #m
b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
b Ldata_simple @ ldc rd, [rn, #m]
b Ldata_unknown
+
Ldata_unknown: @ Part of jumptable
mov r0, r2
mov r1, r4
bl baddataabort
b ret_from_sys_call
+Ldata_lateldrhpre:
+ tst r4, #1 << 21 @ check writeback bit
+ beq Ldata_simple
+Ldata_lateldrhpost:
+ tst r4, #1 << 22 @ check if register or immediate offset
+ beq Ldata_lateldrhpostreg
+Ldata_lateldrhpostconst:
+ and r2, r4, #0xf @ load and clear low nibble of const offset
+ and r5, r4, #0xf00 @ load and clear high nibble of const offset
+ orrs r2, r2, r5, lsr #4 @ create offset
+ beq Ldata_simple @ don't have to do anything if zero
+ and r5, r4, #0xf << 16 @ get Rn
+ ldr r0, [sp, r5, lsr #14]
+ tst r4, #1 << 23 @ U bit
+ subne r7, r0, r2, lsr #20
+ addeq r7, r0, r2, lsr #20
+ b Ldata_saver7
+Ldata_lateldrhpostreg:
+ and r5, r4, #0xf
+ ldr r2, [sp, r5, lsl #2] @ get Rm
+ and r5, r4, #0xf << 16
+ ldr r0, [sp, r5, lsr #14] @ get Rn
+ tst r4, #1 << 23
+ subne r7, r0, r2
+ addeq r7, r0, r2
+ b Ldata_saver7
+
Ldata_lateldrpreconst:
tst r4, #1 << 21 @ check writeback bit
beq Ldata_simple
* Function: arm720_check_bugs (void)
* : arm720_proc_init (void)
* : arm720_proc_fin (void)
- * : arm720_proc_do_idle (void)
*
* Notes : This processor does not require these
*/
mcr p15, 0, r0, c1, c0, 0 @ disable caches
mov pc, lr
+/*
+ * Function: arm720_proc_do_idle (void)
+ *
+ * Params : r0 = call type:
+ * 0 = slow idle
+ * 1 = fast idle
+ * 2 = switch to slow processor clock
+ * 3 = switch to fast processor clock
+ *
+ * Purpose : put the processer in proper idle mode
+ */
ENTRY(cpu_arm720_do_idle)
- mov r0, #-EINVAL
+ ldr r2, =IO_BASE @ Virt addr of IO
+ add r2, r2, #0x00050000 @ Start of PMU regs
+ mov r1, #0x01 @ Idle mode
+ str r1, [r2, #4]
mov pc, lr
/*
ldr r1, [r0] @ read instruction causing problem
mrc p15, 0, r0, c6, c0, 0 @ get FAR
mov r1, r1, lsr #19 @ b1 = L
- and r1, r1, #2
mrc p15, 0, r3, c5, c0, 0 @ get FSR
+ and r1, r1, #2
and r3, r3, #255
mov pc, lr
# Copyright (C) 1998, 1999 Philip Blundell
#
+USE_STANDARD_AS_RULE := true
+
NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \
fpmodule.o fpopcode.o softfloat.o \
single_cpdo.o double_cpdo.o extended_cpdo.o
--- /dev/null
+#!/bin/awk
+#
+# Awk script to generate include/asm-arm/mach-types.h
+#
+BEGIN { nr = 0 }
+/^#/ { next }
+/^[ ]*$/ { next }
+
+NF == 4 {
+ machine_is[nr] = "machine_is_"$1;
+ config[nr] = "CONFIG_"$2;
+ mach_type[nr] = "MACH_TYPE_"$3;
+ num[nr] = $4; nr++
+ }
+
+NF == 3 {
+ machine_is[nr] = "machine_is_"$1;
+ config[nr] = "CONFIG_"$2;
+ mach_type[nr] = "MACH_TYPE_"$3;
+ num[nr] = ""; nr++
+ }
+
+
+END {
+ printf("/*\n");
+ printf(" * This was automagically generated from %s!\n", FILENAME);
+ printf(" * Do NOT edit\n");
+ printf(" */\n\n");
+ printf("#ifndef __ASM_ARM_MACH_TYPE_H\n");
+ printf("#define __ASM_ARM_MACH_TYPE_H\n\n");
+ printf("#include <linux/config.h>\n\n");
+ printf("#ifndef __ASSEMBLY__\n");
+ printf("/* The type of machine we're running on */\n");
+ printf("extern unsigned int __machine_arch_type;\n");
+ printf("#endif\n\n");
+
+ printf("/* see arch/arm/kernel/arch.c for a description of these */\n");
+ for (i = 0; i < nr; i++)
+ if (num[i] ~ /..*/)
+ printf("#define %-30s %d\n", mach_type[i], num[i]);
+
+ printf("\n");
+
+ for (i = 0; i < nr; i++)
+ if (num[i] ~ /..*/) {
+ printf("#ifdef %s\n", config[i]);
+ printf("# ifdef machine_arch_type\n");
+ printf("# undef machine_arch_type\n");
+ printf("# define machine_arch_type\t__machine_arch_type\n");
+ printf("# else\n");
+ printf("# define machine_arch_type\t%s\n", mach_type[i]);
+ printf("# endif\n");
+ printf("# define %s()\t(machine_arch_type == %s)\n", machine_is[i], mach_type[i]);
+ printf("#else\n");
+ printf("# define %s()\t(0)\n", machine_is[i]);
+ printf("#endif\n\n");
+ }
+
+ printf("/*\n * These have not yet been registered\n */\n");
+ for (i = 0; i < nr; i++)
+ if (num[i] !~ /..*/)
+ printf("/* #define %-30s <<not registered>> */\n", mach_type[i]);
+
+ for (i = 0; i < nr; i++)
+ if (num[i] !~ /..*/) {
+ printf("#define %s()\t(0)\n", machine_is[i]);
+ }
+
+ printf("\n#ifndef machine_arch_type\n");
+ printf("#define machine_arch_type\t__machine_arch_type\n");
+ printf("#endif\n\n");
+ printf("#endif\n");
+ }
--- /dev/null
+# Database of machine macros and numbers
+#
+# To add an entry into this database, please see
+# Documentation/arm/README
+#
+# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
+#
+ebsa110 ARCH_EBSA110 EBSA110 0
+riscpc ARCH_RPC RISCPC 1
+nexuspci ARCH_NEXUSPCI NEXUSPCI 3
+ebsa285 ARCH_EBSA285 EBSA285 4
+netwinder ARCH_NETWINDER NETWINDER 5
+cats ARCH_CATS CATS 6
+tbox ARCH_TBOX TBOX 7
+co285 ARCH_CO285 CO285 8
+clps7110 ARCH_CLPS7110 CLPS7110 9
+arc ARCH_ARC ARCHIMEDES 10
+a5k ARCH_A5K A5K 11
+etoile ARCH_ETOILE ETOILE 12
+lacie_nas ARCH_LACIE_NAS LACIE_NAS 13
+clps7500 ARCH_CLPS7500 CLPS7500 14
+shark ARCH_SHARK SHARK 15
+brutus SA1100_BRUTUS BRUTUS 16
+personal_server ARCH_PERSONAL_SERVER PERSONAL_SERVER 17
+itsy SA1100_ITSY ITSY 18
+l7200 ARCH_L7200 L7200 19
+pleb SA1100_PLEB PLEB 20
+integrator ARCH_INTEGRATOR INTEGRATOR 21
+bitsy SA1100_BITSY BITSY 22
+ixp1200 ARCH_IXP1200 IXP1200 23
+thinclient SA1100_THINCLIENT THINCLIENT 24
+assabet SA1100_ASSABET ASSABET 25
+victor SA1100_VICTOR VICTOR 26
+lart SA1100_LART LART 27
+ranger ARCH_RANGER RANGER 28
+graphicsclient SA1100_GRAPHICSCLIENT GRAPHICSCLIENT 29
+xp860 SA1100_XP860 XP860 30
+cerf SA1100_CERF CERF 31
+nanoengine SA1100_NANOENGINE NANOENGINE 32
+
+# The following are unallocated
+empeg SA1100_EMPEG EMPEG
+tifon SA1100_TIFON TIFON
+penny SA1100_PENNY PENNY
* This interrupt should never happen with our APIC/SMP architecture
*/
-static spinlock_t err_lock = SPIN_LOCK_UNLOCKED;
-
asmlinkage void smp_error_interrupt(void)
{
- unsigned long v;
-
- spin_lock(&err_lock);
+ unsigned long v, v1;
+ /* First tickle the hardware, only then report what went on. -- REW */
v = apic_read(APIC_ESR);
- printk(KERN_INFO "APIC error interrupt on CPU#%d, should never happen.\n",
- smp_processor_id());
- printk(KERN_INFO "... APIC ESR0: %08lx\n", v);
-
apic_write(APIC_ESR, 0);
- v |= apic_read(APIC_ESR);
- printk(KERN_INFO "... APIC ESR1: %08lx\n", v);
- /*
- * Be a bit more verbose. (multiple bits can be set)
- */
- if (v & 0x01)
- printk(KERN_INFO "... bit 0: APIC Send CS Error (hw problem).\n");
- if (v & 0x02)
- printk(KERN_INFO "... bit 1: APIC Receive CS Error (hw problem).\n");
- if (v & 0x04)
- printk(KERN_INFO "... bit 2: APIC Send Accept Error.\n");
- if (v & 0x08)
- printk(KERN_INFO "... bit 3: APIC Receive Accept Error.\n");
- if (v & 0x10)
- printk(KERN_INFO "... bit 4: Reserved!.\n");
- if (v & 0x20)
- printk(KERN_INFO "... bit 5: Send Illegal Vector (kernel bug).\n");
- if (v & 0x40)
- printk(KERN_INFO "... bit 6: Received Illegal Vector.\n");
- if (v & 0x80)
- printk(KERN_INFO "... bit 7: Illegal Register Address.\n");
-
+ v1 = apic_read(APIC_ESR);
ack_APIC_irq();
-
irq_err_count++;
- spin_unlock(&err_lock);
+ /* Here is what the APIC error bits mean:
+ 0: Send CS error
+ 1: Receive CS error
+ 2: Send accept error
+ 3: Receive accept error
+ 4: Reserved
+ 5: Send illegal vector
+ 6: Received illegal vector
+ 7: Illegal register address
+ */
+ printk (KERN_ERR "APIC error on CPU%d: %02x(%02x)\n",
+ smp_processor_id(), v , v1);
}
+#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/page.h>
* are empty for now.
* - remove hack to avoid problem with <= 256M RAM for itr.
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
-/* $Id: systbls.S,v 1.98 2000/08/12 13:25:41 davem Exp $
+/* $Id: systbls.S,v 1.99 2000/08/12 20:49:49 jj Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
/*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
/*145*/ .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
-/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
+/*155*/ .long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
/*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
/*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
/*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-/* $Id: sys_sparc32.c,v 1.160 2000/08/12 13:25:41 davem Exp $
+/* $Id: sys_sparc32.c,v 1.161 2000/08/12 20:49:49 jj Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
old_fs = get_fs(); set_fs (KERNEL_DS);
ret = sys_fcntl(fd, cmd, (unsigned long)&f);
set_fs (old_fs);
+ if (ret) return ret;
+ if (f.l_start >= 0x7fffffffUL ||
+ f.l_len >= 0x7fffffffUL ||
+ f.l_start + f.l_len >= 0x7fffffffUL)
+ return -EOVERFLOW;
if(put_flock(&f, (struct flock32 *)arg))
return -EFAULT;
- return ret;
+ return 0;
}
default:
return sys_fcntl(fd, cmd, (unsigned long)arg);
}
}
+asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ if (cmd >= F_GETLK64 && cmd <= F_SETLKW64)
+ return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg);
+ return sys32_fcntl(fd, cmd, arg);
+}
+
struct dqblk32 {
__u32 dqb_bhardlimit;
__u32 dqb_bsoftlimit;
-/* $Id: systbls.S,v 1.75 2000/08/12 13:25:42 davem Exp $
+/* $Id: systbls.S,v 1.76 2000/08/12 20:49:49 jj Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
.word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
- .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
+ .word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
-/* $Id: dec_and_lock.S,v 1.1 2000/07/10 20:57:34 davem Exp $
+/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $
* dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()"
* using cas and ldstub instructions.
*
* TMP = *(MEM);
* *(MEM) = REG2;
* REG2 = TMP;
- * }
+ * } else
+ * REG2 = *(MEM);
* END_ATOMIC();
* }
- *
- * All non-contention cases are handled in 2 I-cache
- * lines which is 1 L2 cache line.
*/
.globl atomic_dec_and_lock
brnz,pn %g3, spin_on_lock
membar #StoreLoad | #StoreStore
loop2: cas [%o0], %g5, %g7 /* ASSERT(g7 == 0) */
- brnz,pt %g7, out
- mov 1, %g1
+ nop
+ cmp %g5, %g7
+ be,pt %icc, out
+ mov 1, %g1
lduw [%o0], %g5
subcc %g5, 1, %g7
be,pn %icc, loop2
nop
membar #StoreStore | #LoadStore
stb %g0, [%o1]
+
b,pt %xcc, nzero
nop
-
spin_on_lock:
ldub [%o1], %g3
brnz,pt %g3, spin_on_lock
membar #LoadLoad
- b,a,pt %xcc, to_zero
+ ba,pt %xcc, to_zero
+ nop
+ nop
# parent makefile.
#
+USE_STANDARD_AS_RULE := true
+
L_TARGET := acorn-block.a
obj-y :=
#include <asm/io.h>
#include <asm/ioc.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
#include <asm/pgtable.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o
# Do the i2c and rtc last
-obj-y += $(obj-$(MACHINE)) i2c.o pcf8583.o
+obj-y += $(obj-$(MACHINE))
+
+# CL-PS7500 does not have these devices.
+ifneq ($(CONFIG_ARCH_CLPS7500),y)
+obj-y += i2c.o pcf8583.o
+endif
O_OBJS := $(filter-out $(export-objs), $(obj-y))
OX_OBJS := $(filter $(export-objs), $(obj-y))
# Makefile for drivers/acorn/scsi
#
+USE_STANDARD_AS_RULE := true
+
L_TARGET := acorn-scsi.a
obj-y :=
rw_ahead = 1;
rw = READ; /* drop into READ */
case READ:
- if (buffer_uptodate(bh)) /* Hmmph! Already have it */
- goto end_io;
- kstat.pgpgin++;
- break;
- case WRITERAW:
- rw = WRITE;
- goto do_write; /* Skip the buffer refile */
case WRITE:
- if (!test_and_clear_bit(BH_Dirty, &bh->b_state))
- goto end_io; /* Hmmph! Nothing to write */
- refile_buffer(bh);
- do_write:
- kstat.pgpgout++;
break;
default:
BUG();
set_bit(BH_Req, &bh->b_state);
+ switch(rw) {
+ case WRITE:
+ if (!atomic_set_buffer_clean(bh))
+ /* Hmmph! Nothing to write */
+ goto end_io;
+ __mark_buffer_clean(bh);
+ kstat.pgpgout++;
+ break;
+
+ case READA:
+ case READ:
+ if (buffer_uptodate(bh))
+ /* Hmmph! Already have it */
+ goto end_io;
+ kstat.pgpgin++;
+ break;
+ default:
+ BUG();
+ end_io:
+ bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
+ continue;
+
+ }
+
/*
* First step, 'identity mapping' - RAID or LVM might
* further remap this.
if (rw == READA)
rw = READ;
- if (rw == WRITE) {
- rw = WRITERAW;
- /*
- * we first clean the bh, then we start the IO, then
- * when the IO has finished, we end_io the bh and
- * mark it uptodate. This way we do not miss the
- * case when the bh got dirty again during the IO.
- *
- * We do an important optimization here - if the
- * buffer was not dirty and we are during resync or
- * reconstruction, then we can skip writing it back
- * to the master disk! (we still have to write it
- * back to the other disks, because we are not sync
- * yet.)
- */
- if (atomic_set_buffer_clean(bh))
- __mark_buffer_clean(bh);
- else {
- bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
- return 0;
- }
- }
r1_bh = raid1_alloc_r1bh (conf);
spin_lock_irq(&conf->segment_lock);
if (!sh->bh_copy[i])
sh->bh_copy[i] = raid5_alloc_buffer(sh, sh->size);
raid5_build_block(sh, sh->bh_copy[i], i);
- if (atomic_set_buffer_clean(sh->bh_new[i]))
- atomic_set_buffer_dirty(sh->bh_copy[i]);
+ atomic_set_buffer_dirty(sh->bh_copy[i]);
memcpy(sh->bh_copy[i]->b_data, sh->bh_new[i]->b_data, sh->size);
}
if (sh->bh_copy[pd_idx] == NULL) {
}
-static int is_stripe_allclean(struct stripe_head *sh, int disks)
-{
- int i;
-
- return 0;
- for (i = 0; i < disks; i++) {
- if (sh->bh_new[i])
- if (test_bit(BH_Dirty, &sh->bh_new[i]))
- return 0;
- if (sh->bh_old[i])
- if (test_bit(BH_Dirty, &sh->bh_old[i]))
- return 0;
- }
- return 1;
-}
-
static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf,
struct stripe_head *sh, int nr_write, int * operational, int disks,
int parity, int parity_failed, int nr_cache, int nr_cache_other,
int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite)
{
- int i, allclean;
+ int i;
unsigned int block;
struct buffer_head *bh;
int method1 = INT_MAX, method2 = INT_MAX;
PRINTK("handle_stripe(), sector %lu, nr_write %d, method1 %d, method2 %d\n", sh->sector, nr_write, method1, method2);
if (!method1 || !method2) {
- allclean = is_stripe_allclean(sh, disks);
sh->phase = PHASE_WRITE;
compute_parity(sh, method1 <= method2 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE);
PRINTK("writing spare %d\n", i);
atomic_inc(&sh->nr_pending);
bh->b_dev = bh->b_rdev = conf->spare->dev;
- generic_make_request(WRITERAW, bh);
+ generic_make_request(WRITE, bh);
} else {
-#if 0
atomic_inc(&sh->nr_pending);
bh->b_dev = bh->b_rdev = conf->disks[i].dev;
- generic_make_request(WRITERAW, bh);
-#else
- if (!allclean || (i==sh->pd_idx)) {
- PRINTK("writing dirty %d\n", i);
- atomic_inc(&sh->nr_pending);
- bh->b_dev = bh->b_rdev = conf->disks[i].dev;
- generic_make_request(WRITERAW, bh);
- } else {
- PRINTK("not writing clean %d\n", i);
- raid5_end_request(bh, 1);
- sh->new[i] = 0;
- }
-#endif
+ generic_make_request(WRITE, bh);
}
atomic_dec(&bh->b_count);
}
atomic_inc(&sh->nr_pending);
lock_get_bh(bh);
bh->b_dev = bh->b_rdev = conf->spare->dev;
- generic_make_request(WRITERAW, bh);
+ generic_make_request(WRITE, bh);
md_sync_acct(bh->b_rdev, bh->b_size/512);
atomic_dec(&bh->b_count);
PRINTK("handle_stripe_sync() %lu, phase WRITE, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending));
lock_get_bh(bh);
atomic_inc(&sh->nr_pending);
bh->b_dev = bh->b_rdev = conf->disks[pd_idx].dev;
- generic_make_request(WRITERAW, bh);
+ generic_make_request(WRITE, bh);
md_sync_acct(bh->b_rdev, bh->b_size/512);
atomic_dec(&bh->b_count);
PRINTK("handle_stripe_sync() %lu phase WRITE, pending %d buffers\n",
tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
fi
fi
+if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
+ bool 'DC21285 serial port support' CONFIG_SERIAL_21285
+ if [ "$CONFIG_SERIAL_21285" = "y" ]; then
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD
+ fi
+ bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE
+ fi
+fi
bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
fi
dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI
fi
- dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI
+ dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
fi
endif
ifeq ($(ARCH),arm)
-# we actually need to be able to select various different keymaps
-# and keyboards dependent on which actual machine we're going to
-# run on.
- KEYMAP =
- KEYBD =
+ ifneq ($(CONFIG_PC_KEYMAP),y)
+ KEYMAP =
+ endif
+ ifneq ($(CONFIG_PC_KEYB),y)
+ KEYBD =
+ endif
endif
ifeq ($(ARCH),sh)
#ifndef PCI_DEVICE_ID_VIA_82C691_0
#define PCI_DEVICE_ID_VIA_82C691_0 0x0691
#endif
-#ifndef PCI_DEVICE_ID_VIA_82C691_1
-#define PCI_DEVICE_ID_VIA_82C691_1 0x8691
+#ifndef PCI_DEVICE_ID_VIA_8371_0
+#define PCI_DEVICE_ID_VIA_8371_0 0x0391
+#endif
+#ifndef PCI_DEVICE_ID_VIA_8363_0
+#define PCI_DEVICE_ID_VIA_8363_0 0x0305
#endif
#ifndef PCI_DEVICE_ID_INTEL_810_0
#define PCI_DEVICE_ID_INTEL_810_0 0x7120
/*
* Driver routines - start
- * Currently this module supports the
- * i810, 440lx, 440bx, 440gx, via vp3, via mvp3,
- * amd irongate, ALi M1541 and generic support for the
- * SiS chipsets.
+ * Currently this module supports the following chipsets:
+ * i810, 440lx, 440bx, 440gx, via vp3, via mvp3, via kx133, via kt133,
+ * amd irongate, ALi M1541, and generic support for the SiS chipsets.
*/
/* Generic Agp routines - Start */
#endif /* CONFIG_AGP_SIS */
#ifdef CONFIG_AGP_VIA
- { PCI_DEVICE_ID_VIA_8371_0,
- PCI_VENDOR_ID_VIA,
- VIA_APOLLO_SUPER,
- "Via",
- "Apollo Super",
- via_generic_setup },
{ PCI_DEVICE_ID_VIA_8501_0,
PCI_VENDOR_ID_VIA,
VIA_MVP4,
"Via",
"Apollo Pro",
via_generic_setup },
+ { PCI_DEVICE_ID_VIA_8371_0,
+ PCI_VENDOR_ID_VIA,
+ VIA_APOLLO_KX133,
+ "Via",
+ "Apollo Pro KX133",
+ via_generic_setup },
+ { PCI_DEVICE_ID_VIA_8363_0,
+ PCI_VENDOR_ID_VIA,
+ VIA_APOLLO_KT133,
+ "Via",
+ "Apollo Pro KT133",
+ via_generic_setup },
{ 0,
PCI_VENDOR_ID_VIA,
VIA_GENERIC,
#if LINUX_VERSION_CODE >= 0x020400
case VIA_MVP4: head->chipset = "VIA MVP4"; break;
- case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super";
+ case VIA_APOLLO_KX133: head->chipset = "VIA Apollo KX133";
+ break;
+ case VIA_APOLLO_KT133: head->chipset = "VIA Apollo KT133";
break;
#endif
#include <linux/init.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <asm/therm.h>
if [ "$CONFIG_PARPORT" != "n" ]; then
comment 'Parallel port joysticks'
- dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_JOYSTICK
- dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_JOYSTICK
- dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_JOYSTICK
+ dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
+ dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_JOYSTICK $CONFIG_PARPORT
+ dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
printk(KERN_ERR "Memory allocation failed.\n");
+ release_region(ioport, iolen);
return -ENOMEM;
}
memset(port, 0, sizeof(struct ns558));
}
#endif
- return -!ns558;
+ return 0;
}
void __exit ns558_exit(void)
#include <asm/uaccess.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
+
#define __NWBUTTON_C /* Tell the header file who we are */
#include "nwbutton.h"
#include <asm/dec21285.h>
#include <asm/io.h>
#include <asm/leds.h>
+#include <asm/mach-types.h>
#include <asm/system.h>
#include <asm/uaccess.h>
{ 0, 0}
};
-#ifdef CONFIG_SERIAL_RSA
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
#define PORT_RSA_MAX 4
static int probe_rsa[PORT_RSA_MAX];
static int force_rsa[PORT_RSA_MAX];
-#ifdef MODULE
MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
-#endif
#endif /* CONFIG_SERIAL_RSA */
static struct serial_state rs_table[RS_TABLE_SIZE] = {
--- /dev/null
+/*
+ * linux/drivers/char/serial_21285.c
+ *
+ * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
+ *
+ * Based on drivers/char/serial.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/dec21285.h>
+#include <asm/hardware.h>
+
+#define BAUD_BASE (mem_fclk_21285/64)
+
+#define SERIAL_21285_NAME "ttyFB"
+#define SERIAL_21285_MAJOR 204
+#define SERIAL_21285_MINOR 4
+
+#define SERIAL_21285_AUXNAME "cuafb"
+#define SERIAL_21285_AUXMAJOR 205
+#define SERIAL_21285_AUXMINOR 4
+
+static struct tty_driver rs285_driver, callout_driver;
+static int rs285_refcount;
+static struct tty_struct *rs285_table[1];
+
+static struct termios *rs285_termios[1];
+static struct termios *rs285_termios_locked[1];
+
+static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char;
+static struct tty_struct *rs285_tty;
+static int rs285_use_count;
+
+static int rs285_write_room(struct tty_struct *tty)
+{
+ return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1);
+}
+
+static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (!rs285_tty) {
+ disable_irq(IRQ_CONRX);
+ return;
+ }
+ while (!(*CSR_UARTFLG & 0x10)) {
+ int ch, flag;
+ ch = *CSR_UARTDR;
+ flag = *CSR_RXSTAT;
+ if (flag & 4)
+ tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN);
+ if (flag & 2)
+ flag = TTY_PARITY;
+ else if (flag & 1)
+ flag = TTY_FRAME;
+ tty_insert_flip_char(rs285_tty, ch, flag);
+ }
+ tty_flip_buffer_push(rs285_tty);
+}
+
+static void rs285_send_xchar(struct tty_struct *tty, char ch)
+{
+ x_char = ch;
+ enable_irq(IRQ_CONTX);
+}
+
+static void rs285_throttle(struct tty_struct *tty)
+{
+ if (I_IXOFF(tty))
+ rs285_send_xchar(tty, STOP_CHAR(tty));
+}
+
+static void rs285_unthrottle(struct tty_struct *tty)
+{
+ if (I_IXOFF(tty)) {
+ if (x_char)
+ x_char = 0;
+ else
+ rs285_send_xchar(tty, START_CHAR(tty));
+ }
+}
+
+static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ while (!(*CSR_UARTFLG & 0x20)) {
+ if (x_char) {
+ *CSR_UARTDR = x_char;
+ x_char = 0;
+ continue;
+ }
+ if (putp == getp) {
+ disable_irq(IRQ_CONTX);
+ break;
+ }
+ *CSR_UARTDR = *getp;
+ if (++getp >= wbuf + sizeof(wbuf))
+ getp = wbuf;
+ }
+ if (rs285_tty)
+ wake_up_interruptible(&rs285_tty->write_wait);
+}
+
+static inline int rs285_xmit(int ch)
+{
+ if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf))
+ return 0;
+ *putp = ch;
+ if (++putp >= wbuf + sizeof(wbuf))
+ putp = wbuf;
+ enable_irq(IRQ_CONTX);
+ return 1;
+}
+
+static int rs285_write(struct tty_struct *tty, int from_user,
+ const u_char * buf, int count)
+{
+ int i;
+
+ if (from_user && verify_area(VERIFY_READ, buf, count))
+ return -EINVAL;
+
+ for (i = 0; i < count; i++) {
+ char ch;
+ if (from_user)
+ __get_user(ch, buf + i);
+ else
+ ch = buf[i];
+ if (!rs285_xmit(ch))
+ break;
+ }
+ return i;
+}
+
+static void rs285_put_char(struct tty_struct *tty, u_char ch)
+{
+ rs285_xmit(ch);
+}
+
+static int rs285_chars_in_buffer(struct tty_struct *tty)
+{
+ return sizeof(wbuf) - rs285_write_room(tty);
+}
+
+static void rs285_flush_buffer(struct tty_struct *tty)
+{
+ disable_irq(IRQ_CONTX);
+ putp = getp = wbuf;
+ if (x_char)
+ enable_irq(IRQ_CONTX);
+}
+
+static inline void rs285_set_cflag(int cflag)
+{
+ int h_lcr, baud, quot;
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ h_lcr = 0x10;
+ break;
+ case CS6:
+ h_lcr = 0x30;
+ break;
+ case CS7:
+ h_lcr = 0x50;
+ break;
+ default: /* CS8 */
+ h_lcr = 0x70;
+ break;
+
+ }
+ if (cflag & CSTOPB)
+ h_lcr |= 0x08;
+ if (cflag & PARENB)
+ h_lcr |= 0x02;
+ if (!(cflag & PARODD))
+ h_lcr |= 0x04;
+
+ switch (cflag & CBAUD) {
+ case B200: baud = 200; break;
+ case B300: baud = 300; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ default:
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ }
+
+ /*
+ * The documented expression for selecting the divisor is:
+ * BAUD_BASE / baud - 1
+ * However, typically BAUD_BASE is not divisible by baud, so
+ * we want to select the divisor that gives us the minimum
+ * error. Therefore, we want:
+ * int(BAUD_BASE / baud - 0.5) ->
+ * int(BAUD_BASE / baud - (baud >> 1) / baud) ->
+ * int((BAUD_BASE - (baud >> 1)) / baud)
+ */
+ quot = (BAUD_BASE - (baud >> 1)) / baud;
+
+ *CSR_UARTCON = 0;
+ *CSR_L_UBRLCR = quot & 0xff;
+ *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
+ *CSR_H_UBRLCR = h_lcr;
+ *CSR_UARTCON = 1;
+}
+
+static void rs285_set_termios(struct tty_struct *tty, struct termios *old)
+{
+ if (old && tty->termios->c_cflag == old->c_cflag)
+ return;
+ rs285_set_cflag(tty->termios->c_cflag);
+}
+
+
+static void rs285_stop(struct tty_struct *tty)
+{
+ disable_irq(IRQ_CONTX);
+}
+
+static void rs285_start(struct tty_struct *tty)
+{
+ enable_irq(IRQ_CONTX);
+}
+
+static void rs285_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ int orig_jiffies = jiffies;
+ while (*CSR_UARTFLG & 8) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+ current->state = TASK_RUNNING;
+}
+
+static int rs285_open(struct tty_struct *tty, struct file *filp)
+{
+ int line;
+
+ MOD_INC_USE_COUNT;
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if (line) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+
+ tty->driver_data = NULL;
+ if (!rs285_tty)
+ rs285_tty = tty;
+
+ enable_irq(IRQ_CONRX);
+ rs285_use_count++;
+ return 0;
+}
+
+static void rs285_close(struct tty_struct *tty, struct file *filp)
+{
+ if (!--rs285_use_count) {
+ rs285_wait_until_sent(tty, 0);
+ disable_irq(IRQ_CONRX);
+ disable_irq(IRQ_CONTX);
+ rs285_tty = NULL;
+ }
+ MOD_DEC_USE_COUNT;
+}
+
+static int __init rs285_init(void)
+{
+ int baud = B9600;
+
+ if (machine_is_personal_server())
+ baud = B57600;
+
+ rs285_driver.magic = TTY_DRIVER_MAGIC;
+ rs285_driver.driver_name = "serial_21285";
+ rs285_driver.name = SERIAL_21285_NAME;
+ rs285_driver.major = SERIAL_21285_MAJOR;
+ rs285_driver.minor_start = SERIAL_21285_MINOR;
+ rs285_driver.num = 1;
+ rs285_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ rs285_driver.subtype = SERIAL_TYPE_NORMAL;
+ rs285_driver.init_termios = tty_std_termios;
+ rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL;
+ rs285_driver.flags = TTY_DRIVER_REAL_RAW;
+ rs285_driver.refcount = &rs285_refcount;
+ rs285_driver.table = rs285_table;
+ rs285_driver.termios = rs285_termios;
+ rs285_driver.termios_locked = rs285_termios_locked;
+
+ rs285_driver.open = rs285_open;
+ rs285_driver.close = rs285_close;
+ rs285_driver.write = rs285_write;
+ rs285_driver.put_char = rs285_put_char;
+ rs285_driver.write_room = rs285_write_room;
+ rs285_driver.chars_in_buffer = rs285_chars_in_buffer;
+ rs285_driver.flush_buffer = rs285_flush_buffer;
+ rs285_driver.throttle = rs285_throttle;
+ rs285_driver.unthrottle = rs285_unthrottle;
+ rs285_driver.send_xchar = rs285_send_xchar;
+ rs285_driver.set_termios = rs285_set_termios;
+ rs285_driver.stop = rs285_stop;
+ rs285_driver.start = rs285_start;
+ rs285_driver.wait_until_sent = rs285_wait_until_sent;
+
+ callout_driver = rs285_driver;
+ callout_driver.name = SERIAL_21285_AUXNAME;
+ callout_driver.major = SERIAL_21285_AUXMAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL))
+ panic("Couldn't get rx irq for rs285");
+
+ if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL))
+ panic("Couldn't get tx irq for rs285");
+
+ if (tty_register_driver(&rs285_driver))
+ printk(KERN_ERR "Couldn't register 21285 serial driver\n");
+ if (tty_register_driver(&callout_driver))
+ printk(KERN_ERR "Couldn't register 21285 callout driver\n");
+
+ return 0;
+}
+
+static void __exit rs285_fini(void)
+{
+ unsigned long flags;
+ int ret;
+
+ save_flags(flags);
+ cli();
+ ret = tty_unregister_driver(&callout_driver);
+ if (ret)
+ printk(KERN_ERR "Unable to unregister 21285 callout driver "
+ "(%d)\n", ret);
+ ret = tty_unregister_driver(&rs285_driver);
+ if (ret)
+ printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n",
+ ret);
+ free_irq(IRQ_CONTX, NULL);
+ free_irq(IRQ_CONRX, NULL);
+ restore_flags(flags);
+}
+
+module_init(rs285_init);
+module_exit(rs285_fini);
+
+#ifdef CONFIG_SERIAL_21285_CONSOLE
+/************** console driver *****************/
+
+static void rs285_console_write(struct console *co, const char *s, u_int count)
+{
+ int i;
+
+ disable_irq(IRQ_CONTX);
+ for (i = 0; i < count; i++) {
+ while (*CSR_UARTFLG & 0x20);
+ *CSR_UARTDR = s[i];
+ if (s[i] == '\n') {
+ while (*CSR_UARTFLG & 0x20);
+ *CSR_UARTDR = '\r';
+ }
+ }
+ enable_irq(IRQ_CONTX);
+}
+
+static int rs285_console_wait_key(struct console *co)
+{
+ int c;
+
+ disable_irq(IRQ_CONRX);
+ while (*CSR_UARTFLG & 0x10);
+ c = *CSR_UARTDR;
+ enable_irq(IRQ_CONRX);
+ return c;
+}
+
+static kdev_t rs285_console_device(struct console *c)
+{
+ return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
+}
+
+static int __init rs285_console_setup(struct console *co, char *options)
+{
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+
+ if (machine_is_personal_server())
+ baud = 57600;
+
+ if (options) {
+ char *s = options;
+ baud = simple_strtoul(options, NULL, 10);
+ while (*s >= '0' && *s <= '9')
+ s++;
+ if (*s)
+ parity = *s++;
+ if (*s)
+ bits = *s - '0';
+ }
+
+ /*
+ * Now construct a cflag setting.
+ */
+ switch (baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 9600:
+ cflag |= B9600;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 57600:
+ cflag |= B57600;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ default:
+ cflag |= B9600;
+ break;
+ }
+ switch (bits) {
+ case 7:
+ cflag |= CS7;
+ break;
+ default:
+ cflag |= CS8;
+ break;
+ }
+ switch (parity) {
+ case 'o':
+ case 'O':
+ cflag |= PARODD;
+ break;
+ case 'e':
+ case 'E':
+ cflag |= PARENB;
+ break;
+ }
+ co->cflag = cflag;
+ rs285_set_cflag(cflag);
+ rs285_console_write(NULL, "\e[2J\e[Hboot ", 12);
+ if (options)
+ rs285_console_write(NULL, options, strlen(options));
+ else
+ rs285_console_write(NULL, "no options", 10);
+ rs285_console_write(NULL, "\n", 1);
+
+ return 0;
+}
+
+static struct console rs285_cons =
+{
+ SERIAL_21285_NAME,
+ rs285_console_write,
+ NULL,
+ rs285_console_device,
+ rs285_console_wait_key,
+ NULL,
+ rs285_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+void __init rs285_console_init(void)
+{
+ register_console(&rs285_cons);
+}
+
+#endif /* CONFIG_SERIAL_21285_CONSOLE */
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
-#include <asm/system.h>
+#include <asm/mach-types.h>
#include <asm/dec21285.h>
/*
fi
dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
- bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ if [ "$CONFIG_ISDN_DRV_EICON_STANDALONE" != "y" ]; then
+ if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI
+ fi
+ bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ fi
+ if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' build eicon driver type standalone' CONFIG_ISDN_DRV_EICON_STANDALONE
+ fi
fi
dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <linux/fs.h>
+#undef N_DATA
+
+#include <linux/kernel.h>
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <errno.h>
+
+#include "adapter.h"
+#include "uxio.h"
+
+#ifdef MODULE
+#include "idi.h"
+void EtdM_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#define Divas_init init_module
+#endif
+
+extern char *file_check(void);
+
+int DivasCardsDiscover(void);
+
+int
+Divas_init(void)
+{
+ printk(KERN_DEBUG "DIVA Server Driver - initialising\n");
+
+ printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.12 (%s)\n",file_check());
+
+
+#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;
+}
+
+#ifdef MODULE
+void
+cleanup_module(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");
+}
+
+void mod_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+void mod_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+#else
+Divas_setup(char *str, int *ints)
+{
+}
+#endif
+
L_OBJS :=
M_OBJS :=
-O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
+LX_OBJS :=
+MX_OBJS :=
+O_OBJS :=
+OX_OBJS :=
+L_TARGET :=
+O_TARGET :=
+
+ifeq ($(CONFIG_ISDN_DRV_EICON_STANDALONE),y)
+
+ ifeq ($(CONFIG_PCI),y)
+ O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o
+ O_OBJS += lincfg.o linchr.o linsys.o linio.o
+ O_OBJS += fcheck.o
+ OX_OBJS += Divas_mod.o
+ endif
+
+else
+
+ OX_OBJS += eicon_mod.o
+ O_OBJS := eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
+ O_OBJS += fcheck.o
+ ifeq ($(CONFIG_PCI),y)
+ ifeq ($(CONFIG_ISDN_DRV_EICON_PCI),y)
+ O_OBJS += common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o fourbri.o
+ O_OBJS += lincfg.o linchr.o linsys.o linio.o
+ endif
+ endif
+
+endif
O_TARGET :=
+
ifeq ($(CONFIG_ISDN_DRV_EICON),y)
O_TARGET += eicon.o
else
M_OBJS = eicon.o
endif
+
include $(TOPDIR)/Rules.make
+
+MD5FILES += common.c idi.c bri.c pri.c log.c xlog.c kprintf.c fpga.c \
+ fourbri.c fcheck.c
+
+FCHECK = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
+
+fcheck.o: $(MD5FILES)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D FILECHECK=$(FCHECK) -c -o fcheck.o fcheck.c
+
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <sys/types.h>
+
+#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);
+
+#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);
+int bri_ISR (card_t* card);
+
+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; i<dwLength; i++)
+ {
+ dwAddr = r3000_base + i;
+
+ UxCardPortIoOut(card->hw, 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, 0);
+
+ 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);
+}
+
+
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <sys/types.h>
+
+#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[16];
+static
+int DIDD_Length = 0;
+
+void EtdM_DIDD_Read( DESCRIPTOR *table, int *tablelength )
+{
+ int table_size = sizeof(DIDD_Table);
+
+ bcopy((caddr_t)DIDD_Table, (caddr_t)table, table_size);
+
+ *tablelength = DIDD_Length;
+
+ return;
+}
+
+static
+void EtdM_DIDD_Write(DESCRIPTOR *table, int tablelength)
+{
+ int table_size = sizeof(DIDD_Table);
+
+ bcopy((caddr_t)table, (caddr_t)DIDD_Table, table_size);
+
+ DIDD_Length = tablelength;
+
+ return;
+}
+
+static
+void init_idi_tab(void)
+{
+ int length = 0;
+
+ DESCRIPTOR d[16];
+
+ EtdM_DIDD_Read(d, &length);
+
+ d[length].type = IDI_DIMAINT; /* identify the DIMAINT entry */
+ d[length].channels = 0; /* zero channels associated with dimaint*/
+ d[length].features = 0; /* no features associated with dimaint */
+ d[length].request = (IDI_CALL) DivasPrintf;
+ length++;
+
+ EtdM_DIDD_Write(d, length);
+
+ 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[16];
+ 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;
+
+ EtdM_DIDD_Read(d, &length);
+
+ 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++;
+
+ EtdM_DIDD_Write(d, length);
+
+ 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;
+}
+
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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:
+ <word> reconfigure delay (in 8kHz samples)
+ <word> reconfigure code
+ <byte> 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
+ <byte> data 0
+ <byte> data 1
+ ...
+
+data indications if HDLC framer
+ <byte> data 0
+ <byte> data 1
+ ...
+ <byte> CRC 0
+ <byte> CRC 1
+ <byte> preamble flags
+*/
+
+#define DSP_UDATA_INDICATION_SYNC 0
+/*
+returns:
+ <word> time of sync (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_OFF 1
+/*
+returns:
+ <word> time of DCD off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_ON 2
+/*
+returns:
+ <word> time of DCD on (sampled from counter at 8kHz)
+ <byte> connected norm
+ <word> connected options
+ <dword> connected speed (bit/s)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_OFF 3
+/*
+returns:
+ <word> time of CTS off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_ON 4
+/*
+returns:
+ <word> time of CTS on (sampled from counter at 8kHz)
+ <byte> connected norm
+ <word> connected options
+ <dword> 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
+
+/*---------------------------------------------------------------------------*/
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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
+
+/*---------------------------------------------------------------------------*/
-/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon.h,v 1.23 2000/06/21 11:28:42 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
* 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.
- *
- *
*/
#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
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 */
unsigned char data[700];
} eicon_manifbuf;
+#define TRACE_OK (1)
#ifdef __KERNEL__
#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) { \
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 */
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 */
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 */
#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
#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;
__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_...) */
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;
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 *);
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 */
-/* $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
* 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:
- <word> reconfigure delay (in 8kHz samples)
- <word> reconfigure code
- <byte> 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
- <byte> data 0
- <byte> data 1
- ...
-
-data indications if HDLC framer
- <byte> data 0
- <byte> data 1
- ...
- <byte> CRC 0
- <byte> CRC 1
- <byte> preamble flags
-*/
#define DSP_UDATA_REQUEST_SWITCH_FRAMER 1
/*
- none -
*/
-
-#define DSP_UDATA_INDICATION_SYNC 0
-/*
-returns:
- <word> time of sync (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_OFF 1
-/*
-returns:
- <word> time of DCD off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_ON 2
-/*
-returns:
- <word> time of DCD on (sampled from counter at 8kHz)
- <byte> connected norm
- <word> connected options
- <dword> connected speed (bit/s, max of tx and rx speed)
- <word> roundtrip delay (ms)
- <dword> connected speed tx (bit/s)
- <dword> connected speed rx (bit/s)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_OFF 3
-/*
-returns:
- <word> time of CTS off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_ON 4
-/*
-returns:
- <word> time of CTS on (sampled from counter at 8kHz)
- <byte> connected norm
- <word> connected options
- <dword> connected speed (bit/s, max of tx and rx speed)
- <word> roundtrip delay (ms)
- <dword> connected speed tx (bit/s)
- <dword> connected speed rx (bit/s)
-*/
-
typedef struct eicon_dsp_ind {
__u16 time __attribute__ ((packed));
__u8 norm __attribute__ ((packed));
__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:
#define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04
#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05
-
#define DSP_UDATA_INDICATION_TX_CONFIRMATION 6
/*
returns:
-/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $
+/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* IDI interface
* 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 <adams@ipcon.de>
- * 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 <xfl23@dial.pipex.com>
- *
- * 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 <linux/config.h>
#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 $";
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);
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 */
}
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;
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 */
}
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)
{
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:
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;
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 N_CONNECT|0x700:
+ idi_put_req(reqbuf, N_CONNECT, 1, 0);
break;
- case IDI_N_CONNECT_ACK|0x700:
- idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0);
+ case N_CONNECT_ACK|0x700:
+ idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0);
break;
- case IDI_N_DISC|0x700:
- idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh);
+ case N_DISC|0x700:
+ idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh);
break;
- case IDI_N_DISC_ACK|0x700:
- idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh);
+ 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);
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) {
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)
{
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; i<tmp;i++)
reqbuf->XBuffer.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:
}
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:
}
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;
}
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 ***************************/
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;
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
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
if (chan->queued + skb->len > 1200)
return 0;
+ if (chan->pqueued > 1)
+ return 0;
InBuf.Data = skb->data;
InBuf.Size = skb->len;
}
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;
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;
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;
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) &&
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;
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;
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);
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:
/* 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)
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);
}
}
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;
}
}
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;
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;
}
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);
}
#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) {
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
{
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 ! */
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;
}
} 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) &&
}
#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,
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:
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)) {
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);
case UNKNOWN_COMMAND:
case WRONG_COMMAND:
case WRONG_ID:
+ case ADAPTER_DEAD:
case WRONG_CH:
case UNKNOWN_IE:
case WRONG_IE:
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;
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;
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);
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;
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;
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 */
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;
-/* $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
* 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 <linux/config.h>
-#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];
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;
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);
-/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Code for communicating with hardware.
* 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 <linux/config.h>
#include "eicon.h"
+#include "uxio.h"
void
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:
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) {
}
}
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;
}
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;
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;
}
}
/*
- * 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;
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) {
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;
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 */
} 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)
}
}
-
+#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;
}
}
- 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:
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;
if (*irqprobe) {
switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
}
(*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:
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) {
/* clear interrupt */
switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_QUADRO:
writeb(0, isa_card->intack);
writeb(0, &com[0x401]);
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
-/* $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.
* 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 <linux/config.h>
#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
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;
-/* $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.
*
* 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
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 */
-/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_mod.c,v 1.35 2000/08/12 18:00:47 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
*
* Thanks to Eicon Technology GmbH & Co. oHG 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.
* 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 ".14"
+
#include <linux/config.h>
#include <linux/module.h>
#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.35 $";
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);
+void mod_inc_use_count(void);
+void mod_dec_use_count(void);
+extern char *file_check(void);
+
#ifdef MODULE
#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
#endif
ulong DebugVar;
+spinlock_t eicon_lock;
+
+DESCRIPTOR idi_d[16];
+int idi_dlength;
+
/* Parameters to be set by insmod */
#ifdef CONFIG_ISDN_DRV_EICON_ISA
static int membase = -1;
"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)
{
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)
}
}
-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;
+#endif
+#endif
isdn_ctrl cmd;
- char tmp[17];
int ret = 0;
unsigned long flags;
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",
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",
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,
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:
#ifdef MODULE
case EICON_IOCTL_FREEIT:
while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT;
- MOD_INC_USE_COUNT;
+ 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) {
+ EtdM_DIDD_Read(idi_d, &idi_dlength);
+ card->d = &idi_d[idi_dlength - 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, SerNo. %d)\n",
+ (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI",
+ card->d->channels, card->d->features, card->d->serial);
+ } else {
+ int i;
+ EtdM_DIDD_Read(idi_d, &idi_dlength);
+ 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_dlength - (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, SerNo. %d)\n",
+ 4-i, card->d->channels, card->d->features, card->d->serial);
+ }
+ }
+ }
+ return ret;
+#else
+ return -EINVAL;
+#endif
+#endif /* CONFIG_PCI */
}
break;
case ISDN_CMD_DIAL:
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,
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:
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:
eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n");
return 0;
case ISDN_CMD_LOCK:
- MOD_INC_USE_COUNT;
+#ifdef MODULE
+ mod_inc_use_count();
+#endif
return 0;
case ISDN_CMD_UNLOCK:
- MOD_DEC_USE_COUNT;
+#ifdef MODULE
+ mod_dec_use_count();
+#endif
return 0;
#ifdef CONFIG_ISDN_TTY_FAX
case ISDN_CMD_FAXCMD:
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;
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)
} 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
}
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;
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;
}
} else
card->statq_entries++;
- restore_flags(flags);
+ spin_unlock_irqrestore(&eicon_lock, flags);
if (count) {
cmd.command = ISDN_STAT_STAVAIL;
cmd.driver = card->myid;
* 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;
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++) {
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 |
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;
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 |
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;
card->interface.channels = 1;
break;
#endif
+#endif
#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_ISABRI:
if (membase == -1)
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;
}
#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",
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",
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;
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;
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
return (added - failed);
}
-#define DRIVERNAME "Eicon active ISDN driver"
-#define DRIVERRELEASE "1"
#ifdef MODULE
#define eicon_init init_module
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 (%s)\n", DRIVERNAME,
+ DRIVERRELEASE, DRIVERPATCH, file_check());
#ifdef CONFIG_ISDN_DRV_EICON_ISA
#ifdef CONFIG_MCA
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
} 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 mod_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+void mod_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+void EtdM_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#else
+int DivasCardNext;
+card_t DivasCards[1];
+#endif
+
void
cleanup_module(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
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);
}
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);
-/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_pci.c,v 1.15 2000/06/12 12:44:02 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for PCI cards.
* Thanks to Eicon Technology GmbH & Co. oHG 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)
* 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 <linux/config.h>
#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 $";
#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_enable_device(pdev); /* XXX handle error return */
-
- 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 = pci_resource_start(pdev, 2);
- pcfg = pci_resource_start(pdev, 1);
-
-#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 = pci_resource_start(pdev, 0);
- preg = pci_resource_start(pdev, 2);
- pcfg = pci_resource_start(pdev, 4);
-
-#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");
+ 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;
}
- 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");
- }
- 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; i<length; i+=2)
- {
- outb ((u8) ((p_para->dat.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; i<length; i+=2)
- {
- outb ((u8) ((p_para->dat.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<length; i+=4)
- {
- writel(((u32 *)buffer)[i >> 2], &boot->data[i]);
- }
- if (verify) /* check written block */
- {
- for (i=0; i<length; i+=4)
- {
- dwdata = readl(&boot->data[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);
- }
- 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);
+ 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;
}
-
-#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 */
-/* $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).
*
* 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
#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 */
+
--- /dev/null
+/* $Id: fcheck.c,v 1.3 2000/06/12 12:44:02 armin Exp $
+ *
+ * (c) 2000 Cytronics & Melware
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ * For changes and modifications please read
+ * ../../../Documentation/isdn/README.eicon
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+
+char *
+file_check(void) {
+
+#ifdef FILECHECK
+#if FILECHECK == 0
+ return("verified");
+#endif
+#if FILECHECK == 1
+ return("modified");
+#endif
+#if FILECHECK == 127
+ return("verification failed");
+#endif
+#else
+ return("not verified");
+#endif
+}
+
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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);
+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], 0);
+ 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);
+}*/
+
+
+int fourbri_ISR (card_t* card)
+{
+ int served = 0;
+ byte *ctl;
+ byte *reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+ if (UxCardPortIoIn(card->hw, reg, PLX9054_INTCSR) & 0x80)
+ {
+ served = 1;
+ 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);
+ }
+
+ UxCardMemDetach(card->hw, reg);
+ return (served != 0);
+}
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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<FPGA_LEN; i++)
+ {
+ //--- put byte onto FPGA
+ for (j=0; j<8; j++)
+ {
+ if (FPGA_SRC[i] &(0x80>>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;
+}
+
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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(i<this->XNum && 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(i<this->XNum && 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: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
+ }
+#else
+ DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
+#endif
+
+ /* check for ready interrupt */
+ if(Rc==READY_INT) {
+ if(a->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: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
+ }
+#else
+ DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
+#endif
+
+ if(a->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;
+}
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 EtdM_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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <stdarg.h>
+#undef MAX
+#undef MIN
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#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;
+}
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <linux/fs.h>
+#undef N_DATA /* Because we have our own definition */
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#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 <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+
+#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;
+}
+
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+
+#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;
+}
+int private_usage_count;
+extern void mod_inc_use_count(void);
+extern void mod_dec_use_count(void);
+
+int do_open(struct inode *pInode, struct file *pFile)
+{
+#if defined(MODULE)
+ mod_inc_use_count();
+ private_usage_count++;
+#endif
+ return 0;
+}
+
+int do_release(struct inode *pInode, struct file *pFile)
+{
+#if defined(MODULE)
+ mod_dec_use_count();
+ private_usage_count--;
+#endif
+ return 0;
+}
+
+void UnlockDivas(void)
+{
+ while (private_usage_count > 0)
+ {
+ private_usage_count--;
+#if defined(MODULE)
+ mod_dec_use_count();
+#endif
+ }
+}
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <asm/io.h>
+#include <asm/system.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#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);
+
+}
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <linux/sched.h>
+#undef N_DATA
+#include <linux/tqueue.h>
+
+#include <linux/smp.h>
+struct pt_regs;
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#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;
+}
+
+/* #################################################################################### */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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;
+}
--- /dev/null
+# These are valid md5sums to detect modifications
+# in eicon driver files provided by Eicon Technology.
+# For changes and modifications in these files please
+# read ../../../Documentation/isdn/README.eicon
+#
+9b0e381d4558af3a6eba66843e1ee5d9 common.c
+dbb92cba52db31ff8325a252b3f595c3 idi.c
+15687687ef82f099966ed42772001cd3 bri.c
+c3e3b720c3351b66635bd548195e29e8 pri.c
+b0a6d2ab49bcfcfd1825860f178a84b4 log.c
+673746176316b72271a09c0a27287a01 xlog.c
+07e1bbabdb4d69880db196ef31bfb241 kprintf.c
+b60b40ad630f26b7923369df95b4d1b9 fpga.c
+5013ecca0a38a8fcc4a61642754f2076 fourbri.c
+1501ae468a0c5eaab1e60720fa723a67 fcheck.c
+# end of md5sums
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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);
+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], 0);
+ 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; i<length; i++)
+ {
+ UxCardMemOut(card->hw, &boot->data[i], load->code[offset+i]);
+ }
+
+ for (i=0; i<length; i++)
+ {
+ if (load->code[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;
+}
+
+
+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);
+}
+
+
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 <linux/kernel.h>
+#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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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 */
--- /dev/null
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * This source file is supplied for the exclusive use with Eicon
+ * Technology Corporation's range of DIVA Server Adapters.
+ *
+ * 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;
+}
fi
fi
dep_tristate ' Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD
- dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD
+ dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI
if [ "$CONFIG_MTD_PMC551" != "n" ]; then
bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
fi
- Print a warning on out-of-memory (rate limited to 1 per 10 secs)
- Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland)
+ LK1.1.7 2 Jul 2000 andrewm
+ - Better handling of shared IRQs
+ - Reset the transmitter on a Tx reclaim error
+ - Fixed crash under OOM during vortex_open() (Mark Hemment)
+ - Fix Rx cessation problem during OOM (help from Mark Hemment)
+ - The spinlocks around the mdio access were blocking interrupts for 300uS.
+ Fix all this to use spin_lock_bh() within mdio_read/write
+ - Only write to TxFreeThreshold if it's a boomerang - other NICs don't
+ have one.
+ - Added 802.3x MAC-layer flow control support
+
+ LK1.1.8 13 Aug 2000 andrewm
+ - Ignore request_region() return value - already reserved if Cardbus.
+ - Merged some additional Cardbus flags from Don's 0.99Qk
+ - Some fixes for 3c556 (Fred Maciel)
+ - Fix for EISA initialisation (Jan Rkorajski)
+ - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers
+ - Fixed MII_XCVR_PWR for 3CCFE575CT
+ - Added INVERT_LED_PWR, used it.
+ - Backed out the extra_reset stuff
+
- See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
+ - Also see Documentation/networking/vortex.txt
*/
/*
static const int mtu = 1500;
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 32;
-/* Give the NIC an extra reset at the end of vortex_up() */
-static int extra_reset = 0;
/* Tx timeout interval (millisecs) */
static int watchdog = 400;
#include <linux/delay.h>
static char version[] __devinitdata =
-"3c59x.c:v0.99L+LK1.1.6 28 May 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.97 $\n";
+"3c59x.c:LK1.1.8 13 Aug 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.25 $\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
MODULE_PARM(debug, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(extra_reset, "i");
MODULE_PARM(compaq_ioaddr, "i");
MODULE_PARM(compaq_irq, "i");
MODULE_PARM(compaq_device_id, "i");
};
enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
- EEPROM_230=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
- HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, };
+ EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
+ HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
+ INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400 };
enum vortex_chips {
CH_3CSOHO100_TX,
CH_3C555,
+ CH_3C556,
CH_3C575,
CH_3C575_1,
- CH_3CCFE575,
+ CH_3CCFE575,
CH_3CCFE575CT,
CH_3CCFE656,
CH_3CCFEM656,
CH_3CCFEM656_1,
+
CH_3C450,
};
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
{"3c555 Laptop Hurricane",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c556 10/100 Mini PCI Adapter",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, },
{"3c575 [Megahertz] 10/100 LAN CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
{"3c575 Boomerang CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_230, 128, },
- {"3CCFE575 Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+ {"3CCFE575BT Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, },
{"3CCFE575CT Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, },
{"3CCFE656 Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
- {"3CCFEM656 Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
- {"3CCFEM656 Cyclone CardBus(0x6564)", /* From pcmcia-cs-3.1.5 */
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_230, 128, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, },
+ {"3CCFEM656B Cyclone+Winmodem CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, },
+ {"3CCFE656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, },
+
{"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */
PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, },
-
{0,}, /* 0 terminated list. */
};
{ 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
{ 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
+ { 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 },
{ 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 },
{ 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
- { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
+ { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
{ 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
{ 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
{ 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
{ 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 },
- { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
+ { 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
{0,} /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
/* The remainder are related to chip state, mostly media selection. */
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_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
- hw_csums:1, /* Has hardware checksums. */
+ flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */
+ partner_flow_ctrl:1, /* Partner supports flow control */
tx_full:1,
has_nway:1,
- open:1;
+ open:1,
+ must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */
+ int drv_flags;
int tx_reset_resume; /* Flag to retart timer after vortex_error handling */
u16 status_enable;
u16 intr_enable;
u16 deferred; /* Resend these interrupts when we
* bale from the ISR */
u16 io_size; /* Size of PCI region (for release_region) */
- spinlock_t lock;
+ spinlock_t lock; /* Serialise access to device & its vortex_private */
+ spinlock_t mdio_lock; /* Serialise access to mdio hardware */
};
/* The action to take with a media selection timer tick.
static void vortex_down(struct net_device *dev);
static int vortex_open(struct net_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 int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *vp, 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 net_device *dev);
static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int vortex_rx(struct net_device *dev);
#define MAX_UNITS 8
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 flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* #define dev_alloc_skb dev_alloc_skb_debug */
/* A list of all installed Vortex EISA devices, for removing the driver module. */
static struct net_device *root_vortex_eisa_dev = NULL;
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
int device_id;
- if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
+ if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "3c59x") == NULL)
continue;
/* Check the standard EISA ID register for an encoded '3Com'. */
return vortex_cards_found - orig_cards_found;
}
-
/* returns count (>= 0), or negative on error */
static int __devinit vortex_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
if (!printed_version) {
printk (KERN_INFO "%s", version);
+ printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
printed_version = 1;
}
dev->base_addr = ioaddr;
dev->irq = irq;
dev->mtu = mtu;
+ vp->drv_flags = vci->drv_flags;
vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
vp->io_size = vci->io_size;
/* PCI-only startup logic */
if (pdev) {
/* EISA resources already marked, so only PCI needs to do this here */
- if (!request_region (ioaddr, vci->io_size, dev->name)) {
- printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
- dev->name, vci->io_size, ioaddr);
- retval = -EBUSY;
- goto free_dev;
+ /* Ignore return value, because Cardbus drivers already allocate for us */
+ if (request_region(ioaddr, vci->io_size, dev->name) != NULL) {
+ vp->must_free_region = 1;
}
/* wake up and enable device */
pci_set_master (pdev);
}
- vp->lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&vp->lock);
+ spin_lock_init(&vp->mdio_lock);
vp->pdev = pdev;
/* Makes sure rings are at least 16 byte aligned. */
vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
&vp->rx_ring_dma);
- if (vp->rx_ring == 0)
- {
+ if (vp->rx_ring == 0) {
retval = -ENOMEM;
goto free_region;
}
pdev->driver_data = dev;
/* The lower four bits are the media type. */
- if (dev->mem_start)
- { /*
+ if (dev->mem_start) {
+ /*
* AKPM: ewww.. The 'options' param is passed in as the third arg to the
* LILO 'ether=' argument for non-modular use
*/
else
option = -1;
+ vp->media_override = 7;
if (option >= 0) {
vp->media_override = ((option & 7) == 2) ? 0 : option & 15;
vp->full_duplex = (option & 0x200) ? 1 : 0;
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;
+
+ if (card_idx < MAX_UNITS) {
+ if (full_duplex[card_idx] > 0)
+ vp->full_duplex = 1;
+ if (flow_ctrl[card_idx] > 0)
+ vp->flow_ctrl = 1;
+ }
vp->force_fd = vp->full_duplex;
vp->options = option;
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
{
- int base = (vci->drv_flags & EEPROM_230) ? 0x230 : EEPROM_Read;
+ int base = (vci->drv_flags & EEPROM_8BIT) ? 0x230 : EEPROM_Read;
for (i = 0; i < 0x40; i++) {
int timer;
outw(base + i, ioaddr + Wn0EepromCmd);
if (pdev && vci->drv_flags & HAS_CB_FNS) {
unsigned long fn_st_addr; /* Cardbus function status space */
+ unsigned short n;
+
fn_st_addr = pci_resource_start (pdev, 2);
if (fn_st_addr)
vp->cb_fn_base = ioremap(fn_st_addr, 128);
printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
dev->name, fn_st_addr, vp->cb_fn_base);
-#if 1 /* AKPM: the 575_cb and 905B LEDs seem OK without this */
- if (vortex_pci_tbl[chip_idx].device != 0x5257) {
- EL3WINDOW(2);
- outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
- }
-#endif
+ EL3WINDOW(2);
+
+ n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;
+ if (vp->drv_flags & INVERT_LED_PWR)
+ n |= 0x10;
+ if (vp->drv_flags & INVERT_MII_PWR)
+ n |= 0x4000;
+ outw(n, ioaddr + Wn2_ResetOptions);
}
/* Extract our information from the EEPROM data. */
vp->info2 = eeprom[15];
vp->capabilities = eeprom[16];
- if (vp->info1 & 0x8000)
- {
+ if (vp->info1 & 0x8000) {
vp->full_duplex = 1;
printk(KERN_INFO "Full duplex capable\n");
}
EL3WINDOW(4);
mii_preamble_required++;
mii_preamble_required++;
- mdio_read(ioaddr, 24, 1);
+ mdio_read(dev, 24, 1);
for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) {
int mii_status, phyx = phy & 0x1f;
- mii_status = mdio_read(ioaddr, phyx, 1);
+ mii_status = mdio_read(dev, phyx, 1);
if (mii_status && mii_status != 0xffff) {
vp->phys[phy_idx++] = phyx;
printk(KERN_INFO " MII transceiver found at address %d,"
printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n");
vp->phys[0] = 24;
} else {
- vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
+ vp->advertising = mdio_read(dev, vp->phys[0], 4);
if (vp->full_duplex) {
/* Only advertise the FD media types. */
vp->advertising &= ~0x02A0;
- mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
+ mdio_write(dev, vp->phys[0], 4, vp->advertising);
}
}
}
}
/* The 3c59x-specific entries in the device structure. */
- dev->open = &vortex_open;
- dev->hard_start_xmit = &vortex_start_xmit;
- dev->stop = &vortex_close;
- dev->get_stats = &vortex_get_stats;
- dev->do_ioctl = &vortex_ioctl;
- dev->set_multicast_list = &set_rx_mode;
- dev->tx_timeout = &vortex_tx_timeout;
+ dev->open = vortex_open;
+ dev->hard_start_xmit = vp->full_bus_master_tx ?
+ boomerang_start_xmit : vortex_start_xmit;
+ dev->stop = vortex_close;
+ dev->get_stats = vortex_get_stats;
+ dev->do_ioctl = vortex_ioctl;
+ dev->set_multicast_list = set_rx_mode;
+ dev->tx_timeout = vortex_tx_timeout;
dev->watchdog_timeo = (watchdog * HZ) / 1000;
return 0;
free_region:
- release_region (ioaddr, vci->io_size);
-free_dev:
+ if (vp->must_free_region)
+ release_region(ioaddr, vci->io_size);
unregister_netdev(dev);
kfree (dev);
printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval);
int i = 4000;
outw(cmd, dev->base_addr + EL3_CMD);
- while (--i > 0)
- {
+ while (--i > 0) {
if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
return;
}
init_timer(&vp->timer);
vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
vp->timer.data = (unsigned long)dev;
- vp->timer.function = &vortex_timer; /* timer handler */
+ 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;
+
if (vortex_debug > 1)
printk(KERN_DEBUG "%s: Initial media type %s.\n",
dev->name, media_tbl[dev->if_port].name);
int mii_reg1, mii_reg5;
EL3WINDOW(4);
/* Read BMSR (reg1) only to clear old status. */
- mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
- mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+ mii_reg1 = mdio_read(dev, vp->phys[0], 1);
+ mii_reg5 = mdio_read(dev, 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 */
vp->full_duplex = 1;
+ vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
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],
}
/* Set the full-duplex bit. */
- outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
- (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+ outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+ (dev->mtu > 1500 ? 0x40 : 0) |
+ ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0),
+ ioaddr + Wn3_MAC_Ctrl);
if (vortex_debug > 1) {
printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n",
outw(0, ioaddr + i);
if (vp->cb_fn_base) {
- u_short n = inw(ioaddr + Wn2_ResetOptions);
-#if 0 /* AKPM: This is done in vortex_probe1, and seems to be wrong anyway... */
- /* Inverted LED polarity */
- if (device_id != 0x5257)
- n |= 0x0010;
-#endif
- /* Inverted polarity of MII power bit */
- if ((device_id == 0x6560) || (device_id == 0x6562) ||
- (device_id == 0x5257))
+ unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;
+ if (vp->drv_flags & INVERT_LED_PWR)
+ n |= 0x10;
+ if (vp->drv_flags & INVERT_MII_PWR)
n |= 0x4000;
outw(n, ioaddr + Wn2_ResetOptions);
}
outl(vp->rx_ring_dma, ioaddr + UpListPtr);
}
if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
- dev->hard_start_xmit = &boomerang_start_xmit;
vp->cur_tx = vp->dirty_tx = 0;
- outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
+ if (vp->drv_flags & IS_BOOMERANG)
+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
/* Clear the Rx, Tx rings. */
for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */
vp->rx_ring[i].status = 0;
outw(vp->intr_enable, ioaddr + EL3_CMD);
if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
writel(0x8000, vp->cb_fn_base + 4);
-
- if (extra_reset)
- {
- /* AKPM: unjam the 3CCFE575CT */
- wait_for_completion(dev, TxReset);
- if (vp->full_bus_master_tx) {
- outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
- outw(DownUnstall, ioaddr + EL3_CMD);
- }
- outw(TxEnable, ioaddr + EL3_CMD);
- }
netif_start_queue (dev);
}
MOD_INC_USE_COUNT;
/* Use the now-standard shared IRQ implementation. */
- if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt,
- SA_SHIRQ, dev->name, dev)) {
- retval = -EAGAIN;
+ if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
+ &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) {
+ printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
goto out;
}
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
}
+ if (i != RX_RING_SIZE) {
+ int j;
+ for (j = 0; j < RX_RING_SIZE; j++) {
+ if (vp->rx_skbuff[j]) {
+ dev_kfree_skb(vp->rx_skbuff[j]);
+ vp->rx_skbuff[j] = 0;
+ }
+ }
+ retval = -ENOMEM;
+ goto out_free_irq;
+ }
/* Wrap the ring. */
vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
}
vortex_up(dev);
vp->open = 1;
return 0;
+
+out_free_irq:
+ free_irq(dev->irq, dev);
out:
- MOD_DEC_USE_COUNT;
if (vortex_debug > 1)
- printk(KERN_ERR PFX "vortex_open() fails: returning %d\n", retval);
+ printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval);
+ MOD_DEC_USE_COUNT;
return retval;
}
int ok = 0;
int media_status, mii_status, old_window;
- if (vortex_debug > 1) {
+ if (vortex_debug > 2) {
printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
dev->name, media_tbl[dev->if_port].name);
printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
break;
case XCVR_MII: case XCVR_NWAY:
{
- unsigned long flags;
- spin_lock_irqsave(&vp->lock, flags); /* AKPM: protect mdio state */
-
- mii_status = mdio_read(ioaddr, vp->phys[0], 1);
+ mii_status = mdio_read(dev, vp->phys[0], 1);
ok = 1;
- if (vortex_debug > 1)
+ if (vortex_debug > 2)
printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
dev->name, mii_status);
if (mii_status & 0x0004) {
- int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+ int mii_reg5 = mdio_read(dev, vp->phys[0], 5);
if (! vp->force_fd && mii_reg5 != 0xffff) {
int duplex = (mii_reg5&0x0100) ||
(mii_reg5 & 0x01C0) == 0x0040;
vp->phys[0], mii_reg5);
/* Set the full-duplex bit. */
EL3WINDOW(3); /* AKPM: this was missing from 2.3.99 3c59x.c! */
- outb((vp->full_duplex ? 0x20 : 0) |
- (dev->mtu > 1500 ? 0x40 : 0),
- ioaddr + Wn3_MAC_Ctrl);
+ outw( (vp->full_duplex ? 0x20 : 0) |
+ (dev->mtu > 1500 ? 0x40 : 0) |
+ ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0),
+ ioaddr + Wn3_MAC_Ctrl);
if (vortex_debug > 1)
printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n");
/* AKPM: bug: should reset Tx and Rx after setting Duplex. Page 180 */
}
- next_tick = 60*HZ;
}
}
- spin_unlock_irqrestore(&vp->lock, flags);
}
break;
default: /* Other media types handled by Tx timeouts. */
EL3WINDOW(old_window);
enable_irq(dev->irq);
- if (vortex_debug > 1)
+ if (vortex_debug > 2)
printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
dev->name, media_tbl[dev->if_port].name);
}
if (vp->tx_full)
netif_stop_queue (dev);
- outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
+ if (vp->drv_flags & IS_BOOMERANG)
+ outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
outw(DownUnstall, ioaddr + EL3_CMD);
} else {
vp->stats.tx_dropped++;
if (tx_status & 0x14) vp->stats.tx_fifo_errors++;
if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
outb(0, ioaddr + TxStatus);
- if (tx_status & 0x38) /* AKPM: tx reset after 16 collisions, despite what the manual says */
- do_tx_reset = 1;
+ if (tx_status & 0x3a) /* TxReset after 16 collisions, despite what the manual says */
+ do_tx_reset = 1; /* Also reset on reclaim errors */
else /* Merely re-enable the transmitter. */
outw(TxEnable, ioaddr + EL3_CMD);
}
/* In this case, blow the card away */
vortex_down(dev);
wait_for_completion(dev, TotalReset | 0xff);
- vortex_up(dev);
+ vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */
} else if (fifo_diag & 0x0400)
do_tx_reset = 1;
if (fifo_diag & 0x3000) {
struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
unsigned long flags;
- if (vortex_debug > 6)
+ if (vortex_debug > 6) {
printk(KERN_DEBUG "boomerang_start_xmit()\n");
+ if (vortex_debug > 3)
+ printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
+ dev->name, vp->cur_tx);
+ }
- if (vortex_debug > 3)
- printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
- dev->name, vp->cur_tx);
if (vp->tx_full) {
if (vortex_debug > 0)
printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
long ioaddr;
int status;
int work_done = max_interrupt_work;
-
- spin_lock(&vp->lock);
ioaddr = dev->base_addr;
+ spin_lock(&vp->lock);
+
status = inw(ioaddr + EL3_STATUS);
if (vortex_debug > 6)
printk("vortex_interrupt(). status=0x%4x\n", status);
+ if ((status & IntLatch) == 0)
+ goto handler_exit; /* No interrupt: shared IRQs cause this */
+
if (status & IntReq) {
status |= vp->deferred;
vp->deferred = 0;
if (vortex_debug > 4)
printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
dev->name, status, inb(ioaddr + Timer));
+
do {
if (vortex_debug > 5)
printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
}
/* Acknowledge the IRQ. */
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
- if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
- writel(0x8000, vp->cb_fn_base + 4);
-
} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
if (vortex_debug > 4)
int status;
int work_done = max_interrupt_work;
- spin_lock(&vp->lock);
-
ioaddr = dev->base_addr;
+
+ /*
+ * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout
+ * and boomerang_start_xmit
+ */
+ spin_lock(&vp->lock);
+
status = inw(ioaddr + EL3_STATUS);
if (vortex_debug > 6)
printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status);
+ if ((status & IntLatch) == 0)
+ goto handler_exit; /* No interrupt: shared IRQs can cause this */
+
if (status == 0xffff) { /* AKPM: h/w no longer present (hotplug)? */
if (vortex_debug > 1)
printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n");
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. */
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 net_device *dev = (struct net_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 void
vortex_down(struct net_device *dev)
{
netif_stop_queue (dev);
+ del_timer_sync(&vp->rx_oom_timer);
del_timer_sync(&vp->timer);
/* Turn off statistics ASAP. We update vp->stats below. */
u16 *data = (u16 *)&rq->ifr_data;
int phy = vp->phys[0] & 0x1f;
int retval;
- unsigned long flags;
-
- spin_lock_irqsave(&vp->lock, flags);
switch(cmd) {
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
data[0] = phy;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
EL3WINDOW(4);
- data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
retval = 0;
break;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
retval = -EPERM;
} else {
EL3WINDOW(4);
- mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
retval = 0;
}
break;
break;
}
- spin_unlock_irqrestore(&vp->lock, flags);
return retval;
}
}
}
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(struct net_device *dev, int phy_id, int location)
{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
int i;
+ long ioaddr = dev->base_addr;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
unsigned int retval = 0;
long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ spin_lock_bh(&vp->mdio_lock);
+
if (mii_preamble_required)
mdio_sync(ioaddr, 32);
outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
+ spin_unlock_bh(&vp->mdio_lock);
return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
}
-static void mdio_write(long ioaddr, int phy_id, int location, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ long ioaddr = dev->base_addr;
int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
int i;
+ spin_lock_bh(&vp->mdio_lock);
+
if (mii_preamble_required)
mdio_sync(ioaddr, 32);
outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
-
+ spin_unlock_bh(&vp->mdio_lock);
return;
}
\f
long ioaddr = dev->base_addr;
/* AKPM: This kills the 905 */
- if (vortex_debug > 0) {
+ if (vortex_debug > 1) {
printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n");
}
return;
*/
unregister_netdev(dev);
outw(TotalReset, dev->base_addr + EL3_CMD);
- release_region(dev->base_addr, vp->io_size);
+ if (vp->must_free_region)
+ release_region(dev->base_addr, vp->io_size);
kfree(dev);
}
{
int rc;
- rc = pci_module_init (&vortex_driver);
- if (rc < 0)
- goto out;
-
- if (rc >= 0) /* AKPM: had "> 0" */
+ rc = pci_module_init(&vortex_driver);
+ if (rc < 0) {
+ rc = vortex_eisa_init();
+ if (rc > 0)
+ vortex_have_eisa = 1;
+ } else {
vortex_have_pci = 1;
+ }
- rc = vortex_eisa_init ();
- if (rc < 0)
- goto out;
-
- if (rc > 0)
- vortex_have_eisa = 1;
-
-out:
return rc;
}
\f
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
- dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
+ if [ "$CONFIG_IBMTR" != "y" ]; then
+ dep_tristate ' IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
+ fi
if [ "$CONFIG_CARDBUS" = "y" ]; then
tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP
-/* $Id: sunlance.c,v 1.102 2000/06/30 10:18:35 davem Exp $
+/* $Id: sunlance.c,v 1.103 2000/08/12 19:23:38 anton Exp $
* lance.c: Linux/Sparc/Lance driver
*
* Written 1995, 1996 by Miguel de Icaza
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <asm/machines.h>
-
/* Define: 2^4 Tx buffers and 2^4 Rx buffers */
#ifndef LANCE_LOG_TX_BUFFERS
#define LANCE_LOG_TX_BUFFERS 4
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) lmc
-O_TARGET := wan.a
+O_TARGET := wan.o
export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o
list-multi = wanpipe.o cyclomx.o
obj-$(CONFIG_SEALEVEL_4021) += z85230.o syncppp.o sealevel.o
obj-$(CONFIG_COMX) += comx.o
obj-$(CONFIG_COMX_HW_COMX) += comx-hw-comx.o
-obj-$(CONFIG_COMX_HW_LOCOMX) += cz85230.o syncppp.o comx-hw-locomx.o
+obj-$(CONFIG_COMX_HW_LOCOMX) += z85230.o syncppp.o comx-hw-locomx.o
obj-$(CONFIG_COMX_HW_MIXCOM) += comx-hw-mixcom.o
obj-$(CONFIG_COMX_PROTO_PPP) += syncppp.o comx-proto-ppp.o
obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o
* < 0 error.
* Context: process
*/
-static int __init cyclomx_init (void)
+int __init cyclomx_init (void)
{
int cnt, err = 0;
if(z8530_init(dev)!=0)
{
printk(KERN_ERR "Z8530 series device not found.\n");
+ restore_flags(flags);
goto dmafail2;
}
z8530_channel_load(&dev->chanB, z8530_dead_port);
if(z8530_init(dev)!=0)
{
printk(KERN_ERR "Z8530 series device not found.\n");
+ restore_flags(flags);
goto dmafail2;
}
if(dev->type==Z85C30)
10b7 3590 TokenLink Velocity XL Adapter
4500 3c450 Cyclone/unknown
5055 3c555 Laptop Hurricane
+ 6055 3c556 Laptop Hurricane
5057 3c575 [Megahertz] 10/100 LAN CardBus
10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card
5157 3c575 [Megahertz] 10/100 LAN CardBus
6100 VT85C100A [Rhine II]
8231 VT8231 [PCI-to-ISA Bridge]
8235 VT8235 Power Management
- 8305 VT8365 [KM133 AGP]
- 8391 VT8363/8371 [KT133/KX133 AGP]
+ 8305 VT8363/8365 [KT133/KM133 AGP]
+ 8391 VT8371 [KX133 AGP]
8501 VT8501 [Apollo MVP4 AGP]
8596 VT82C596 [Apollo PRO AGP]
8597 VT82C597 [Apollo VP3 AGP]
bool ' Persistent DMA buffers' CONFIG_SOUND_DMAP
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND
+ dep_tristate ' AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND_OSS
fi
dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
dep_tristate ' Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
#ifndef _8010_H
#define _8010_H
-/* ------------------- DEFINES -------------------- */
+#include <linux/types.h>
-#define EMUPAGESIZE 4096 /* don't change */
-#define RESERVED 0
-#define NUM_G 64 /* use all channels */
-#define NUM_FXSENDS 4 /* don't change */
-#define MAXPAGES (32768 * NUM_G / EMUPAGESIZE) /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */
+/* ------------------- DEFINES -------------------- */
-#define TMEMSIZE 256*1024
-#define TMEMSIZEREG 4
+#define CMD_WRITEFN0 0x0
+#define CMD_READFN0 0x1
+#define CMD_WRITEPTR 0x2
+#define CMD_READPTR 0x3
+#define CMD_SETRECSRC 0x4
+#define CMD_GETRECSRC 0x5
+#define CMD_GETVOICEPARAM 0x6
+#define CMD_SETVOICEPARAM 0x7
-#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL))
+struct mixer_private_ioctl {
+ u32 cmd;
+ u32 val[10];
+};
/************************************************************************************************/
/* PCI function 0 registers, address = <val> + PCIBASE0 */
#define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */
#define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */
#define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */
+#define HCFG_AC3ENABLE_GPSPDIF 0x00000020 /* Channels 0 and 1 replace GPSPDIF */
#define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */
/* will automatically mute their output when */
/* they are not rate-locked to the external */
/* async audio source */
#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */
/* NOTE: This should generally never be used. */
-#define HCFG_LOCKTANKCACHE 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */
+#define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */
/* NOTE: This should generally never be used. */
+#define HCFG_LOCKTANKCACHE 0x01020014
#define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */
/* NOTE: This is a 'cheap' way to implement a */
/* master mute function on the mute button, and */
#define AC97_RECORDSELECT 0x1a
#define AC97_RECORDGAIN 0x1c
#define AC97_RECORDGAINMIC 0x1e
-#define AC97_GENERALPUPOSE 0x20
+#define AC97_GENERALPURPOSE 0x20
#define AC97_3DCONTROL 0x22
#define AC97_MODEMRATE 0x24
#define AC97_POWERDOWN 0x26
#define CCCA_CURRADDR 0x18000008
#define CCR 0x09 /* Cache control register */
-#define CCR_CACHEINVALIDSIZE 0xfe000000 /* Number of invalid samples cache for this channel */
+#define CCR_CACHEINVALIDSIZE 0x07190009
+#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
#define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */
#define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */
#define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */
+#define CCR_READADDRESS 0x06100009
#define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */
#define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */
/* NOTE: This is valid only if CACHELOOPFLAG is set */
ifeq ($(CONFIG_SOUND_EMU10K1),y)
O_TARGET := emu10k1.o
- O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \
+ O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
- osutils.o recmgr.o timer.o voicemgr.o
+ recmgr.o timer.o voicemgr.o
else
ifeq ($(CONFIG_SOUND_EMU10K1),m)
M_OBJS := emu10k1.o
O_TARGET := emu10k1.o
- O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \
+ O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
- osutils.o recmgr.o timer.o voicemgr.o
+ recmgr.o timer.o voicemgr.o
endif
endif
-EXTRA_CFLAGS += -I.
-
ifdef DEBUG
EXTRA_CFLAGS += -DEMU10K1_DEBUG
endif
-
/*
**********************************************************************
* audio.c -- /dev/dsp interface for emu10k1 driver
**********************************************************************
*/
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/wrapper.h>
+
+
#include "hwaccess.h"
#include "cardwo.h"
#include "cardwi.h"
#include "recmgr.h"
+#include "irqmgr.h"
#include "audio.h"
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/wrapper.h>
static void calculate_ofrag(struct woinst *);
static void calculate_ifrag(struct wiinst *);
/* Audio file operations */
-static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin)
+static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int origin)
{
return -ESPIPE;
}
{
struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
struct wiinst *wiinst = wave_dev->wiinst;
- struct wave_in *wave_in;
ssize_t ret = 0;
unsigned long flags;
- DPD(4, "emu10k1_audio_read(), buffer=%p, count=%x\n", buffer, (u32) count);
+ DPD(3, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count);
if (ppos != &file->f_pos)
return -ESPIPE;
spin_lock_irqsave(&wiinst->lock, flags);
- if (wiinst->mapped) {
+ if (wiinst->mmapped) {
spin_unlock_irqrestore(&wiinst->lock, flags);
return -ENXIO;
}
- if (!wiinst->wave_in) {
+ if (wiinst->state == WAVE_STATE_CLOSED) {
calculate_ifrag(wiinst);
- while (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) {
+ while (emu10k1_wavein_open(wave_dev) < 0) {
spin_unlock_irqrestore(&wiinst->lock, flags);
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- UP_INODE_SEM(&inode->i_sem);
interruptible_sleep_on(&wave_dev->card->open_wait);
- DOWN_INODE_SEM(&inode->i_sem);
if (signal_pending(current))
return -ERESTARTSYS;
}
}
- wave_in = wiinst->wave_in;
-
spin_unlock_irqrestore(&wiinst->lock, flags);
while (count > 0) {
- u32 bytestocopy, dummy;
+ u32 bytestocopy;
spin_lock_irqsave(&wiinst->lock, flags);
- if ((wave_in->state != CARDWAVE_STATE_STARTED)
+ if (!(wiinst->state & WAVE_STATE_STARTED)
&& (wave_dev->enablebits & PCM_ENABLE_INPUT))
emu10k1_wavein_start(wave_dev);
- emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
+ emu10k1_wavein_update(wave_dev->card, wiinst);
+ emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(4, "bytestocopy --> %x\n", bytestocopy);
+ DPD(3, "bytestocopy --> %d\n", bytestocopy);
- if ((bytestocopy >= wiinst->fragment_size)
+ if ((bytestocopy >= wiinst->buffer.fragment_size)
|| (bytestocopy >= count)) {
bytestocopy = min(bytestocopy, count);
|| (!(wave_dev->enablebits & PCM_ENABLE_INPUT)))
return (ret ? ret : -EAGAIN);
- UP_INODE_SEM(&inode->i_sem);
interruptible_sleep_on(&wiinst->wait_queue);
- DOWN_INODE_SEM(&inode->i_sem);
if (signal_pending(current))
return (ret ? ret : -ERESTARTSYS);
}
}
- DPD(4, "bytes copied -> %x\n", (u32) ret);
+ DPD(3, "bytes copied -> %d\n", (u32) ret);
return ret;
}
{
struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
struct woinst *woinst = wave_dev->woinst;
- struct wave_out *wave_out;
ssize_t ret;
unsigned long flags;
- GET_INODE_STRUCT();
-
- DPD(4, "emu10k1_audio_write(), buffer=%p, count=%x\n", buffer, (u32) count);
+ DPD(3, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count);
if (ppos != &file->f_pos)
return -ESPIPE;
spin_lock_irqsave(&woinst->lock, flags);
- if (woinst->mapped) {
+ if (woinst->mmapped) {
spin_unlock_irqrestore(&woinst->lock, flags);
return -ENXIO;
}
- if (!woinst->wave_out) {
+ if (woinst->state == WAVE_STATE_CLOSED) {
calculate_ofrag(woinst);
- while (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) {
+ while (emu10k1_waveout_open(wave_dev) < 0) {
spin_unlock_irqrestore(&woinst->lock, flags);
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- UP_INODE_SEM(&inode->i_sem);
interruptible_sleep_on(&wave_dev->card->open_wait);
- DOWN_INODE_SEM(&inode->i_sem);
if (signal_pending(current))
return -ERESTARTSYS;
}
}
- wave_out = woinst->wave_out;
-
spin_unlock_irqrestore(&woinst->lock, flags);
ret = 0;
while (count > 0) {
- u32 bytestocopy, pending, dummy;
+ u32 bytestocopy;
spin_lock_irqsave(&woinst->lock, flags);
-
- emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
-
+ emu10k1_waveout_update(woinst);
+ emu10k1_waveout_getxfersize(woinst, &bytestocopy);
spin_unlock_irqrestore(&woinst->lock, flags);
- DPD(4, "bytestocopy --> %x\n", bytestocopy);
+ DPD(3, "bytestocopy --> %d\n", bytestocopy);
- if ((bytestocopy >= woinst->fragment_size)
+ if ((bytestocopy >= woinst->buffer.fragment_size)
|| (bytestocopy >= count)) {
bytestocopy = min(bytestocopy, count);
spin_lock_irqsave(&woinst->lock, flags);
woinst->total_copied += bytestocopy;
- if ((wave_out->state != CARDWAVE_STATE_STARTED)
+ if (!(woinst->state & WAVE_STATE_STARTED)
&& (wave_dev->enablebits & PCM_ENABLE_OUTPUT)
- && (woinst->total_copied >= woinst->fragment_size)) {
+ && (woinst->total_copied >= woinst->buffer.fragment_size))
+ emu10k1_waveout_start(wave_dev);
- if (emu10k1_waveout_start(wave_dev) != CTSTATUS_SUCCESS) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- ERROR();
- return -EFAULT;
- }
- }
spin_unlock_irqrestore(&woinst->lock, flags);
}
|| (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT)))
return (ret ? ret : -EAGAIN);
- UP_INODE_SEM(&inode->i_sem);
interruptible_sleep_on(&woinst->wait_queue);
- DOWN_INODE_SEM(&inode->i_sem);
if (signal_pending(current))
return (ret ? ret : -ERESTARTSYS);
}
}
- DPD(4, "bytes copied -> %x\n", (u32) ret);
+ DPD(3, "bytes copied -> %d\n", (u32) ret);
return ret;
}
static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- int val = 0;
struct woinst *woinst = NULL;
- struct wave_out *wave_out = NULL;
struct wiinst *wiinst = NULL;
- struct wave_in *wave_in = NULL;
- u32 pending, bytestocopy, dummy;
+ int val = 0;
+ u32 bytestocopy;
unsigned long flags;
DPF(4, "emu10k1_audio_ioctl()\n");
- if (file->f_mode & FMODE_WRITE) {
+ if (file->f_mode & FMODE_WRITE)
woinst = wave_dev->woinst;
- spin_lock_irqsave(&woinst->lock, flags);
- wave_out = woinst->wave_out;
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
+ if (file->f_mode & FMODE_READ)
wiinst = wave_dev->wiinst;
- spin_lock_irqsave(&wiinst->lock, flags);
- wave_in = wiinst->wave_in;
- spin_unlock_irqrestore(&wiinst->lock, flags);
- }
switch (cmd) {
case OSS_GETVERSION:
if (file->f_mode & FMODE_WRITE) {
spin_lock_irqsave(&woinst->lock, flags);
- if (wave_out)
+ if (woinst->state & WAVE_STATE_OPEN) {
+ if (woinst->mmapped) {
+ int i;
+
+ /* Undo marking the pages as reserved */
+ for (i = 0; i < woinst->buffer.pages; i++)
+ mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));
+ }
+
emu10k1_waveout_close(wave_dev);
+ }
+ woinst->mmapped = 0;
woinst->total_copied = 0;
woinst->total_played = 0;
woinst->blocks = 0;
- woinst->curpos = 0;
spin_unlock_irqrestore(&woinst->lock, flags);
}
if (file->f_mode & FMODE_READ) {
spin_lock_irqsave(&wiinst->lock, flags);
- if (wave_in)
+ if (wiinst->state & WAVE_STATE_OPEN)
emu10k1_wavein_close(wave_dev);
+ wiinst->mmapped = 0;
wiinst->total_recorded = 0;
wiinst->blocks = 0;
- wiinst->curpos = 0;
spin_unlock_irqrestore(&wiinst->lock, flags);
}
if (file->f_mode & FMODE_WRITE) {
- if (wave_out) {
- spin_lock_irqsave(&woinst->lock, flags);
+ spin_lock_irqsave(&woinst->lock, flags);
+
+ if (woinst->state & WAVE_STATE_OPEN) {
- if (wave_out->state == CARDWAVE_STATE_STARTED)
+ if (woinst->state & WAVE_STATE_STARTED)
while ((woinst->total_played < woinst->total_copied)
&& !signal_pending(current)) {
spin_unlock_irqrestore(&woinst->lock, flags);
spin_lock_irqsave(&woinst->lock, flags);
}
- emu10k1_waveout_close(wave_dev);
- woinst->total_copied = 0;
- woinst->total_played = 0;
- woinst->blocks = 0;
- woinst->curpos = 0;
+ if (woinst->mmapped) {
+ int i;
- spin_unlock_irqrestore(&woinst->lock, flags);
+ /* Undo marking the pages as reserved */
+ for (i = 0; i < woinst->buffer.pages; i++)
+ mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));
+ }
+
+ emu10k1_waveout_close(wave_dev);
}
+
+ woinst->mmapped = 0;
+ woinst->total_copied = 0;
+ woinst->total_played = 0;
+ woinst->blocks = 0;
+
+ spin_unlock_irqrestore(&woinst->lock, flags);
}
if (file->f_mode & FMODE_READ) {
spin_lock_irqsave(&wiinst->lock, flags);
- if (wave_in)
+ if (wiinst->state & WAVE_STATE_OPEN)
emu10k1_wavein_close(wave_dev);
+ wiinst->mmapped = 0;
wiinst->total_recorded = 0;
wiinst->blocks = 0;
- wiinst->curpos = 0;
spin_unlock_irqrestore(&wiinst->lock, flags);
}
get_user_ret(val, (int *) arg, -EFAULT);
DPD(2, "val is %d\n", val);
- if (val >= 0) {
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
+ if (val > 0) {
+ if (file->f_mode & FMODE_READ) {
+ struct wave_format format;
- woinst->wave_fmt.samplingrate = val;
+ spin_lock_irqsave(&wiinst->lock, flags);
+
+ format = wiinst->format;
+ format.samplingrate = val;
- if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ if (emu10k1_wavein_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = woinst->wave_fmt.samplingrate;
+ val = wiinst->format.samplingrate;
- spin_unlock_irqrestore(&woinst->lock, flags);
+ spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(2, "set playback sampling rate -> %d\n", val);
+ DPD(2, "set recording sampling rate -> %d\n", val);
}
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ struct wave_format format;
+
+ spin_lock_irqsave(&woinst->lock, flags);
- wiinst->wave_fmt.samplingrate = val;
+ format = woinst->format;
+ format.samplingrate = val;
- if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ if (emu10k1_waveout_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = wiinst->wave_fmt.samplingrate;
+ val = woinst->format.samplingrate;
- spin_unlock_irqrestore(&wiinst->lock, flags);
+ spin_unlock_irqrestore(&woinst->lock, flags);
- DPD(2, "set recording sampling rate -> %d\n", val);
+ DPD(2, "set playback sampling rate -> %d\n", val);
}
return put_user(val, (int *) arg);
} else {
if (file->f_mode & FMODE_READ)
- val = wiinst->wave_fmt.samplingrate;
+ val = wiinst->format.samplingrate;
else if (file->f_mode & FMODE_WRITE)
- val = woinst->wave_fmt.samplingrate;
+ val = woinst->format.samplingrate;
return put_user(val, (int *) arg);
}
get_user_ret(val, (int *) arg, -EFAULT);
DPD(2, " val is %d\n", val);
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
+ if (file->f_mode & FMODE_READ) {
+ struct wave_format format;
- woinst->wave_fmt.channels = val ? 2 : 1;
+ spin_lock_irqsave(&wiinst->lock, flags);
- if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ format = wiinst->format;
+ format.channels = val ? 2 : 1;
+
+ if (emu10k1_wavein_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = woinst->wave_fmt.channels - 1;
+ val = wiinst->format.channels - 1;
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- DPD(2, "set playback stereo -> %d\n", val);
+ spin_unlock_irqrestore(&wiinst->lock, flags);
+ DPD(2, "set recording stereo -> %d\n", val);
}
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ struct wave_format format;
+
+ spin_lock_irqsave(&woinst->lock, flags);
- wiinst->wave_fmt.channels = val ? 2 : 1;
+ format = woinst->format;
+ format.channels = val ? 2 : 1;
- if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ if (emu10k1_waveout_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = wiinst->wave_fmt.channels - 1;
+ val = woinst->format.channels - 1;
- spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(2, "set recording stereo -> %d\n", val);
+ spin_unlock_irqrestore(&woinst->lock, flags);
+
+ DPD(2, "set playback stereo -> %d\n", val);
}
return put_user(val, (int *) arg);
get_user_ret(val, (int *) arg, -EFAULT);
DPD(2, " val is %d\n", val);
- if (val != 0) {
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
+ if (val > 0) {
+ if (file->f_mode & FMODE_READ) {
+ struct wave_format format;
+
+ spin_lock_irqsave(&wiinst->lock, flags);
- woinst->wave_fmt.channels = val;
+ format = wiinst->format;
+ format.channels = val;
- if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ if (emu10k1_wavein_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = woinst->wave_fmt.channels;
+ val = wiinst->format.channels;
- spin_unlock_irqrestore(&woinst->lock, flags);
- DPD(2, "set playback number of channels -> %d\n", val);
+ spin_unlock_irqrestore(&wiinst->lock, flags);
+ DPD(2, "set recording number of channels -> %d\n", val);
}
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ struct wave_format format;
+
+ spin_lock_irqsave(&woinst->lock, flags);
- wiinst->wave_fmt.channels = val;
+ format = woinst->format;
+ format.channels = val;
- if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ if (emu10k1_waveout_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = wiinst->wave_fmt.channels;
+ val = woinst->format.channels;
- spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(2, "set recording number of channels -> %d\n", val);
+ spin_unlock_irqrestore(&woinst->lock, flags);
+ DPD(2, "set playback number of channels -> %d\n", val);
}
return put_user(val, (int *) arg);
} else {
if (file->f_mode & FMODE_READ)
- val = wiinst->wave_fmt.channels;
+ val = wiinst->format.channels;
else if (file->f_mode & FMODE_WRITE)
- val = woinst->wave_fmt.channels;
+ val = woinst->format.channels;
return put_user(val, (int *) arg);
}
DPD(2, " val is %d\n", val);
if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
+ if (file->f_mode & FMODE_READ) {
+ struct wave_format format;
+
+ spin_lock_irqsave(&wiinst->lock, flags);
- woinst->wave_fmt.bitsperchannel = val;
+ format = wiinst->format;
+ format.bitsperchannel = val;
- if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ if (emu10k1_wavein_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = woinst->wave_fmt.bitsperchannel;
+ val = wiinst->format.bitsperchannel;
- spin_unlock_irqrestore(&woinst->lock, flags);
- DPD(2, "set playback sample size -> %d\n", val);
+ spin_unlock_irqrestore(&wiinst->lock, flags);
+ DPD(2, "set recording sample size -> %d\n", val);
}
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
+ if (file->f_mode & FMODE_WRITE) {
+ struct wave_format format;
- wiinst->wave_fmt.bitsperchannel = val;
+ spin_lock_irqsave(&woinst->lock, flags);
- if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+ format = woinst->format;
+ format.bitsperchannel = val;
+
+ if (emu10k1_waveout_setformat(wave_dev, &format) < 0)
return -EINVAL;
- val = wiinst->wave_fmt.bitsperchannel;
+ val = woinst->format.bitsperchannel;
- spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(2, "set recording sample size -> %d\n", val);
+ spin_unlock_irqrestore(&woinst->lock, flags);
+ DPD(2, "set playback sample size -> %d\n", val);
}
return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
} else {
if (file->f_mode & FMODE_READ)
- val = wiinst->wave_fmt.bitsperchannel;
+ val = wiinst->format.bitsperchannel;
else if (file->f_mode & FMODE_WRITE)
- val = woinst->wave_fmt.bitsperchannel;
+ val = woinst->format.bitsperchannel;
return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
}
case SOUND_PCM_READ_BITS:
if (file->f_mode & FMODE_READ)
- val = wiinst->wave_fmt.bitsperchannel;
+ val = wiinst->format.bitsperchannel;
else if (file->f_mode & FMODE_WRITE)
- val = woinst->wave_fmt.bitsperchannel;
+ val = woinst->format.bitsperchannel;
return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
case SOUND_PCM_READ_RATE:
if (file->f_mode & FMODE_READ)
- val = wiinst->wave_fmt.samplingrate;
+ val = wiinst->format.samplingrate;
else if (file->f_mode & FMODE_WRITE)
- val = woinst->wave_fmt.samplingrate;
+ val = woinst->format.samplingrate;
return put_user(val, (int *) arg);
case SOUND_PCM_READ_CHANNELS:
if (file->f_mode & FMODE_READ)
- val = wiinst->wave_fmt.channels;
+ val = wiinst->format.channels;
else if (file->f_mode & FMODE_WRITE)
- val = woinst->wave_fmt.channels;
+ val = woinst->format.channels;
return put_user(val, (int *) arg);
if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT))
val |= PCM_ENABLE_OUTPUT;
+
if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT))
val |= PCM_ENABLE_INPUT;
if (val & PCM_ENABLE_OUTPUT) {
wave_dev->enablebits |= PCM_ENABLE_OUTPUT;
- if (wave_out)
+ if (woinst->state & WAVE_STATE_OPEN)
emu10k1_waveout_start(wave_dev);
} else {
wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT;
- if (wave_out)
+ if (woinst->state & WAVE_STATE_STARTED)
emu10k1_waveout_stop(wave_dev);
}
if (val & PCM_ENABLE_INPUT) {
wave_dev->enablebits |= PCM_ENABLE_INPUT;
- if (wave_in)
+ if (wiinst->state & WAVE_STATE_OPEN)
emu10k1_wavein_start(wave_dev);
} else {
wave_dev->enablebits &= ~PCM_ENABLE_INPUT;
- if (wave_in)
+ if (wiinst->state & WAVE_STATE_STARTED)
emu10k1_wavein_stop(wave_dev);
}
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (wave_out) {
- spin_lock_irqsave(&woinst->lock, flags);
- emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
- spin_unlock_irqrestore(&woinst->lock, flags);
+ spin_lock_irqsave(&woinst->lock, flags);
+ if (woinst->state & WAVE_STATE_OPEN) {
+ emu10k1_waveout_update(woinst);
+ emu10k1_waveout_getxfersize(woinst, &bytestocopy);
info.bytes = bytestocopy;
} else {
- spin_lock_irqsave(&woinst->lock, flags);
calculate_ofrag(woinst);
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- info.bytes = woinst->numfrags * woinst->fragment_size;
+ info.bytes = woinst->buffer.size;
}
+ spin_unlock_irqrestore(&woinst->lock, flags);
- info.fragstotal = woinst->numfrags;
- info.fragments = info.bytes / woinst->fragment_size;
- info.fragsize = woinst->fragment_size;
+ info.fragstotal = woinst->buffer.numfrags;
+ info.fragments = info.bytes / woinst->buffer.fragment_size;
+ info.fragsize = woinst->buffer.fragment_size;
if (copy_to_user((int *) arg, &info, sizeof(info)))
return -EFAULT;
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (wave_in) {
- spin_lock_irqsave(&wiinst->lock, flags);
- emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
+ spin_lock_irqsave(&wiinst->lock, flags);
+ if (wiinst->state & WAVE_STATE_OPEN) {
+ emu10k1_wavein_update(wave_dev->card, wiinst);
+ emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
info.bytes = bytestocopy;
} else {
- spin_lock_irqsave(&wiinst->lock, flags);
calculate_ifrag(wiinst);
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
info.bytes = 0;
}
+ spin_unlock_irqrestore(&wiinst->lock, flags);
- info.fragstotal = wiinst->numfrags;
- info.fragments = info.bytes / wiinst->fragment_size;
- info.fragsize = wiinst->fragment_size;
+ info.fragstotal = wiinst->buffer.numfrags;
+ info.fragments = info.bytes / wiinst->buffer.fragment_size;
+ info.fragsize = wiinst->buffer.fragment_size;
if (copy_to_user((int *) arg, &info, sizeof(info)))
return -EFAULT;
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (wave_out) {
- spin_lock_irqsave(&woinst->lock, flags);
- emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- val = pending;
+ spin_lock_irqsave(&woinst->lock, flags);
+ if (woinst->state & WAVE_STATE_OPEN) {
+ emu10k1_waveout_update(woinst);
+ emu10k1_waveout_getxfersize(woinst, &bytestocopy);
+ val = woinst->buffer.size - bytestocopy;
} else
val = 0;
+ spin_unlock_irqrestore(&woinst->lock, flags);
+
return put_user(val, (int *) arg);
case SNDCTL_DSP_GETIPTR:
spin_lock_irqsave(&wiinst->lock, flags);
- if (wave_in) {
- emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, (u32 *) & cinfo.ptr);
- cinfo.bytes =
- cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags);
- cinfo.blocks = cinfo.bytes / wiinst->fragment_size - wiinst->blocks;
- wiinst->blocks = cinfo.bytes / wiinst->fragment_size;
+ if (wiinst->state & WAVE_STATE_OPEN) {
+ emu10k1_wavein_update(wave_dev->card, wiinst);
+ cinfo.ptr = wiinst->buffer.hw_pos;
+ cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % wiinst->buffer.size;
+ cinfo.blocks = cinfo.bytes / wiinst->buffer.fragment_size - wiinst->blocks;
+ wiinst->blocks = cinfo.bytes / wiinst->buffer.fragment_size;
} else {
cinfo.ptr = 0;
cinfo.bytes = 0;
cinfo.blocks = 0;
- wiinst->blocks = 0;
}
spin_unlock_irqrestore(&wiinst->lock, flags);
spin_lock_irqsave(&woinst->lock, flags);
- if (wave_out) {
- emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, (u32 *) & cinfo.ptr);
- cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags);
- cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->blocks;
- woinst->blocks = cinfo.bytes / woinst->fragment_size;
+ if (woinst->state & WAVE_STATE_OPEN) {
+ emu10k1_waveout_update(woinst);
+ cinfo.ptr = woinst->buffer.hw_pos;
+ cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % woinst->buffer.size;
+ cinfo.blocks = cinfo.bytes / woinst->buffer.fragment_size - woinst->blocks;
+ woinst->blocks = cinfo.bytes / woinst->buffer.fragment_size;
} else {
cinfo.ptr = 0;
cinfo.bytes = 0;
cinfo.blocks = 0;
- woinst->blocks = 0;
}
+ if(woinst->mmapped)
+ woinst->buffer.bytestocopy %= woinst->buffer.fragment_size;
spin_unlock_irqrestore(&woinst->lock, flags);
spin_lock_irqsave(&woinst->lock, flags);
calculate_ofrag(woinst);
- val = woinst->fragment_size;
+ val = woinst->buffer.fragment_size;
spin_unlock_irqrestore(&woinst->lock, flags);
}
spin_lock_irqsave(&wiinst->lock, flags);
calculate_ifrag(wiinst);
- val = wiinst->fragment_size;
+ val = wiinst->buffer.fragment_size;
spin_unlock_irqrestore(&wiinst->lock, flags);
}
break;
case SNDCTL_DSP_POST:
- DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+ if (file->f_mode & FMODE_WRITE) {
+ spin_lock_irqsave(&woinst->lock, flags);
+
+ if (!(woinst->state & WAVE_STATE_STARTED)
+ && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)
+ && (woinst->total_copied > 0))
+ emu10k1_waveout_start(wave_dev);
+
+ spin_unlock_irqrestore(&woinst->lock, flags);
+ }
+
break;
case SNDCTL_DSP_SUBDIVIDE:
get_user_ret(val, (int *) arg, -EFAULT);
- DPD(2, "val is %x\n", val);
+ DPD(2, "val is 0x%x\n", val);
if (val == 0)
return -EIO;
if (file->f_mode & FMODE_WRITE) {
- if (wave_out)
+ if (woinst->state & WAVE_STATE_OPEN)
return -EINVAL; /* too late to change */
- woinst->ossfragshift = val & 0xffff;
- woinst->numfrags = (val >> 16) & 0xffff;
+ woinst->buffer.ossfragshift = val & 0xffff;
+ woinst->buffer.numfrags = (val >> 16) & 0xffff;
}
if (file->f_mode & FMODE_READ) {
- if (wave_in)
+ if (wiinst->state & WAVE_STATE_OPEN)
return -EINVAL; /* too late to change */
- wiinst->ossfragshift = val & 0xffff;
- wiinst->numfrags = (val >> 16) & 0xffff;
+ wiinst->buffer.ossfragshift = val & 0xffff;
+ wiinst->buffer.numfrags = (val >> 16) & 0xffff;
}
break;
if ((buf.command != 1) && (buf.command != 2))
return -EINVAL;
- if (((buf.offs < 0x100) && (buf.command == 2))
+ if ((buf.offs < 0x100)
|| (buf.offs < 0x000)
|| (buf.offs + buf.len > 0x800) || (buf.len > 1000))
return -EINVAL;
if (buf.command == 1) {
for (i = 0; i < buf.len; i++)
-
((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0);
+
if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf)))
return -EFAULT;
} else {
}
default: /* Default is unrecognized command */
- DPD(2, "default: %x\n", cmd);
+ DPD(2, "default: 0x%x\n", cmd);
return -EINVAL;
}
return 0;
return -ENXIO;
lock_kernel();
+
if (vma->vm_flags & VM_WRITE) {
struct woinst *woinst = wave_dev->woinst;
- struct wave_out *wave_out;
u32 size;
unsigned long flags;
int i;
spin_lock_irqsave(&woinst->lock, flags);
- wave_out = woinst->wave_out;
-
- if (!wave_out) {
+ if (woinst->state == WAVE_STATE_CLOSED) {
calculate_ofrag(woinst);
- if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) {
+ if (emu10k1_waveout_open(wave_dev) < 0) {
spin_unlock_irqrestore(&woinst->lock, flags);
ERROR();
unlock_kernel();
return -EINVAL;
}
- wave_out = woinst->wave_out;
-
/* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */
- for (i = 0; i < wave_out->wavexferbuf->numpages; i++)
- mem_map_reserve(virt_to_page(wave_out->pagetable[i]));
+ for (i = 0; i < woinst->buffer.pages; i++)
+ mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));
}
size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) {
+ if (size > (PAGE_SIZE * woinst->buffer.pages)) {
spin_unlock_irqrestore(&woinst->lock, flags);
unlock_kernel();
return -EINVAL;
}
- for (i = 0; i < wave_out->wavexferbuf->numpages; i++) {
- if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) {
+ for (i = 0; i < woinst->buffer.pages; i++) {
+ if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(woinst->buffer.addr[i]), PAGE_SIZE, vma->vm_page_prot)) {
spin_unlock_irqrestore(&woinst->lock, flags);
- unlock_kernel();
return -EAGAIN;
}
}
- woinst->mapped = 1;
+ woinst->mmapped = 1;
spin_unlock_irqrestore(&woinst->lock, flags);
}
unsigned long flags;
spin_lock_irqsave(&wiinst->lock, flags);
- wiinst->mapped = 1;
+ wiinst->mmapped = 1;
spin_unlock_irqrestore(&wiinst->lock, flags);
}
+
unlock_kernel();
return 0;
list_for_each(entry, &emu10k1_devs) {
card = list_entry(entry, struct emu10k1_card, list);
- if (card->audio1_num == minor || card->audio2_num == minor)
+ if (!((card->audio_num ^ minor) & ~0xf) || !((card->audio1_num ^ minor) & ~0xf))
break;
}
wave_dev->woinst = NULL;
wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* Default */
+ if (file->f_mode & FMODE_READ) {
+ /* Recording */
+ struct wiinst *wiinst;
+
+ if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
+ ERROR();
+ return -ENODEV;
+ }
+
+ wiinst->recsrc = card->wavein.recsrc;
+ wiinst->fxwc = card->wavein.fxwc;
+
+ switch (wiinst->recsrc) {
+ case WAVERECORD_AC97:
+ wiinst->format.samplingrate = 8000;
+ wiinst->format.bitsperchannel = 16;
+ wiinst->format.channels = 1;
+ break;
+ case WAVERECORD_MIC:
+ wiinst->format.samplingrate = 8000;
+ wiinst->format.bitsperchannel = 16;
+ wiinst->format.channels = 1;
+ break;
+ case WAVERECORD_FX:
+ wiinst->format.samplingrate = 48000;
+ wiinst->format.bitsperchannel = 16;
+ wiinst->format.channels = hweight32(wiinst->fxwc);
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ wiinst->state = WAVE_STATE_CLOSED;
+
+ wiinst->buffer.ossfragshift = 0;
+ wiinst->buffer.fragment_size = 0;
+ wiinst->buffer.numfrags = 0;
+
+ init_waitqueue_head(&wiinst->wait_queue);
+
+ wiinst->mmapped = 0;
+ wiinst->total_recorded = 0;
+ wiinst->blocks = 0;
+ wiinst->lock = SPIN_LOCK_UNLOCKED;
+ tasklet_init(&wiinst->timer.tasklet, emu10k1_wavein_bh, (unsigned long) wave_dev);
+ wave_dev->wiinst = wiinst;
+ emu10k1_wavein_setformat(wave_dev, &wiinst->format);
+ }
+
if (file->f_mode & FMODE_WRITE) {
struct woinst *woinst;
return -ENODEV;
}
- woinst->wave_fmt.samplingrate = 8000;
- woinst->wave_fmt.bitsperchannel = 8;
- woinst->wave_fmt.channels = 1;
- woinst->ossfragshift = 0;
- woinst->fragment_size = 0;
- woinst->numfrags = 0;
- woinst->device = (card->audio2_num == minor);
- woinst->wave_out = NULL;
+ if (wave_dev->wiinst != NULL) {
+ woinst->format = wave_dev->wiinst->format;
+ } else {
+ woinst->format.samplingrate = 8000;
+ woinst->format.bitsperchannel = 8;
+ woinst->format.channels = 1;
+ }
+
+ woinst->state = WAVE_STATE_CLOSED;
+
+ woinst->buffer.fragment_size = 0;
+ woinst->buffer.ossfragshift = 0;
+ woinst->buffer.numfrags = 0;
+ woinst->device = (card->audio1_num == minor);
init_waitqueue_head(&woinst->wait_queue);
- woinst->mapped = 0;
+ woinst->mmapped = 0;
woinst->total_copied = 0;
woinst->total_played = 0;
woinst->blocks = 0;
- woinst->curpos = 0;
woinst->lock = SPIN_LOCK_UNLOCKED;
+ tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev);
wave_dev->woinst = woinst;
+ emu10k1_waveout_setformat(wave_dev, &woinst->format);
#ifdef PRIVATE_PCM_VOLUME
{
if (i == MAX_PCM_CHANNELS) {
// add new entry
if (j < 0)
- printk("TOO MANY WRITTERS!!!\n");
+ printk(KERN_WARNING "emu10k1: too many writters!\n");
i = (j >= 0) ? j : 0;
DPD(2, "new pcm private %p\n", current->files);
sblive_pcm_volume[i].files = current->files;
- sblive_pcm_volume[i].mixer = 0x6464; // max
+ sblive_pcm_volume[i].mixer = pcm_last_mixer;
sblive_pcm_volume[i].attn_l = 0;
sblive_pcm_volume[i].attn_r = 0;
sblive_pcm_volume[i].channel_l = NUM_G;
sblive_pcm_volume[i].channel_r = NUM_G;
- }
+ } else
+ DPD(2, "old pcm private %p 0x%x\n", current->files,
+ sblive_pcm_volume[i].mixer);
+
sblive_pcm_volume[i].opened++;
}
#endif
}
- if (file->f_mode & FMODE_READ) {
- /* Recording */
- struct wiinst *wiinst;
-
- if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
- ERROR();
- return -ENODEV;
- }
-
- switch (card->wavein->recsrc) {
- case WAVERECORD_AC97:
- wiinst->wave_fmt.samplingrate = 8000;
- wiinst->wave_fmt.bitsperchannel = 8;
- wiinst->wave_fmt.channels = 1;
- break;
- case WAVERECORD_MIC:
- wiinst->wave_fmt.samplingrate = 8000;
- wiinst->wave_fmt.bitsperchannel = 8;
- wiinst->wave_fmt.channels = 1;
- break;
- case WAVERECORD_FX:
- wiinst->wave_fmt.samplingrate = 48000;
- wiinst->wave_fmt.bitsperchannel = 16;
- wiinst->wave_fmt.channels = 2;
- break;
- default:
- break;
- }
-
- wiinst->recsrc = card->wavein->recsrc;
- wiinst->ossfragshift = 0;
- wiinst->fragment_size = 0;
- wiinst->numfrags = 0;
- wiinst->wave_in = NULL;
-
- init_waitqueue_head(&wiinst->wait_queue);
-
- wiinst->mapped = 0;
- wiinst->total_recorded = 0;
- wiinst->blocks = 0;
- wiinst->curpos = 0;
- wiinst->lock = SPIN_LOCK_UNLOCKED;
- wave_dev->wiinst = wiinst;
- }
-
file->private_data = (void *) wave_dev;
- return 0; /* Success? */
+ return 0;
}
static int emu10k1_audio_release(struct inode *inode, struct file *file)
lock_kernel();
card = wave_dev->card;
+
DPF(2, "emu10k1_audio_release()\n");
if (file->f_mode & FMODE_WRITE) {
struct woinst *woinst = wave_dev->woinst;
- struct wave_out *wave_out;
spin_lock_irqsave(&woinst->lock, flags);
- wave_out = woinst->wave_out;
-
- if (wave_out) {
- if ((wave_out->state == CARDWAVE_STATE_STARTED)
- && !(file->f_flags & O_NONBLOCK)) {
- while (!signal_pending(current)
- && (woinst->total_played < woinst->total_copied)) {
- DPF(4, "Buffer hasn't been totally played, sleep....\n");
- spin_unlock_irqrestore(&woinst->lock, flags);
- interruptible_sleep_on(&woinst->wait_queue);
- spin_lock_irqsave(&woinst->lock, flags);
+ if (woinst->state & WAVE_STATE_OPEN) {
+ if (woinst->state & WAVE_STATE_STARTED) {
+ if (!(file->f_flags & O_NONBLOCK)) {
+ while (!signal_pending(current)
+ && (woinst->total_played < woinst->total_copied)) {
+ DPF(4, "Buffer hasn't been totally played, sleep....\n");
+ spin_unlock_irqrestore(&woinst->lock, flags);
+ interruptible_sleep_on(&woinst->wait_queue);
+ spin_lock_irqsave(&woinst->lock, flags);
+ }
}
}
- if (woinst->mapped && wave_out->pagetable) {
+ if (woinst->mmapped) {
int i;
/* Undo marking the pages as reserved */
- for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++)
- mem_map_reserve(virt_to_page(woinst->wave_out->pagetable[i]));
+ for (i = 0; i < woinst->buffer.pages; i++)
+ mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));
}
- woinst->mapped = 0;
emu10k1_waveout_close(wave_dev);
}
#ifdef PRIVATE_PCM_VOLUME
}
#endif
spin_unlock_irqrestore(&woinst->lock, flags);
+ /* wait for the tasklet (bottom-half) to finish */
+ tasklet_unlock_wait(&woinst->timer.tasklet);
kfree(wave_dev->woinst);
}
if (file->f_mode & FMODE_READ) {
struct wiinst *wiinst = wave_dev->wiinst;
- struct wave_in *wave_in;
spin_lock_irqsave(&wiinst->lock, flags);
- wave_in = wiinst->wave_in;
-
- if (wave_in) {
- wiinst->mapped = 0;
+ if (wiinst->state & WAVE_STATE_OPEN)
emu10k1_wavein_close(wave_dev);
- }
+
spin_unlock_irqrestore(&wiinst->lock, flags);
+ tasklet_unlock_wait(&wiinst->timer.tasklet);
kfree(wave_dev->wiinst);
}
struct woinst *woinst = wave_dev->woinst;
struct wiinst *wiinst = wave_dev->wiinst;
unsigned int mask = 0;
- u32 bytestocopy, pending, dummy;
+ u32 bytestocopy;
unsigned long flags;
DPF(4, "emu10k1_audio_poll()\n");
poll_wait(file, &wiinst->wait_queue, wait);
if (file->f_mode & FMODE_WRITE) {
- struct wave_out *wave_out;
-
spin_lock_irqsave(&woinst->lock, flags);
- wave_out = woinst->wave_out;
-
- if (wave_out) {
+ if (woinst->state & WAVE_STATE_OPEN) {
+ emu10k1_waveout_update(woinst);
+ emu10k1_waveout_getxfersize(woinst, &bytestocopy);
- emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
-
- if (bytestocopy >= woinst->fragment_size)
+ if (bytestocopy >= woinst->buffer.fragment_size)
mask |= POLLOUT | POLLWRNORM;
} else
mask |= POLLOUT | POLLWRNORM;
+ if(woinst->mmapped) {
+ spin_unlock_irqrestore(&woinst->lock, flags);
+ return mask;
+ }
+
spin_unlock_irqrestore(&woinst->lock, flags);
}
if (file->f_mode & FMODE_READ) {
- struct wave_in *wave_in;
-
spin_lock_irqsave(&wiinst->lock, flags);
- wave_in = wiinst->wave_in;
-
- if (!wave_in) {
+ if (wiinst->state == WAVE_STATE_CLOSED) {
calculate_ifrag(wiinst);
- if (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) {
+ if (emu10k1_wavein_open(wave_dev) < 0) {
spin_unlock_irqrestore(&wiinst->lock, flags);
return (mask |= POLLERR);
}
-
- wave_in = wiinst->wave_in;
}
- if (wave_in->state != CARDWAVE_STATE_STARTED) {
+ if (!(wiinst->state & WAVE_STATE_STARTED)) {
wave_dev->enablebits |= PCM_ENABLE_INPUT;
emu10k1_wavein_start(wave_dev);
}
+ emu10k1_wavein_update(wave_dev->card, wiinst);
+ emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
- emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
-
- if (bytestocopy >= wiinst->fragment_size)
+ if (bytestocopy >= wiinst->buffer.fragment_size)
mask |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&wiinst->lock, flags);
static void calculate_ofrag(struct woinst *woinst)
{
- u32 fragsize, bytespersec;
+ struct waveout_buffer *buffer = &woinst->buffer;
+ u32 fragsize;
- if (woinst->fragment_size)
+ if (buffer->fragment_size)
return;
- bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitsperchannel >> 3) * woinst->wave_fmt.samplingrate;
-
- if (!woinst->ossfragshift) {
- fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1;
+ if (!buffer->ossfragshift) {
+ fragsize = (woinst->format.bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1;
while (fragsize) {
fragsize >>= 1;
- woinst->ossfragshift++;
+ buffer->ossfragshift++;
}
}
- if (woinst->ossfragshift < WAVEOUT_MINFRAGSHIFT)
- woinst->ossfragshift = WAVEOUT_MINFRAGSHIFT;
+ if (buffer->ossfragshift < WAVEOUT_MINFRAGSHIFT)
+ buffer->ossfragshift = WAVEOUT_MINFRAGSHIFT;
- woinst->fragment_size = 1 << woinst->ossfragshift;
+ buffer->fragment_size = 1 << buffer->ossfragshift;
- if (!woinst->numfrags) {
+ if (!buffer->numfrags) {
u32 numfrags;
- numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN) / (woinst->fragment_size * 1000) - 1;
+ numfrags = (woinst->format.bytespersec * WAVEOUT_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1;
- woinst->numfrags = 1;
+ buffer->numfrags = 1;
while (numfrags) {
numfrags >>= 1;
- woinst->numfrags <<= 1;
+ buffer->numfrags <<= 1;
}
}
- if (woinst->numfrags < MINFRAGS)
- woinst->numfrags = MINFRAGS;
+ if (buffer->numfrags < MINFRAGS)
+ buffer->numfrags = MINFRAGS;
- if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE) {
- woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size;
+ if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE) {
+ buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size;
- if (woinst->numfrags < MINFRAGS) {
- woinst->numfrags = MINFRAGS;
- woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;
+ if (buffer->numfrags < MINFRAGS) {
+ buffer->numfrags = MINFRAGS;
+ buffer->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;
}
- } else if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE)
- woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size;
+ } else if (buffer->numfrags * buffer->fragment_size < WAVEOUT_MINBUFSIZE)
+ buffer->numfrags = WAVEOUT_MINBUFSIZE / buffer->fragment_size;
+
+ buffer->size = buffer->fragment_size * buffer->numfrags;
+ buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);
- DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size);
- DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags);
+ DPD(2, " calculated playback fragment_size -> %d\n", buffer->fragment_size);
+ DPD(2, " calculated playback numfrags -> %d\n", buffer->numfrags);
+
+ return;
}
static void calculate_ifrag(struct wiinst *wiinst)
{
- u32 fragsize, bytespersec;
+ struct wavein_buffer *buffer = &wiinst->buffer;
+ u32 fragsize, bufsize, size[4];
+ int i, j;
- if (wiinst->fragment_size)
+ if (buffer->fragment_size)
return;
- bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitsperchannel >> 3) * wiinst->wave_fmt.samplingrate;
-
- if (!wiinst->ossfragshift) {
- fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1;
+ if (!buffer->ossfragshift) {
+ fragsize = (wiinst->format.bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1;
while (fragsize) {
fragsize >>= 1;
- wiinst->ossfragshift++;
+ buffer->ossfragshift++;
}
}
- if (wiinst->ossfragshift < WAVEIN_MINFRAGSHIFT)
- wiinst->ossfragshift = WAVEIN_MINFRAGSHIFT;
+ if (buffer->ossfragshift < WAVEIN_MINFRAGSHIFT)
+ buffer->ossfragshift = WAVEIN_MINFRAGSHIFT;
- wiinst->fragment_size = 1 << wiinst->ossfragshift;
+ buffer->fragment_size = 1 << buffer->ossfragshift;
- if (!wiinst->numfrags)
- wiinst->numfrags = (bytespersec * WAVEIN_DEFAULTBUFLEN) / (wiinst->fragment_size * 1000) - 1;
+ if (!buffer->numfrags)
+ buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1;
- if (wiinst->numfrags < MINFRAGS)
- wiinst->numfrags = MINFRAGS;
+ if (buffer->numfrags < MINFRAGS)
+ buffer->numfrags = MINFRAGS;
- if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) {
- wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size;
+ if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE) {
+ buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size;
- if (wiinst->numfrags < MINFRAGS) {
- wiinst->numfrags = MINFRAGS;
- wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;
+ if (buffer->numfrags < MINFRAGS) {
+ buffer->numfrags = MINFRAGS;
+ buffer->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;
+ }
+ } else if (buffer->numfrags * buffer->fragment_size < WAVEIN_MINBUFSIZE)
+ buffer->numfrags = WAVEIN_MINBUFSIZE / buffer->fragment_size;
+
+ bufsize = buffer->fragment_size * buffer->numfrags;
+
+ if (bufsize >= 0x10000) {
+ buffer->size = 0x10000;
+ buffer->sizeregval = 0x1f;
+ } else {
+ buffer->size = 0;
+ size[0] = 384;
+ size[1] = 448;
+ size[2] = 512;
+ size[3] = 640;
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 4; j++)
+ if (bufsize >= size[j]) {
+ buffer->size = size[j];
+ size[j] *= 2;
+ buffer->sizeregval = i * 4 + j + 1;
+ } else
+ goto exitloop;
+ exitloop:
+ if (buffer->size == 0) {
+ buffer->size = 384;
+ buffer->sizeregval = 0x01;
}
- } else if (wiinst->numfrags * wiinst->fragment_size < WAVEIN_MINBUFSIZE)
- wiinst->numfrags = WAVEIN_MINBUFSIZE / wiinst->fragment_size;
+ }
+
+ buffer->numfrags = buffer->size / buffer->fragment_size;
+
+ if (buffer->size % buffer->fragment_size)
+ BUG();
+
+ DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size);
+ DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags);
+ DPD(2, " buffer size register -> 0x%2x\n", buffer->sizeregval);
- DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size);
- DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags);
+ return;
}
void emu10k1_wavein_bh(unsigned long refdata)
{
struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
struct wiinst *wiinst = wave_dev->wiinst;
- struct wave_in *wave_in = wiinst->wave_in;
- u32 bytestocopy, curpos;
+ u32 bytestocopy;
unsigned long flags;
spin_lock_irqsave(&wiinst->lock, flags);
- if (wave_in->state == CARDWAVE_STATE_STOPPED) {
+ if (!(wiinst->state & WAVE_STATE_STARTED)) {
spin_unlock_irqrestore(&wiinst->lock, flags);
return;
}
- emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &curpos);
-
- wiinst->total_recorded += curpos - wiinst->curpos;
-
- if (curpos < wiinst->curpos)
- wiinst->total_recorded += wiinst->fragment_size * wiinst->numfrags;
-
- wiinst->curpos = curpos;
+ emu10k1_wavein_update(wave_dev->card, wiinst);
- if (wiinst->mapped) {
+ if (wiinst->mmapped) {
spin_unlock_irqrestore(&wiinst->lock, flags);
return;
}
+ emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
+
spin_unlock_irqrestore(&wiinst->lock, flags);
- if (bytestocopy >= wiinst->fragment_size)
+ if (bytestocopy >= wiinst->buffer.fragment_size)
wake_up_interruptible(&wiinst->wait_queue);
else
- DPD(4, "Not enough transfer size, %d\n", bytestocopy);
+ DPD(3, "Not enough transfer size, %d\n", bytestocopy);
return;
}
{
struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
struct woinst *woinst = wave_dev->woinst;
- struct wave_out *wave_out = woinst->wave_out;
- u32 bytestocopy, pending, curpos;
+ u32 bytestocopy;
unsigned long flags;
spin_lock_irqsave(&woinst->lock, flags);
- if (wave_out->state == CARDWAVE_STATE_STOPPED) {
+ if (!(woinst->state & WAVE_STATE_STARTED)) {
spin_unlock_irqrestore(&woinst->lock, flags);
return;
}
- emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &curpos);
-
- woinst->total_played += curpos - woinst->curpos;
-
- if (curpos < woinst->curpos)
- woinst->total_played += woinst->fragment_size * woinst->numfrags;
-
- woinst->curpos = curpos;
-
- if (woinst->mapped) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return;
- }
+ emu10k1_waveout_update(woinst);
+ emu10k1_waveout_getxfersize(woinst, &bytestocopy);
- if (wave_out->fill_silence) {
+ if (woinst->buffer.fill_silence) {
spin_unlock_irqrestore(&woinst->lock, flags);
emu10k1_waveout_fillsilence(woinst);
} else
spin_unlock_irqrestore(&woinst->lock, flags);
- if (bytestocopy >= woinst->fragment_size)
+ if (bytestocopy >= woinst->buffer.fragment_size)
wake_up_interruptible(&woinst->wait_queue);
else
- DPD(4, "Not enough transfer size -> %x\n", bytestocopy);
+ DPD(3, "Not enough transfer size -> %d\n", bytestocopy);
return;
}
struct file_operations emu10k1_audio_fops = {
- owner:THIS_MODULE,
- llseek:emu10k1_audio_llseek,
- read:emu10k1_audio_read,
- write:emu10k1_audio_write,
- poll:emu10k1_audio_poll,
- ioctl:emu10k1_audio_ioctl,
- mmap:emu10k1_audio_mmap,
- open:emu10k1_audio_open,
- release:emu10k1_audio_release,
+ owner: THIS_MODULE,
+ llseek: emu10k1_audio_llseek,
+ read: emu10k1_audio_read,
+ write: emu10k1_audio_write,
+ poll: emu10k1_audio_poll,
+ ioctl: emu10k1_audio_ioctl,
+ mmap: emu10k1_audio_mmap,
+ open: emu10k1_audio_open,
+ release: emu10k1_audio_release,
};
#ifndef _AUDIO_H
#define _AUDIO_H
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <asm/uaccess.h>
-
#define MINFRAGS 2 /* _don't_ got bellow 2 */
+struct emu10k1_wavedevice
+{
+ struct emu10k1_card *card;
+ struct wiinst *wiinst;
+ struct woinst *woinst;
+ u16 enablebits;
+};
+
void emu10k1_waveout_bh(unsigned long);
void emu10k1_wavein_bh(unsigned long);
**********************************************************************
*/
+#include <linux/malloc.h>
+#include <linux/sched.h>
+
#include "hwaccess.h"
+#include "8010.h"
#include "cardmi.h"
+#include "irqmgr.h"
static struct {
int (*Fn) (struct emu10k1_mpuin *, u8);
DPF(2, "emu10k1_mpuin_open\n");
if (!(card_mpuin->status & FLAGS_AVAILABLE))
- return CTSTATUS_INUSE;
+ return -1;
/* Copy open info and mark channel as in use */
card_mpuin->openinfo = *openinfo;
emu10k1_mpu_reset(card);
emu10k1_mpu_acquire(card);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int emu10k1_mpuin_close(struct emu10k1_card *card)
/* Check if there are pending input SysEx buffers */
if (card_mpuin->firstmidiq != NULL) {
ERROR();
- return CTSTATUS_ERROR;
+ return -1;
}
/* Disable RX interrupt */
card_mpuin->status |= FLAGS_AVAILABLE; /* set */
card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* Adds MIDI buffer to local queue list */
if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
/* Message lost */
- return CTSTATUS_ERROR;
+ return -1;
}
midiq->next = NULL;
spin_unlock_irqrestore(&card_mpuin->lock, flags);
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* First set the Time Stamp if MIDI IN has not started. */
if (card_mpuin->status & FLAGS_MIDM_STARTED) {
DPF(2, "Time Stamp not changed\n");
} else {
- while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS);
+ while (!emu10k1_mpu_read_data(card, &dummy));
card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */
emu10k1_irq_enable(card, INTE_MIDIRXENABLE);
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* Disable the RX Irq. If a partial recorded buffer */
}
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* Disable the RX Irq. If any buffer */
card_mpuin->lastmidiq = NULL;
card_mpuin->status &= ~FLAGS_MIDM_STARTED;
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* Passes the message with the data back to the client */
/* Notify client that Sysex buffer has been sent */
emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg);
- return CTSTATUS_SUCCESS;
+ return 0;
}
void emu10k1_mpuin_bh(unsigned long refdata)
idx = card_mpuin->qtail;
while (1) {
- if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) {
+ if (emu10k1_mpu_read_data(card, &MPUIvalue) < 0) {
+ break;
+ } else {
++count;
card_mpuin->midiq[idx].data = MPUIvalue;
card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ;
idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
- } else {
- break;
}
}
tasklet_hi_schedule(&card_mpuin->tasklet);
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
/*****************************************************************************/
card_mpuin->timestart = 0;
card_mpuin->timein = 0;
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* FIXME: This should be a macro */
case 0x7:
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0);
- return CTSTATUS_ERROR;
+ return -1;
case 0x2:
card_mpuin->laststate = card_mpuin->curstate;
default:
DPF(2, "BUG: default case hit\n");
- return CTSTATUS_ERROR;
+ return -1;
}
return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
- return CTSTATUS_ERROR;
+ return -1;
}
card_mpuin->data = data;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
- return CTSTATUS_ERROR;
+ return -1;
}
card_mpuin->curstate = STIN_3BYTE;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
- return CTSTATUS_ERROR;
+ return -1;
}
card_mpuin->curstate = STIN_2BYTE;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data)
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
- return CTSTATUS_ERROR;
+ return -1;
}
card_mpuin->curstate = card_mpuin->laststate;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data)
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
- return CTSTATUS_ERROR;
+ return -1;
}
card_mpuin->data = data;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
- return CTSTATUS_ERROR;
+ return -1;
}
card_mpuin->curstate = card_mpuin->laststate;
emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data)
kfree(midiq);
}
- return CTSTATUS_ERROR;
+ return -1;
}
if (card_mpuin->firstmidiq) {
kfree(midiq);
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
if (card_mpuin->firstmidiq) {
#define _CARDMI_H
#include "icardmid.h"
+#include <linux/interrupt.h>
typedef enum
{
**********************************************************************
*/
+#include <linux/malloc.h>
+
#include "hwaccess.h"
+#include "8010.h"
#include "cardmo.h"
+#include "irqmgr.h"
/* Installs the IRQ handler for the MPU out port *
* and initialize parameters */
DPF(2, "emu10k1_mpuout_open()\n");
if (!(card_mpuout->status & FLAGS_AVAILABLE))
- return CTSTATUS_INUSE;
+ return -1;
/* Copy open info and mark channel as in use */
card_mpuout->intr = 0;
emu10k1_mpu_reset(card);
emu10k1_mpu_acquire(card);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int emu10k1_mpuout_close(struct emu10k1_card *card)
spin_unlock_irqrestore(&card_mpuout->lock, flags);
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* If there isn't enough buffer space, reject Midi Buffer. *
DPF(2, "emu10k1_mpuout_add_buffer()\n");
if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
- return CTSTATUS_SUCCESS;
+ return 0;
midihdr->flags |= MIDIBUF_INQUEUE;
midihdr->flags &= ~MIDIBUF_DONE;
if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
/* Message lost */
- return CTSTATUS_NOMEMORY;
+ return -1;
}
midiq->next = NULL;
spin_unlock_irqrestore(&card_mpuout->lock, flags);
- return CTSTATUS_SUCCESS;
+ return 0;
}
void emu10k1_mpuout_bh(unsigned long refdata)
struct emu10k1_card *card = (struct emu10k1_card *) refdata;
struct emu10k1_mpuout *card_mpuout = card->mpuout;
int cByteSent = 0;
- int status;
struct midi_queue *midiq;
struct midi_queue *doneq = NULL;
unsigned long flags;
midiq = card_mpuout->firstmidiq;
while (cByteSent < 4 && midiq->sizeLeft) {
- status = emu10k1_mpu_write_data(card, *midiq->midibyte);
-
- if (status == CTSTATUS_SUCCESS) {
+ if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) {
+ DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
+ } else {
++cByteSent;
--midiq->sizeLeft;
++midiq->midibyte;
- } else {
- DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
}
}
tasklet_hi_schedule(&card_mpuout->tasklet);
- return CTSTATUS_SUCCESS;
+ return 0;
}
#define _CARDMO_H
#include "icardmid.h"
+#include <linux/interrupt.h>
#define CARDMIDIOUT_STATE_DEFAULT 0x00000000
#define CARDMIDIOUT_STATE_SUSPEND 0x00000001
-
/*
**********************************************************************
* cardwi.c - PCM input HAL for emu10k1 driver
**********************************************************************
*/
+#include <linux/poll.h>
#include "hwaccess.h"
+#include "timer.h"
#include "recmgr.h"
#include "audio.h"
#include "cardwi.h"
switch (recsrc) {
case WAVERECORD_AC97:
- if ((wave_fmt->channels != 2) && (wave_fmt->channels != 1))
+ if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
wave_fmt->channels = 2;
if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2)
else
wave_fmt->samplingrate = 0x1F40;
- if ((wave_fmt->bitsperchannel != 16) && (wave_fmt->bitsperchannel != 8))
+ if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16))
wave_fmt->bitsperchannel = 16;
break;
+ /* these can't be changed from the original values */
case WAVERECORD_MIC:
- wave_fmt->channels = 1;
- wave_fmt->samplingrate = 0x1F40;
- wave_fmt->bitsperchannel = 8;
- break;
-
case WAVERECORD_FX:
- wave_fmt->channels = 2;
- wave_fmt->samplingrate = 0xBB80;
- wave_fmt->bitsperchannel = 16;
break;
default:
+ BUG();
break;
}
+ wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
+ wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
+ wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
+
return;
}
-static int alloc_recbuffer(struct wave_in *wave_in, u32 * bufsize, u8 ** buffer)
+static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
- u32 reqsize;
- int i, j;
- u32 size[4];
-
- /* NOTE: record buffer size only can be certain sizes. If the requested
- * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */
- if (!wave_in->rec_ptr->is_16bit)
- *bufsize <<= 1;
-
- if (*bufsize >= 0x10000) {
- *bufsize = reqsize = 0x10000;
- wave_in->rec_ptr->bufsize = 31;
- } else {
- reqsize = 0;
- size[0] = 384;
- size[1] = 448;
- size[2] = 512;
- size[3] = 640;
-
- for (i = 0; i < 8; i++)
- for (j = 0; j < 4; j++)
- if (*bufsize >= size[j]) {
- reqsize = size[j];
- size[j] = size[j] * 2;
- wave_in->rec_ptr->bufsize = i * 4 + j + 1;
- } else
- goto exitloop;
- exitloop:
- if (reqsize == 0) {
- reqsize = 384;
- wave_in->rec_ptr->bufsize = 1;
- }
-
- *bufsize = reqsize;
- }
-
- DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsize);
+ if ((buffer->addr = pci_alloc_consistent(card->pci_dev, buffer->size * buffer->cov, &buffer->dma_handle)) == NULL)
+ return -1;
- /* Recording buffer must be continuous and page-aligned */
- if ((wave_in->memhandle = emu10k1_alloc_memphysical(reqsize)) == NULL)
- return CTSTATUS_ERROR;
-
- DPD(2, "recbufsize: %x\n", *bufsize);
-
- *buffer = (u8 *) wave_in->memhandle->virtaddx;
-
- return CTSTATUS_SUCCESS;
+ return 0;
}
-static int get_recbuffer(struct emu10k1_card *card, struct wave_in *wave_in, u32 * size)
+static void free_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
- u8 *buffer;
+ if (buffer->addr != NULL)
+ pci_free_consistent(card->pci_dev, buffer->size * buffer->cov, buffer->addr, buffer->dma_handle);
- wave_in->rec_ptr->card = card;
- wave_in->rec_ptr->recpos = 0;
- wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate;
- wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0;
- wave_in->rec_ptr->is_16bit = (wave_in->wave_fmt.bitsperchannel == 16) ? 1 : 0;
-
- /* Allocate buffer here */
- if (alloc_recbuffer(wave_in, size, &buffer) != CTSTATUS_SUCCESS) {
- ERROR();
- return CTSTATUS_ERROR;
- }
-
- /* recbufsize contains actual record buffer size */
- /* for 8 bit samples the size is twice the requested */
- /* value since we only make use of one in every two bytes */
- wave_in->rec_ptr->recbufsize = *size;
- wave_in->rec_ptr->recbuffer = buffer;
- wave_in->rec_ptr->busaddx = wave_in->memhandle->busaddx;
-
- return CTSTATUS_SUCCESS;
-}
-
-static void dealloc_recbuffer(struct wave_in *wave_in)
-{
- emu10k1_free_memphysical(wave_in->memhandle);
return;
}
{
struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst;
- struct wave_in *wave_in;
- struct wave_in **wave_in_tmp = NULL;
- u32 buffsize, bytespersec, delay;
+ struct wiinst **wiinst_tmp = NULL;
+ u32 delay;
unsigned long flags;
DPF(2, "emu10k1_wavein_open()\n");
- if ((wave_in = (struct wave_in *) kmalloc(sizeof(struct wave_in), GFP_KERNEL)) == NULL) {
- ERROR();
- return CTSTATUS_ERROR;
- }
-
- wave_in->state = CARDWAVE_STATE_STOPPED;
- wave_in->wave_fmt = wiinst->wave_fmt;
- wave_in->memhandle = NULL;
- wave_in->timer = NULL;
-
switch (wiinst->recsrc) {
case WAVERECORD_AC97:
- wave_in_tmp = &card->wavein->ac97;
+ wiinst_tmp = &card->wavein.ac97;
break;
case WAVERECORD_MIC:
- wave_in_tmp = &card->wavein->mic;
+ wiinst_tmp = &card->wavein.mic;
break;
case WAVERECORD_FX:
- wave_in_tmp = &card->wavein->fx;
+ wiinst_tmp = &card->wavein.fx;
break;
default:
+ BUG();
break;
}
spin_lock_irqsave(&card->lock, flags);
- if (*wave_in_tmp != NULL) {
+ if (*wiinst_tmp != NULL) {
spin_unlock_irqrestore(&card->lock, flags);
- kfree(wave_in);
- return CTSTATUS_ERROR;
+ return -1;
}
- *wave_in_tmp = wave_in;
+ *wiinst_tmp = wiinst;
spin_unlock_irqrestore(&card->lock, flags);
- wiinst->wave_in = wave_in;
+ /* handle 8 bit recording */
+ if (wiinst->format.bytesperchannel == 1) {
+ if (wiinst->buffer.size > 0x8000) {
+ wiinst->buffer.size = 0x8000;
+ wiinst->buffer.sizeregval = 0x1f;
+ } else
+ wiinst->buffer.sizeregval += 4;
- if ((wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)) == NULL) {
- ERROR();
- emu10k1_wavein_close(wave_dev);
- return CTSTATUS_ERROR;
- }
+ wiinst->buffer.cov = 2;
+ } else
+ wiinst->buffer.cov = 1;
- buffsize = wiinst->fragment_size * wiinst->numfrags;
-
- if (get_recbuffer(card, wave_in, &buffsize) != CTSTATUS_SUCCESS) {
+ if (alloc_buffer(card, &wiinst->buffer) < 0) {
ERROR();
emu10k1_wavein_close(wave_dev);
- return CTSTATUS_ERROR;
+ return -1;
}
- wiinst->fragment_size = buffsize / wiinst->numfrags;
-
- /* This callback size returned is the size in the play buffer.
- * For 8-bit samples, callbacksize of user buffer should be
- * half of the callbacksize in play buffer. */
- if (wave_in->wave_fmt.bitsperchannel == 8)
- wiinst->fragment_size >>= 1;
+ emu10k1_set_record_src(card, wiinst);
- wave_in->callbacksize = wiinst->fragment_size;
+ delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
- emu10k1_set_record_src(wave_in->rec_ptr, wiinst->recsrc);
+ emu10k1_timer_install(card, &wiinst->timer, delay / 2);
- bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate);
- delay = (48000 * wave_in->callbacksize) / bytespersec;
-
- if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
- ERROR();
- emu10k1_wavein_close(wave_dev);
- return CTSTATUS_ERROR;
- }
+ wiinst->state = WAVE_STATE_OPEN;
- return CTSTATUS_SUCCESS;
+ return 0;
}
void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
- struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+ struct wiinst *wiinst = wave_dev->wiinst;
unsigned long flags;
- if (wave_in->state != CARDWAVE_STATE_STOPPED)
- emu10k1_wavein_stop(wave_dev);
+ DPF(2, "emu10k1_wavein_close()\n");
- if (wave_in->timer != NULL)
- emu10k1_timer_uninstall(card, wave_in->timer);
+ emu10k1_wavein_stop(wave_dev);
- if (wave_in->memhandle != NULL)
- dealloc_recbuffer(wave_in);
+ emu10k1_timer_uninstall(card, &wiinst->timer);
- if (wave_in->rec_ptr != NULL)
- kfree(wave_in->rec_ptr);
+ free_buffer(card, &wiinst->buffer);
spin_lock_irqsave(&card->lock, flags);
switch (wave_dev->wiinst->recsrc) {
case WAVERECORD_AC97:
- card->wavein->ac97 = NULL;
+ card->wavein.ac97 = NULL;
break;
case WAVERECORD_MIC:
- card->wavein->mic = NULL;
+ card->wavein.mic = NULL;
break;
case WAVERECORD_FX:
- card->wavein->fx = NULL;
+ card->wavein.fx = NULL;
break;
default:
+ BUG();
break;
}
spin_unlock_irqrestore(&card->lock, flags);
- kfree(wave_in);
- wave_dev->wiinst->wave_in = NULL;
+ wiinst->state = WAVE_STATE_CLOSED;
return;
}
void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev)
{
- struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+ struct emu10k1_card *card = wave_dev->card;
+ struct wiinst *wiinst = wave_dev->wiinst;
DPF(2, "emu10k1_wavein_start()\n");
- if (wave_in->state == CARDWAVE_STATE_STARTED)
- return;
+ emu10k1_start_record(card, &wiinst->buffer);
+ emu10k1_timer_enable(wave_dev->card, &wiinst->timer);
- emu10k1_start_record(wave_in->rec_ptr);
- wave_in->state = CARDWAVE_STATE_STARTED;
+ wiinst->buffer.hw_pos = 0;
+ wiinst->buffer.pos = 0;
+ wiinst->buffer.bytestocopy = 0;
- emu10k1_timer_enable(wave_dev->card, wave_in->timer);
+ wiinst->state |= WAVE_STATE_STARTED;
return;
}
void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev)
{
- struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+ struct emu10k1_card *card = wave_dev->card;
+ struct wiinst *wiinst = wave_dev->wiinst;
DPF(2, "emu10k1_wavein_stop()\n");
- emu10k1_stop_record(wave_in->rec_ptr);
- emu10k1_timer_disable(wave_dev->card, wave_in->timer);
+ if (!(wiinst->state & WAVE_STATE_STARTED))
+ return;
- wave_in->rec_ptr->recpos = 0;
- wave_in->state = CARDWAVE_STATE_STOPPED;
+ emu10k1_timer_disable(card, &wiinst->timer);
+ emu10k1_stop_record(card, &wiinst->buffer);
+
+ wiinst->state &= ~WAVE_STATE_STARTED;
return;
}
-int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev)
+int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format)
{
struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst;
- struct wave_in *wave_in = wiinst->wave_in;
- u32 bytespersec, delay;
+ u32 delay;
DPF(2, "emu10k1_wavein_setformat()\n");
- query_format(wiinst->recsrc, &wiinst->wave_fmt);
+ if (wiinst->state & WAVE_STATE_STARTED)
+ return -1;
- if (!wave_in)
- return CTSTATUS_SUCCESS;
+ query_format(wiinst->recsrc, format);
- if (wave_in->state == CARDWAVE_STATE_STARTED) {
- wiinst->wave_fmt = wave_in->wave_fmt;
- return CTSTATUS_SUCCESS;
- }
+ if ((wiinst->format.samplingrate != format->samplingrate)
+ || (wiinst->format.bitsperchannel != format->bitsperchannel)
+ || (wiinst->format.channels != format->channels)) {
- if ((wave_in->wave_fmt.samplingrate != wiinst->wave_fmt.samplingrate)
- || (wave_in->wave_fmt.bitsperchannel != wiinst->wave_fmt.bitsperchannel)
- || (wave_in->wave_fmt.channels != wiinst->wave_fmt.channels)) {
+ wiinst->format = *format;
- emu10k1_timer_uninstall(card, wave_in->timer);
+ if (wiinst->state == WAVE_STATE_CLOSED)
+ return 0;
- wave_in->wave_fmt = wiinst->wave_fmt;
+ wiinst->buffer.size *= wiinst->buffer.cov;
- bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate);
- delay = (48000 * wave_in->callbacksize) / bytespersec;
+ if (wiinst->format.bytesperchannel == 1) {
+ wiinst->buffer.cov = 2;
+ wiinst->buffer.size /= wiinst->buffer.cov;
+ } else
+ wiinst->buffer.cov = 1;
- if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
- ERROR();
- emu10k1_wavein_close(wave_dev);
- return CTSTATUS_ERROR;
- }
+ emu10k1_timer_uninstall(card, &wiinst->timer);
+
+ delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
+
+ emu10k1_timer_install(card, &wiinst->timer, delay / 2);
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
-void emu10k1_wavein_getxfersize(struct wave_in *wave_in, u32 * size, u32 * curpos)
+void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size)
{
- struct record *rec_ptr = wave_in->rec_ptr;
-
- /* Get position of current address, this is in no. of bytes in play buffer */
- emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, curpos);
+ struct wavein_buffer *buffer = &wiinst->buffer;
- *size = *curpos - rec_ptr->recpos;
+ *size = buffer->bytestocopy;
- /* Recpos is the actual position in user buffer and play buffer */
- if (*curpos < rec_ptr->recpos)
- *size += rec_ptr->recbufsize;
-
- if (!rec_ptr->is_16bit)
- *size >>= 1;
+ if (*size > buffer->size) {
+ *size = buffer->size;
+ buffer->pos = buffer->hw_pos;
+ buffer->bytestocopy = buffer->size;
+ DPF(1, "buffer overrun\n");
+ }
return;
}
-static void copy_s16_to_u8(u8 * dstbuf, s16 * srcbuf, u32 size)
+static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov)
{
- u16 sample;
- u8 byte;
-
- while (size--) {
- sample = (*srcbuf) + 32767;
- byte = (u8) (sample >> 8);
- copy_to_user(dstbuf, &byte, 1);
- dstbuf++;
- srcbuf++;
+ if (cov == 1)
+ copy_to_user(dst, src + str, len);
+ else {
+ u8 byte;
+ u32 i;
+
+ src += 1 + 2 * str;
+
+ for (i = 0; i < len; i++) {
+ byte = src[2 * i] ^ 0x80;
+ copy_to_user(dst + i, &byte, 1);
+ }
}
+
+ return;
}
-/* transfer the data from the wave device. */
void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size)
{
- struct wave_in *wave_in = wiinst->wave_in;
- struct record *rec_ptr = wave_in->rec_ptr;
+ struct wavein_buffer *buffer = &wiinst->buffer;
u32 sizetocopy, sizetocopy_now, start;
unsigned long flags;
- sizetocopy = min(rec_ptr->recbufsize * (rec_ptr->is_16bit + 1) / 2, *size);
+ sizetocopy = min(buffer->size, *size);
*size = sizetocopy;
if (!sizetocopy)
return;
spin_lock_irqsave(&wiinst->lock, flags);
+ start = buffer->pos;
+ buffer->pos += sizetocopy;
+ buffer->pos %= buffer->size;
+ buffer->bytestocopy -= sizetocopy;
+ sizetocopy_now = buffer->size - start;
- sizetocopy_now = (rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is_16bit + 1) / 2;
-
- start = rec_ptr->recpos;
+ spin_unlock_irqrestore(&wiinst->lock, flags);
if (sizetocopy > sizetocopy_now) {
sizetocopy -= sizetocopy_now;
- rec_ptr->recpos = sizetocopy * 2 / (rec_ptr->is_16bit + 1);
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- if (rec_ptr->is_16bit) {
- copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy_now);
- copy_to_user(data + sizetocopy_now, rec_ptr->recbuffer, sizetocopy);
- } else {
- copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy_now);
- copy_s16_to_u8(data + sizetocopy_now, (s16 *) rec_ptr->recbuffer, sizetocopy);
- }
+ copy_block(data, buffer->addr, start, sizetocopy_now, buffer->cov);
+ copy_block(data + sizetocopy_now, buffer->addr, 0, sizetocopy, buffer->cov);
} else {
- if (sizetocopy == sizetocopy_now)
- rec_ptr->recpos = 0;
- else
- rec_ptr->recpos += sizetocopy * 2 / (rec_ptr->is_16bit + 1);
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- if (rec_ptr->is_16bit)
- copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy);
- else
- copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy);
+ copy_block(data, buffer->addr, start, sizetocopy, buffer->cov);
}
return;
}
-/* get the specified control value of the wave device. */
-
-int emu10k1_wavein_getcontrol(struct wave_in *wave_in, u32 ctrlid, u32 * value)
+void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst)
{
- switch (ctrlid) {
- case WAVECURPOS:
- /* There is no actual start yet */
- if (wave_in->state == CARDWAVE_STATE_STOPPED) {
- *value = 0;
- } else {
- /* value is in byte units */
- *value = sblive_readptr(wave_in->rec_ptr->card, wave_in->rec_ptr->bufidxreg, 0);
- }
-
- break;
+ u32 hw_pos;
+ u32 diff;
- default:
- return CTSTATUS_ERROR;
+ /* There is no actual start yet */
+ if (!(wiinst->state & WAVE_STATE_STARTED)) {
+ hw_pos = wiinst->buffer.hw_pos;
+ } else {
+ /* hw_pos in byte units */
+ hw_pos = sblive_readptr(card, wiinst->buffer.idxreg, 0) / wiinst->buffer.cov;
}
- return CTSTATUS_SUCCESS;
+ diff = (wiinst->buffer.size + hw_pos - wiinst->buffer.hw_pos) % wiinst->buffer.size;
+ wiinst->total_recorded += diff;
+ wiinst->buffer.bytestocopy += diff;
+
+ wiinst->buffer.hw_pos = hw_pos;
+
+ return;
}
#define _CARDWI_H
#include "icardwav.h"
+#include "audio.h"
+#include "timer.h"
-struct wave_in
-{
- struct list_head list;
-
- u32 state;
- struct record *rec_ptr;
- struct memhandle *memhandle;
- struct emu_timer *timer;
- u32 callbacksize;
- struct wave_format wave_fmt;
+struct wavein_buffer {
+ u16 ossfragshift;
+ u32 fragment_size;
+ u32 numfrags;
+ u32 hw_pos; /* hardware cursor position */
+ u32 pos; /* software cursor position */
+ u32 bytestocopy; /* bytes of recorded data available */
+ u32 size;
+ u32 sizereg;
+ u32 sizeregval;
+ u32 addrreg;
+ u32 idxreg;
+ u32 adcctl;
+ void *addr;
+ u8 cov;
+ dma_addr_t dma_handle;
};
struct wiinst
{
- struct wave_in *wave_in;
- struct wave_format wave_fmt;
- u16 ossfragshift;
- u32 fragment_size;
- u32 numfrags;
+ u8 state;
+ struct emu_timer timer;
+ struct wave_format format;
+ struct wavein_buffer buffer;
wait_queue_head_t wait_queue;
- int mapped;
- u32 total_recorded;
+ u8 mmapped;
+ u32 total_recorded; /* total bytes read() from device */
u32 blocks;
- u32 curpos;
spinlock_t lock;
u8 recsrc;
+ u16 fxwc;
};
-struct emu10k1_wavein
-{
- struct wave_in *ac97;
- struct wave_in *mic;
- struct wave_in *fx;
-
- u8 recsrc;
-};
-
-
#define WAVEIN_MAXBUFSIZE 65536
#define WAVEIN_MINBUFSIZE 368
void emu10k1_wavein_close(struct emu10k1_wavedevice *);
void emu10k1_wavein_start(struct emu10k1_wavedevice *);
void emu10k1_wavein_stop(struct emu10k1_wavedevice *);
-void emu10k1_wavein_getxfersize(struct wave_in *, u32 *, u32 *);
+void emu10k1_wavein_getxfersize(struct wiinst *, u32 *);
void emu10k1_wavein_xferdata(struct wiinst *, u8 *, u32 *);
-int emu10k1_wavein_setformat(struct emu10k1_wavedevice *);
-int emu10k1_wavein_getcontrol(struct wave_in *, u32, u32 *);
+int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *);
+void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *);
#endif /* _CARDWI_H */
-
/*
**********************************************************************
* cardwo.c - PCM output HAL for emu10k1 driver
**********************************************************************
*/
+#include <linux/poll.h>
#include "hwaccess.h"
+#include "8010.h"
+#include "voicemgr.h"
#include "cardwo.h"
#include "audio.h"
-/* Volume calcs */
-
-static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left)
+static u32 samplerate_to_linearpitch(u32 samplingrate)
{
- /* only applicable for playback */
- u32 volL, volR, vol = 0;
-
- volL = (wave_out->localvol & 0xffff);
- volR = ((wave_out->localvol >> 16) & 0xffff);
-
- if (wave_out->globalvolFactor) {
- volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff;
- volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff;
- }
-
- /* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */
- /* New volume and pan */
-
- if (volL == volR) {
- vol = volL;
- left->send_c = 0xff;
- left->send_b = 0xff;
- } else {
- if (volL > volR) {
- vol = volL;
- left->send_c = 0xff;
- left->send_b = (char) ((volR * 255) / vol);
- } else {
- vol = volR;
- left->send_b = 0xff;
- left->send_c = (char) ((volL * 255) / vol);
- }
- }
-
- left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2);
-
- return vol;
+ samplingrate = (samplingrate << 8) / 375;
+ return (samplingrate >> 1) + (samplingrate & 1);
}
static void query_format(struct wave_format *wave_fmt)
if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
wave_fmt->channels = 2;
- if (wave_fmt->samplingrate >= 0x2EE00)
- wave_fmt->samplingrate = 0x2EE00;
+ if (wave_fmt->samplingrate >= 0x2ee00)
+ wave_fmt->samplingrate = 0x2ee00;
if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16))
wave_fmt->bitsperchannel = 16;
+ wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
+ wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
+ wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
+
return;
}
-static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer)
+static int alloc_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer)
{
- u32 numpages, reqsize, pageindex, pagecount;
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+ u32 pageindex, pagecount;
unsigned long busaddx;
int i;
- reqsize = *size;
- numpages = reqsize / PAGE_SIZE;
-
- /* If size is not a multiple of PAGE_SIZE then we need to round up */
- if (reqsize % PAGE_SIZE)
- numpages += 1;
-
- DPD(2, "requested pages is: %d\n", numpages);
-
- wavexferbuf->numpages = numpages;
-
- /* Only for playback, request for emu address space */
- /* Support non page-aligned buffer, don't need interpolation page */
+ DPD(2, "requested pages is: %d\n", buffer->pages);
- if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0)
- return CTSTATUS_ERROR;
-
- if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL)
- return CTSTATUS_ERROR;
+ if ((buffer->emupageindex = emu10k1_addxmgr_alloc(buffer->pages * PAGE_SIZE, card)) < 0)
+ return -1;
/* Fill in virtual memory table */
- for (pagecount = 0; pagecount < numpages; pagecount++) {
- if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) {
- wavexferbuf->numpages = pagecount;
- return CTSTATUS_ERROR;
+ for (pagecount = 0; pagecount < buffer->pages; pagecount++) {
+ if ((buffer->addr[pagecount] = pci_alloc_consistent(card->pci_dev, PAGE_SIZE, &buffer->dma_handle[pagecount])) == NULL) {
+ buffer->pages = pagecount;
+ return -1;
}
- DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]);
+ DPD(2, "Virtual Addx: %p\n", buffer->addr[pagecount]);
for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
- busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE);
+ busaddx = buffer->dma_handle[pagecount] + i * EMUPAGESIZE;
DPD(3, "Bus Addx: %lx\n", busaddx);
- pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
+ pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
- ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex;
+ ((u32 *) card->virtualpagetable.addr)[pageindex] = (busaddx * 2) | pageindex;
}
}
- *buffer = wave_out->pagetable;
-
- return CTSTATUS_SUCCESS;
-}
-
-static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size)
-{
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
- void **buffer;
-
- wavexferbuf->xferpos = 0;
- wavexferbuf->silence_xferpos = 0;
- wavexferbuf->stopposition = 0;
- wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
- wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
- wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
-
- if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS)
- return CTSTATUS_ERROR;
-
- /* xferbufsize contains actual transfer buffer size */
- wavexferbuf->xferbufsize = *size;
- wavexferbuf->xferbuffer = buffer;
-
- return CTSTATUS_SUCCESS;
+ return 0;
}
-static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out)
+static void free_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer)
{
u32 pagecount, pageindex;
int i;
- if (wave_out->pagetable != NULL) {
- for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) {
- free_page((unsigned long) wave_out->pagetable[pagecount]);
+ if (buffer->emupageindex < 0)
+ return;
+
+ for (pagecount = 0; pagecount < buffer->pages; pagecount++) {
+ pci_free_consistent(card->pci_dev, PAGE_SIZE, buffer->addr[pagecount], buffer->dma_handle[pagecount]);
- for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
- pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
- ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex;
- }
+ for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
+ pageindex = buffer->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
+ ((u32 *) card->virtualpagetable.addr)[pageindex] = (card->silentpage.dma_handle * 2) | pageindex;
}
- kfree(wave_out->pagetable);
}
- emu10k1_addxmgr_free(card, wave_out->emupageindex);
+ emu10k1_addxmgr_free(card, buffer->emupageindex);
+ buffer->emupageindex = -1;
return;
}
-static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device)
+static int get_voice(struct emu10k1_card *card, struct woinst *woinst)
{
- struct emu10k1_waveout *card_waveout = card->waveout;
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
- struct voice_allocdesc voice_allocdesc;
- struct voice_param *left, *right;
- u32 size;
-
+ struct emu_voice *voice = &woinst->voice;
/* Allocate voices here, if no voices available, return error.
* Init voice_allocdesc first.*/
- voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK;
-
- voice_allocdesc.flags = 0;
-
- if (device == 1)
- voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2;
-
- if (wave_out->wave_fmt.channels == 1)
- voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO;
+ voice->usage = VOICE_USAGE_PLAYBACK;
- if (wave_out->wave_fmt.bitsperchannel == 16)
- voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT;
+ voice->flags = 0;
- if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL)
- return CTSTATUS_ERROR;
+ if (woinst->format.channels == 2)
+ voice->flags |= VOICE_FLAGS_STEREO;
- /* voice initialization */
+ if (woinst->format.bitsperchannel == 16)
+ voice->flags |= VOICE_FLAGS_16BIT;
- left = &wave_out->voice->params;
+ if (emu10k1_voice_alloc(card, voice) < 0)
+ return -1;
/* Calculate pitch */
- left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8);
+ voice->initial_pitch = (u16) (srToPitch(woinst->format.samplingrate) >> 8);
+ voice->pitch_target = samplerate_to_linearpitch(woinst->format.samplingrate);
- DPD(2, "Initial pitch --> %x\n", left->initial_pitch);
+ DPD(2, "Initial pitch --> 0x%x\n", voice->initial_pitch);
- /* Easy way out.. gotta calculate value */
- left->pitch_target = 0;
- left->volume_target = 0;
- left->FC_target = 0;
+ voice->startloop = (woinst->buffer.emupageindex << 12) / woinst->format.bytespersample;
+ voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespersample;
+ voice->start = voice->startloop;
- left->byampl_env_sustain = 0x7f;
- left->byampl_env_decay = 0x7f;
+ if (voice->flags & VOICE_FLAGS_STEREO) {
+ voice->params[0].send_a = card->waveout.send_a[1];
+ voice->params[0].send_b = card->waveout.send_b[1];
+ voice->params[0].send_c = card->waveout.send_c[1];
+ voice->params[0].send_d = card->waveout.send_d[1];
- if (wave_out->globalreverbFactor) {
- u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff);
+ if (woinst->device)
+ voice->params[0].send_routing = 0xd23c;
+ else
+ voice->params[0].send_routing = card->waveout.send_routing[1];
- left->send_a = (t > 255) ? 255 : t;
- } else {
- left->send_a = 0;
- }
+ voice->params[0].volume_target = 0xffff;
+ voice->params[0].initial_fc = 0xff;
+ voice->params[0].initial_attn = 0x00;
+ voice->params[0].byampl_env_sustain = 0x7f;
+ voice->params[0].byampl_env_decay = 0x7f;
- if (wave_out->globalchorusFactor) {
- u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff);
+ voice->params[1].send_a = card->waveout.send_a[2];
+ voice->params[1].send_b = card->waveout.send_b[2];
+ voice->params[1].send_c = card->waveout.send_c[2];
+ voice->params[1].send_d = card->waveout.send_d[2];
+
+ if (woinst->device)
+ voice->params[1].send_routing = 0xd23c;
+ else
+ voice->params[1].send_routing = card->waveout.send_routing[2];
- left->send_d = (t > 255) ? 255 : t;
+ voice->params[1].volume_target = 0xffff;
+ voice->params[1].initial_fc = 0xff;
+ voice->params[1].initial_attn = 0x00;
+ voice->params[1].byampl_env_sustain = 0x7f;
+ voice->params[1].byampl_env_decay = 0x7f;
} else {
- left->send_d = 0;
+ voice->params[0].send_a = card->waveout.send_a[0];
+ voice->params[0].send_b = card->waveout.send_b[0];
+ voice->params[0].send_c = card->waveout.send_c[0];
+ voice->params[0].send_d = card->waveout.send_d[0];
+
+ if (woinst->device)
+ voice->params[0].send_routing = 0xd23c;
+ else
+ voice->params[0].send_routing = card->waveout.send_routing[0];
+
+ voice->params[0].volume_target = 0xffff;
+ voice->params[0].initial_fc = 0xff;
+ voice->params[0].initial_attn = 0x00;
+ voice->params[0].byampl_env_sustain = 0x7f;
+ voice->params[0].byampl_env_decay = 0x7f;
}
- set_volume_instance(card_waveout, wave_out, left);
-
- left->pan_target = left->send_c;
- left->aux_target = left->send_b;
-
- size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample;
- left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample;
- left->end = left->start + size;
- left->startloop = left->start;
- left->endloop = left->end;
-
- if (wave_out->voice->linked_voice) {
- DPF(2, "is stereo\n");
- right = &wave_out->voice->linked_voice->params;
-
- right->initial_pitch = left->initial_pitch;
+ DPD(2, "voice: startloop=0x%x, endloop=0x%x\n", voice->startloop, voice->endloop);
- /* Easy way out.. gotta calculate value */
- right->pitch_target = 0;
- right->volume_target = 0;
- right->FC_target = 0;
+ emu10k1_voice_playback_setup(voice);
- right->byampl_env_sustain = 0x7f;
- right->byampl_env_decay = 0x7f;
-
- right->send_d = left->send_d;
- right->send_a = left->send_a;
-
- /* Left output of right channel is always zero */
- right->send_c = 0;
-
- /* Update right channel aux */
- right->pan_target = 0;
- right->send_b = left->send_b;
- right->aux_target = right->send_b;
-
- /* Zero out right output of left channel */
- left->send_b = 0;
- left->aux_target = 0;
-
- /* Update right channel attenuation */
- right->initial_attn = left->initial_attn;
-
- right->start = left->start;
- right->end = left->end;
- right->startloop = left->startloop;
- right->endloop = left->endloop;
-
- }
-
- DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop);
-
- return CTSTATUS_SUCCESS;
+ return 0;
}
int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
- struct wave_out *wave_out;
- u32 bytespersec, delay;
- u32 buffsize;
+ u32 delay;
DPF(2, "emu10k1_waveout_open()\n");
- if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) {
- ERROR();
- emu10k1_waveout_close(wave_dev);
- return CTSTATUS_ERROR;
- }
-
- woinst->wave_out = wave_out;
-
- /* Init channel object */
- wave_out->state = CARDWAVE_STATE_STOPPED;
- wave_out->wave_fmt = woinst->wave_fmt;
- wave_out->voice = NULL;
- wave_out->emupageindex = -1;
- wave_out->wavexferbuf = NULL;
- wave_out->pagetable = NULL;
- wave_out->timer = NULL;
-
- /* Assign default local volume */
- /* FIXME: Should we be maxing the initial values like this? */
- wave_out->localvol = 0xffffffff;
- wave_out->localreverb = 0xffffffff;
- wave_out->localchorus = 0xffffffff;
- wave_out->globalvolFactor = 0xffff;
- wave_out->globalreverbFactor = 0xffff;
- wave_out->globalchorusFactor = 0xffff;
-
- wave_out->setpos = 0;
- wave_out->position = 0;
-
- wave_out->fill_silence = 0;
-
- if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) {
+ if (alloc_buffer(card, &woinst->buffer) < 0) {
ERROR();
emu10k1_waveout_close(wave_dev);
- return CTSTATUS_ERROR;
+ return -1;
}
- buffsize = woinst->fragment_size * woinst->numfrags;
+ woinst->buffer.fill_silence = 0;
+ woinst->buffer.silence_bytes = 0;
+ woinst->buffer.silence_pos = 0;
+ woinst->buffer.hw_pos = 0;
+ woinst->buffer.bytestocopy = woinst->buffer.size;
- if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) {
+ if (get_voice(card, woinst) < 0) {
ERROR();
emu10k1_waveout_close(wave_dev);
- return CTSTATUS_ERROR;
+ return -1;
}
- woinst->fragment_size = buffsize / woinst->numfrags;
- wave_out->callbacksize = woinst->fragment_size;
+ delay = (48000 * woinst->buffer.fragment_size) / woinst->format.bytespersec;
- if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
- ERROR();
- emu10k1_waveout_close(wave_dev);
- return CTSTATUS_ERROR;
- }
+ emu10k1_timer_install(card, &woinst->timer, delay / 2);
- bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
- delay = (48000 * wave_out->callbacksize) / bytespersec;
+ woinst->state = WAVE_STATE_OPEN;
- if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
- ERROR();
- emu10k1_waveout_close(wave_dev);
- return CTSTATUS_ERROR;
- }
-
- return CTSTATUS_SUCCESS;
+ return 0;
}
void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
- struct wave_out *wave_out = wave_dev->woinst->wave_out;
+ struct woinst *woinst = wave_dev->woinst;
DPF(2, "emu10k1_waveout_close()\n");
- if (wave_out->state != CARDWAVE_STATE_STOPPED)
- emu10k1_waveout_stop(wave_dev);
+ emu10k1_waveout_stop(wave_dev);
- if (wave_out->timer != NULL)
- emu10k1_timer_uninstall(card, wave_out->timer);
+ emu10k1_timer_uninstall(card, &woinst->timer);
- if (wave_out->voice != NULL)
- emu10k1_voice_free(&card->voicemgr, wave_out->voice);
+ emu10k1_voice_free(&woinst->voice);
- if (wave_out->emupageindex >= 0)
- dealloc_xferbuffer(card, wave_out);
+ free_buffer(card, &woinst->buffer);
- if (wave_out->wavexferbuf != NULL)
- kfree(wave_out->wavexferbuf);
-
- kfree(wave_out);
- wave_dev->woinst->wave_out = NULL;
+ woinst->state = WAVE_STATE_CLOSED;
return;
}
-int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
+void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
- struct wave_out *wave_out = wave_dev->woinst->wave_out;
- u32 start, startPosition;
+ struct woinst *woinst = wave_dev->woinst;
DPF(2, "emu10k1_waveout_start()\n");
-
- /* If already started, return success */
- if (wave_out->state == CARDWAVE_STATE_STARTED)
- return CTSTATUS_SUCCESS;
-
- if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos)
- startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample);
- else
- startPosition = wave_out->wavexferbuf->stopposition;
-
- start = wave_out->voice->params.start;
- wave_out->voice->params.start += startPosition;
-
- DPD(2, "CA is %x\n", wave_out->voice->params.start);
-
- emu10k1_voice_playback_setup(wave_out->voice);
-
- wave_out->voice->params.start = start;
-
/* Actual start */
- emu10k1_voice_start(wave_out->voice);
- wave_out->state = CARDWAVE_STATE_STARTED;
- wave_out->setpos = 0;
+ emu10k1_voice_start(&woinst->voice, woinst->total_played);
- emu10k1_timer_enable(card, wave_out->timer);
+ emu10k1_timer_enable(card, &woinst->timer);
- return CTSTATUS_SUCCESS;
+ woinst->state |= WAVE_STATE_STARTED;
+
+ return;
}
-int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev)
+int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
- struct wave_out *wave_out = woinst->wave_out;
- u32 bytespersec, delay;
+ u32 delay;
DPF(2, "emu10k1_waveout_setformat()\n");
- query_format(&woinst->wave_fmt);
+ if (woinst->state & WAVE_STATE_STARTED)
+ return -1;
- if (wave_out == NULL)
- return CTSTATUS_SUCCESS;
-
- if (wave_out->state == CARDWAVE_STATE_STARTED) {
- woinst->wave_fmt = wave_out->wave_fmt;
- return CTSTATUS_SUCCESS;
- }
+ query_format(format);
- if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate)
- || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel)
- || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) {
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+ if (woinst->format.samplingrate != format->samplingrate ||
+ woinst->format.channels != format->channels ||
+ woinst->format.bitsperchannel != format->bitsperchannel) {
- emu10k1_timer_uninstall(card, wave_out->timer);
+ woinst->format = *format;
- emu10k1_voice_free(&card->voicemgr, wave_out->voice);
+ if (woinst->state == WAVE_STATE_CLOSED)
+ return 0;
- wave_out->wave_fmt = woinst->wave_fmt;
- wave_out->timer = NULL;
+ emu10k1_timer_uninstall(card, &woinst->timer);
+ emu10k1_voice_free(&woinst->voice);
- wavexferbuf->xferpos = 0;
- wavexferbuf->silence_xferpos = 0;
- wavexferbuf->stopposition = 0;
- wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
- wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
- wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
-
- if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
+ if (get_voice(card, woinst) < 0) {
ERROR();
emu10k1_waveout_close(wave_dev);
- return CTSTATUS_ERROR;
+ return -1;
}
- bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
- delay = (48000 * wave_out->callbacksize) / bytespersec;
+ delay = (48000 * woinst->buffer.fragment_size) / woinst->format.bytespersec;
- if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
- ERROR();
- emu10k1_waveout_close(wave_dev);
- return CTSTATUS_ERROR;
- }
+ emu10k1_timer_install(card, &woinst->timer, delay / 2);
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
- struct wave_out *wave_out = wave_dev->woinst->wave_out;
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
- u32 samples = 32;
- u32 position;
+ struct woinst *woinst = wave_dev->woinst;
DPF(2, "emu10k1_waveout_stop()\n");
- if (wave_out->state == CARDWAVE_STATE_STOPPED)
+ if (!(woinst->state & WAVE_STATE_STARTED))
return;
- emu10k1_timer_disable(card, wave_out->timer);
+ emu10k1_timer_disable(card, &woinst->timer);
/* Stop actual voice */
- emu10k1_voice_stop(wave_out->voice);
-
- /* Save the stop position */
- emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition);
-
- wavexferbuf->stopposition -= wave_out->voice->params.start;
-
- /* Refer to voicemgr.c, CA is not started at zero. We need to take this into account. */
- position = wavexferbuf->stopposition * wavexferbuf->bytespersample;
+ emu10k1_voice_stop(&woinst->voice);
- if (!wavexferbuf->is_16bit)
- samples <<= 1;
+ emu10k1_waveout_update(woinst);
- if (wavexferbuf->is_stereo)
- samples <<= 1;
-
- samples -= 4;
-
- if (position >= samples * (wavexferbuf->is_16bit + 1))
- position -= samples * (wavexferbuf->is_16bit + 1);
- else
- position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1);
-
- wavexferbuf->stopposition = position / wavexferbuf->bytespersample;
-
- DPD(2, "position is %x\n", wavexferbuf->stopposition);
-
- wave_out->state = CARDWAVE_STATE_STOPPED;
- wave_out->setpos = 0;
- wave_out->position = 0;
+ woinst->state &= ~WAVE_STATE_STARTED;
return;
}
-void emu10k1_waveout_getxfersize(struct wave_out *wave_out, u32 * size, u32 * pending, u32 * curpos)
+void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 * size)
{
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
-
- /* Get position of current address, this is in no. of bytes in play buffer */
- emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, curpos);
-
- if ((*curpos > wavexferbuf->silence_xferpos)
- || ((*curpos == wavexferbuf->silence_xferpos)
- && (wave_out->state == CARDWAVE_STATE_STARTED))
- || ((*curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0)
- && (wave_out->state == CARDWAVE_STATE_STOPPED))) {
- *size = *curpos - wavexferbuf->silence_xferpos;
- *pending = wavexferbuf->xferbufsize - *size;
- } else {
- *pending = wavexferbuf->silence_xferpos - *curpos;
- *size = wavexferbuf->xferbufsize - *pending;
+ struct waveout_buffer *buffer = &woinst->buffer;
+ int pending;
+
+ if (woinst->mmapped) {
+ *size = buffer->bytestocopy;
+ return;
}
- if (wavexferbuf->silence_xferpos != wavexferbuf->xferpos) {
- if (*pending < wave_out->callbacksize) {
- wave_out->fill_silence = 2;
- *pending = 0;
- *size = wavexferbuf->xferbufsize;
- wavexferbuf->xferpos = *curpos;
- } else {
- if (wave_out->fill_silence == 2) {
- *pending = 0;
- *size = wavexferbuf->xferbufsize;
- wavexferbuf->xferpos = *curpos;
- } else {
- *pending -= wave_out->callbacksize;
- *size += wave_out->callbacksize;
- }
- }
+ pending = buffer->size - buffer->bytestocopy;
+
+ buffer->fill_silence = (pending < (signed) buffer->fragment_size) ? 1 : 0;
+
+ if (pending > (signed) buffer->silence_bytes) {
+ *size = buffer->bytestocopy + buffer->silence_bytes;
} else {
- if (*pending < wave_out->callbacksize)
- wave_out->fill_silence = 1;
- else
- wave_out->fill_silence = 0;
+ *size = buffer->size;
+ buffer->silence_bytes = pending;
+ if (pending < 0) {
+ buffer->silence_pos = buffer->hw_pos;
+ buffer->silence_bytes = 0;
+ buffer->bytestocopy = buffer->size;
+ DPF(1, "buffer underrun\n");
+ }
}
return;
}
-static void copy_block(u32 dst, u8 * src, u32 len, void **pt)
+static void copy_block(void **dst, u32 str, u8 *src, u32 len)
{
int i, j, k;
- i = dst / PAGE_SIZE;
- j = dst % PAGE_SIZE;
- k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
- copy_from_user(pt[i] + j, src, k);
- len -= k;
- while (len >= PAGE_SIZE) {
- copy_from_user(pt[++i], src + k, PAGE_SIZE);
- k += PAGE_SIZE;
- len -= PAGE_SIZE;
- }
- copy_from_user(pt[++i], src + k, len);
+ i = str / PAGE_SIZE;
+ j = str % PAGE_SIZE;
+
+ if (len > PAGE_SIZE - j) {
+ k = PAGE_SIZE - j;
+ copy_from_user(dst[i] + j, src, k);
+ len -= k;
+ while (len > PAGE_SIZE) {
+ copy_from_user(dst[++i], src + k, PAGE_SIZE);
+ k += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ }
+ copy_from_user(dst[++i], src + k, len);
+
+ } else
+ copy_from_user(dst[i] + j, src, len);
return;
}
-static void fill_block(u32 dst, u8 val, u32 len, void **pt)
+static void fill_block(void **dst, u32 str, u8 src, u32 len)
{
int i, j, k;
- i = dst / PAGE_SIZE;
- j = dst % PAGE_SIZE;
- k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
- memset(pt[i] + j, val, k);
- len -= k;
- while (len >= PAGE_SIZE) {
- memset(pt[++i], val, PAGE_SIZE);
- len -= PAGE_SIZE;
- }
- memset(pt[++i], val, len);
+ i = str / PAGE_SIZE;
+ j = str % PAGE_SIZE;
+
+ if (len > PAGE_SIZE - j) {
+ k = PAGE_SIZE - j;
+ memset(dst[i] + j, src, k);
+ len -= k;
+ while (len > PAGE_SIZE) {
+ memset(dst[++i], src, PAGE_SIZE);
+ len -= PAGE_SIZE;
+ }
+ memset(dst[++i], src, len);
+
+ } else
+ memset(dst[i] + j, src, len);
return;
}
-void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size)
+void emu10k1_waveout_xferdata(struct woinst *woinst, u8 *data, u32 *size)
{
- struct wave_out *wave_out = woinst->wave_out;
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+ struct waveout_buffer *buffer = &woinst->buffer;
u32 sizetocopy, sizetocopy_now, start;
unsigned long flags;
- sizetocopy = min(wavexferbuf->xferbufsize, *size);
+ sizetocopy = min(buffer->size, *size);
*size = sizetocopy;
if (!sizetocopy)
return;
spin_lock_irqsave(&woinst->lock, flags);
+ start = (buffer->size + buffer->silence_pos - buffer->silence_bytes) % buffer->size;
- sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos;
+ if(sizetocopy > buffer->silence_bytes) {
+ buffer->silence_pos += sizetocopy - buffer->silence_bytes;
+ buffer->bytestocopy -= sizetocopy - buffer->silence_bytes;
+ buffer->silence_bytes = 0;
+ } else
+ buffer->silence_bytes -= sizetocopy;
- start = wavexferbuf->xferpos;
+ sizetocopy_now = buffer->size - start;
+
+ spin_unlock_irqrestore(&woinst->lock, flags);
if (sizetocopy > sizetocopy_now) {
sizetocopy -= sizetocopy_now;
- wavexferbuf->xferpos = sizetocopy;
- wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer);
- copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer);
+ copy_block(buffer->addr, start, data, sizetocopy_now);
+ copy_block(buffer->addr, 0, data + sizetocopy_now, sizetocopy);
} else {
- if (sizetocopy == sizetocopy_now)
- wavexferbuf->xferpos = 0;
- else
- wavexferbuf->xferpos += sizetocopy;
-
- wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer);
+ copy_block(buffer->addr, start, data, sizetocopy);
}
return;
void emu10k1_waveout_fillsilence(struct woinst *woinst)
{
- struct wave_out *wave_out = woinst->wave_out;
- struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+ struct waveout_buffer *buffer = &woinst->buffer;
u16 filldata;
u32 sizetocopy, sizetocopy_now, start;
unsigned long flags;
- sizetocopy = wave_out->callbacksize;
+ sizetocopy = woinst->buffer.fragment_size;
- if (wave_out->wave_fmt.bitsperchannel == 8)
- filldata = 0x8080;
- else
+ if (woinst->format.bitsperchannel == 16)
filldata = 0x0000;
+ else
+ filldata = 0x8080;
spin_lock_irqsave(&woinst->lock, flags);
+ buffer->silence_bytes += sizetocopy;
+ buffer->bytestocopy -= sizetocopy;
+ buffer->silence_pos %= buffer->size;
+ start = buffer->silence_pos;
+ buffer->silence_pos += sizetocopy;
+ sizetocopy_now = buffer->size - start;
- sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos;
- start = wavexferbuf->silence_xferpos;
+ spin_unlock_irqrestore(&woinst->lock, flags);
if (sizetocopy > sizetocopy_now) {
sizetocopy -= sizetocopy_now;
- wavexferbuf->silence_xferpos = sizetocopy;
- spin_unlock_irqrestore(&woinst->lock, flags);
- fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer);
- fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer);
+ fill_block(buffer->addr, start, filldata, sizetocopy_now);
+ fill_block(buffer->addr, 0, filldata, sizetocopy);
} else {
- if (sizetocopy == sizetocopy_now)
- wavexferbuf->silence_xferpos = 0;
- else
- wavexferbuf->silence_xferpos += sizetocopy;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer);
+ fill_block(buffer->addr, start, filldata, sizetocopy);
}
return;
}
-/* get the specified control value of the wave device. */
-
-int emu10k1_waveout_getcontrol(struct wave_out *wave_out, u32 ctrl_id, u32 * value)
+void emu10k1_waveout_update(struct woinst *woinst)
{
- switch (ctrl_id) {
- case WAVECURPOS:
- /* There is no actual start yet */
- if (wave_out->state == CARDWAVE_STATE_STOPPED) {
- if (wave_out->setpos)
- *value = wave_out->position;
- else
- *value = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample;
- } else {
- emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, value);
-
- *value -= wave_out->voice->params.start;
-
- /* Get number of bytes in play buffer per channel.
- * If 8 bit mode is enabled, this needs to be changed. */
- {
- u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1);
-
- *value *= wave_out->wavexferbuf->bytespersample;
-
- /* Refer to voicemgr.c, CA is not started at zero.
- * We need to take this into account. */
-
- samples -= 4 * (wave_out->wavexferbuf->is_16bit + 1);
-
- if (*value >= samples)
- *value -= samples;
- else
- *value += wave_out->wavexferbuf->xferbufsize - samples;
- }
- }
+ u32 hw_pos;
+ u32 diff;
+
+ /* There is no actual start yet */
+ if (!(woinst->state & WAVE_STATE_STARTED)) {
+ hw_pos = woinst->buffer.hw_pos;
+ } else {
+ /* hw_pos in sample units */
+ hw_pos = sblive_readptr(woinst->voice.card, CCCA_CURRADDR, woinst->voice.num);
- break;
- default:
- return CTSTATUS_ERROR;
+ if(hw_pos < woinst->voice.start)
+ hw_pos += woinst->buffer.size / woinst->format.bytespersample - woinst->voice.start;
+ else
+ hw_pos -= woinst->voice.start;
+
+ hw_pos *= woinst->format.bytespersample;
}
- return CTSTATUS_SUCCESS;
+ diff = (woinst->buffer.size + hw_pos - woinst->buffer.hw_pos) % woinst->buffer.size;
+ woinst->total_played += diff;
+ woinst->buffer.bytestocopy += diff;
+ woinst->buffer.hw_pos = hw_pos;
+
+ return;
}
#define _CARDWO_H
#include "icardwav.h"
+#include "audio.h"
+#include "voicemgr.h"
+#include "timer.h"
-struct wave_xferbuf
-{
- u32 xferpos;
- u32 silence_xferpos;
- u32 xferbufsize; /* transfer buffer size */
- u32 numpages; /* number of pages in transfer buffer */
- void **xferbuffer; /* pointer to the transfer buffer */
- int is_stereo;
- int is_16bit;
- int bytespersample;
- u32 stopposition;
-};
-
-struct wave_out
-{
- u32 state;
- struct emu_voice *voice;
- int emupageindex;
- struct emu_timer *timer;
- struct wave_xferbuf *wavexferbuf;
- void **pagetable;
- u32 callbacksize;
- u32 localvol;
- u32 localreverb;
- u32 localchorus;
- u32 globalvolFactor;
- u32 globalreverbFactor;
- u32 globalchorusFactor;
- int setpos;
- u32 position;
- struct wave_format wave_fmt;
- int fill_silence;
-};
+/* setting this to other than a power of two may break some applications */
+#define WAVEOUT_MAXBUFSIZE MAXBUFSIZE
+#define WAVEOUT_MINBUFSIZE 64
-/* setting this to other than a power of two
- may break some applications */
-#define WAVEOUT_MAXBUFSIZE 32768
-#define WAVEOUT_MINBUFSIZE 64
+#define WAVEOUT_DEFAULTFRAGLEN 20 /* Time to play a fragment in ms (latency) */
+#define WAVEOUT_DEFAULTBUFLEN 500 /* Time to play the entire buffer in ms */
-#define WAVEOUT_DEFAULTFRAGLEN 100 /* Time to play a fragment in ms (latency) */
-#define WAVEOUT_DEFAULTBUFLEN 1000 /* Time to play the entire buffer in ms */
+#define WAVEOUT_MINFRAGSHIFT 6
-#define WAVEOUT_MINFRAGSHIFT 4
+struct waveout_buffer {
+ u16 ossfragshift;
+ u32 numfrags;
+ u32 fragment_size; /* in bytes units */
+ u32 size; /* in bytes units */
+ u32 pages; /* buffer size in page units*/
+ int emupageindex;
+ void *addr[BUFMAXPAGES];
+ dma_addr_t dma_handle[BUFMAXPAGES];
+ u32 silence_pos; /* software cursor position (including silence) */
+ u32 hw_pos; /* hardware cursor position */
+ u32 bytestocopy; /* free space on buffer (including silence) */
+ u8 fill_silence;
+ u32 silence_bytes; /* silence bytes in buffer */
+};
struct woinst
{
- struct wave_out *wave_out;
- struct wave_format wave_fmt;
- u16 ossfragshift;
- u32 fragment_size;
- u32 numfrags;
+ u8 state;
+ struct emu_voice voice;
+ struct emu_timer timer;
+ struct wave_format format;
+ struct waveout_buffer buffer;
wait_queue_head_t wait_queue;
- int mapped;
- u32 total_copied;
- u32 total_played;
+ u8 mmapped;
+ u32 total_copied; /* total number of bytes written() to the buffer (excluding silence) */
+ u32 total_played; /* total number of bytes played including silence */
u32 blocks;
- u32 curpos;
- u32 device;
+ u8 device;
spinlock_t lock;
};
-struct emu10k1_waveout
-{
- u32 globalvol;
- u32 mute;
- u32 left;
- u32 right;
- u32 globalreverb;
- u32 globalchorus;
-};
-
int emu10k1_waveout_open(struct emu10k1_wavedevice *);
void emu10k1_waveout_close(struct emu10k1_wavedevice *);
-int emu10k1_waveout_start(struct emu10k1_wavedevice *);
+void emu10k1_waveout_start(struct emu10k1_wavedevice *);
void emu10k1_waveout_stop(struct emu10k1_wavedevice *);
-void emu10k1_waveout_getxfersize(struct wave_out *, u32 *, u32 *, u32 *);
+void emu10k1_waveout_getxfersize(struct woinst*, u32 *);
void emu10k1_waveout_xferdata(struct woinst*, u8*, u32 *);
void emu10k1_waveout_fillsilence(struct woinst*);
-int emu10k1_waveout_setformat(struct emu10k1_wavedevice*);
-int emu10k1_waveout_getcontrol(struct wave_out*, u32, u32 *);
+int emu10k1_waveout_setformat(struct emu10k1_wavedevice*, struct wave_format*);
+void emu10k1_waveout_update(struct woinst*);
#endif /* _CARDWO_H */
--- /dev/null
+/*
+ **********************************************************************
+ * ecard.c - E-card initialization code
+ * Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ * Date Author Summary of changes
+ * ---- ------ ------------------
+ * October 20, 1999 Bertrand Lee base code release
+ *
+ **********************************************************************
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ **********************************************************************
+ */
+
+#include "ecard.h"
+#include "hwaccess.h"
+
+/* Private routines */
+static void ecard_setadcgain(struct emu10k1_card *, struct ecard_state *, u16);
+static void ecard_write(struct emu10k1_card *, u32);
+
+/**************************************************************************
+ * @func Set the gain of the ECARD's CS3310 Trim/gain controller. The
+ * trim value consists of a 16bit value which is composed of two
+ * 8 bit gain/trim values, one for the left channel and one for the
+ * right channel. The following table maps from the Gain/Attenuation
+ * value in decibels into the corresponding bit pattern for a single
+ * channel.
+ */
+
+static void ecard_setadcgain(struct emu10k1_card *card, struct ecard_state *ecard, u16 gain)
+{
+ u32 currbit;
+ ecard->adc_gain = gain;
+
+ /* Enable writing to the TRIM registers */
+ ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
+
+ /* Do it again to insure that we meet hold time requirements */
+ ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
+
+ for (currbit = (1L << 15); currbit; currbit >>= 1) {
+
+ u32 value = ecard->control_bits & ~(EC_TRIM_CSN|EC_TRIM_SDATA);
+
+ if (gain & currbit)
+ value |= EC_TRIM_SDATA;
+
+ /* Clock the bit */
+ ecard_write(card, value);
+ ecard_write(card, value | EC_TRIM_SCLK);
+ ecard_write(card, value);
+ }
+
+ ecard_write(card, ecard->control_bits);
+}
+
+/**************************************************************************
+ * @func Clock bits into the Ecard's control latch. The Ecard uses a
+ * control latch will is loaded bit-serially by toggling the Modem control
+ * lines from function 2 on the E8010. This function hides these details
+ * and presents the illusion that we are actually writing to a distinct
+ * register.
+ */
+static void ecard_write(struct emu10k1_card *card, u32 value)
+{
+ u16 count;
+ u32 data, hcvalue;
+
+ hcvalue = emu10k1_readfn0(card, HCFG) & ~(HOOKN_BIT|HANDN_BIT|PULSEN_BIT);
+
+ emu10k1_writefn0(card, HCFG, hcvalue);
+
+ for (count = 0 ; count < EC_NUM_CONTROL_BITS; count++) {
+
+ /* Set up the value */
+ data = ((value & 0x1) ? PULSEN_BIT : 0);
+ value >>= 1;
+
+ emu10k1_writefn0(card, HCFG, hcvalue | data);
+
+ /* Clock the shift register */
+ emu10k1_writefn0(card, HCFG, hcvalue | data | HANDN_BIT);
+ emu10k1_writefn0(card, HCFG, hcvalue | data);
+ }
+
+ /* Latch the bits */
+ emu10k1_writefn0(card, HCFG, hcvalue | HOOKN_BIT);
+ emu10k1_writefn0(card, HCFG, hcvalue);
+}
+
+int __devinit emu10k1_ecard_init(struct emu10k1_card *card)
+{
+ u32 hcvalue;
+ struct ecard_state ecard;
+
+ /* Set up the initial settings */
+ ecard.mux0_setting = EC_DEFAULT_SPDIF0_SEL;
+ ecard.mux1_setting = EC_DEFAULT_SPDIF1_SEL;
+ ecard.mux2_setting = 0;
+ ecard.adc_gain = EC_DEFAULT_ADC_GAIN;
+ ecard.control_bits = EC_RAW_RUN_MODE |
+ EC_SPDIF0_SELECT(ecard.mux0_setting) |
+ EC_SPDIF1_SELECT(ecard.mux1_setting);
+
+
+ /* Step 0: Set the codec type in the hardware control register
+ * and enable audio output */
+ hcvalue = emu10k1_readfn0(card, HCFG);
+ emu10k1_writefn0(card, HCFG, hcvalue | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S);
+ emu10k1_readfn0(card, HCFG);
+
+ /* Step 1: Turn off the led and deassert TRIM_CS */
+ ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
+
+ /* Step 2: Calibrate the ADC and DAC */
+ ecard_write(card, EC_DACCAL | EC_LEDN | EC_TRIM_CSN);
+
+ /* Step 3: Wait for awhile; FIXME: Is this correct? */
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ);
+
+ /* Step 4: Switch off the DAC and ADC calibration. Note
+ * That ADC_CAL is actually an inverted signal, so we assert
+ * it here to stop calibration. */
+ ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
+
+ /* Step 4: Switch into run mode */
+ ecard_write(card, ecard.control_bits);
+
+ /* Step 5: Set the analog input gain */
+ ecard_setadcgain(card, &ecard, ecard.adc_gain);
+
+ return 0;
+}
+
+
--- /dev/null
+/*
+ **********************************************************************
+ * ecard.h
+ * Copyright 1999, 2000 Creative Labs, Inc.
+ *
+ **********************************************************************
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ **********************************************************************
+ */
+
+#ifndef _ECARD_H
+#define _ECARD_H
+
+#include "8010.h"
+#include "hwaccess.h"
+#include <linux/init.h>
+
+/* In A1 Silicon, these bits are in the HC register */
+#define HOOKN_BIT (1L << 12)
+#define HANDN_BIT (1L << 11)
+#define PULSEN_BIT (1L << 10)
+
+#define EC_GDI1 (1 << 13)
+#define EC_GDI0 (1 << 14)
+
+#define EC_NUM_CONTROL_BITS 20
+
+#define EC_AC3_DATA_SELN 0x0001L
+#define EC_EE_DATA_SEL 0x0002L
+#define EC_EE_CNTRL_SELN 0x0004L
+#define EC_EECLK 0x0008L
+#define EC_EECS 0x0010L
+#define EC_EESDO 0x0020L
+#define EC_TRIM_CSN 0x0040L
+#define EC_TRIM_SCLK 0x0080L
+#define EC_TRIM_SDATA 0x0100L
+#define EC_TRIM_MUTEN 0x0200L
+#define EC_ADCCAL 0x0400L
+#define EC_ADCRSTN 0x0800L
+#define EC_DACCAL 0x1000L
+#define EC_DACMUTEN 0x2000L
+#define EC_LEDN 0x4000L
+
+#define EC_SPDIF0_SEL_SHIFT 15
+#define EC_SPDIF1_SEL_SHIFT 17
+#define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT)
+#define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT)
+#define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK)
+#define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK)
+#define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should
+ * be incremented any time the EEPROM's
+ * format is changed. */
+
+#define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */
+
+/* Addresses for special values stored in to EEPROM */
+#define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */
+#define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */
+#define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */
+
+#define EC_LAST_PROMFILE_ADDR 0x2f
+
+#define EC_SERIALNUM_ADD 0x30 /* First word of serial number. The number
+ * can be up to 30 characters in length
+ * and is stored as a NULL-terminated
+ * ASCII string. Any unused bytes must be
+ * filled with zeros */
+#define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */
+
+
+
+/* Most of this stuff is pretty self-evident. According to the hardware
+ * dudes, we need to leave the ADCCAL bit low in order to avoid a DC
+ * offset problem. Weird.
+ */
+#define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | EC_TRIM_CSN)
+
+
+#define EC_DEFAULT_ADC_GAIN 0xC4C4
+#define EC_DEFAULT_SPDIF0_SEL 0x0
+#define EC_DEFAULT_SPDIF1_SEL 0x4
+
+#define HC_EA 0x01L
+
+/* ECARD state structure. This structure maintains the state
+ * for various portions of the the ECARD's onboard hardware.
+ */
+struct ecard_state {
+ u32 control_bits;
+ u16 adc_gain;
+ u16 mux0_setting;
+ u16 mux1_setting;
+ u16 mux2_setting;
+};
+
+int emu10k1_ecard_init(struct emu10k1_card *) __devinit;
+
+#endif /* _ECARD_H */
+++ /dev/null
-
-/*
- **********************************************************************
- * sblive_fx.c
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-#include "hwaccess.h"
-#include "efxmgr.h"
#include <linux/wrapper.h>
-#define UP_INODE_SEM(a)
-#define DOWN_INODE_SEM(a)
+#define PCI_SET_DMA_MASK(pdev,mask) (((pdev)->dma_mask) = (mask))
-#define GET_INODE_STRUCT()
+#ifndef PCI_GET_DRIVER_DATA
+ #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data)
+ #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data))
+#endif /* PCI_GET_DRIVER_DATA */
#endif
/* Convert bytes to pages */
numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0);
- while (index < (MAXPAGES - RESERVED - 1)) {
+ spin_lock_irqsave(&card->lock, flags);
+
+ while (index < (MAXPAGES - 1)) {
if (pagetable[index] & 0x8000) {
/* This block of pages is in use, jump to the start of the next block. */
index += (pagetable[index] & 0x7fff);
} else {
/* Found free block */
if (pagetable[index] >= numpages) {
- spin_lock_irqsave(&card->lock, flags);
/* Block is large enough */
}
}
+ spin_unlock_irqrestore(&card->lock, flags);
+
return -1;
}
-
/*
**********************************************************************
* hwaccess.c -- Hardware access layer
**********************************************************************
*/
+#include <asm/io.h>
+
#include "hwaccess.h"
+#include "8010.h"
#include "icardmid.h"
/*************************************************************************
};
if (sampleRate == 0)
- return (0); /* Bail out if no leading "1" */
+ return 0; /* Bail out if no leading "1" */
sampleRate *= 11185; /* Scale 48000 to 0x20002380 */
/*******************************************
* write/read PCI function 0 registers *
********************************************/
-void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data)
+void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data)
{
unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- outl(data, card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return;
-}
-
-void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data)
-{
- unsigned long flags;
+ if (reg & 0xff000000) {
+ u32 mask;
+ u8 size, offset;
- data &= mask;
+ size = (reg >> 24) & 0x3f;
+ offset = (reg >> 16) & 0x1f;
+ mask = ((1 << size) - 1) << offset;
+ data = (data << offset) & mask;
+ reg &= 0x7f;
- spin_lock_irqsave(&card->lock, flags);
- data |= inl(card->iobase + reg) & ~mask;
- outl(data, card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
+ data |= inl(card->iobase + reg) & ~mask;
+ outl(data, card->iobase + reg);
+ spin_unlock_irqrestore(&card->lock, flags);
+ } else {
+ spin_lock_irqsave(&card->lock, flags);
+ outl(data, card->iobase + reg);
+ spin_unlock_irqrestore(&card->lock, flags);
+ }
return;
}
-u32 sblive_readfn0(struct emu10k1_card * card, u8 reg)
+u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
{
u32 val;
unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- val = inl(card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
- return val;
-}
+ if (reg & 0xff000000) {
+ u32 mask;
+ u8 size, offset;
-u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask)
-{
- u32 val;
- unsigned long flags;
+ size = (reg >> 24) & 0x3f;
+ offset = (reg >> 16) & 0x1f;
+ mask = ((1 << size) - 1) << offset;
+ reg &= 0x7f;
- spin_lock_irqsave(&card->lock, flags);
- val = inl(card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
- return val & mask;
+ spin_lock_irqsave(&card->lock, flags);
+ val = inl(card->iobase + reg);
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ return (val & mask) >> offset;
+ } else {
+ spin_lock_irqsave(&card->lock, flags);
+ val = inl(card->iobase + reg);
+ spin_unlock_irqrestore(&card->lock, flags);
+ return val;
+ }
}
/************************************************************************
outl(data, card->iobase + DATA);
spin_unlock_irqrestore(&card->lock, flags);
}
+}
+
+/* ... : data, reg, ... , TAGLIST_END */
+void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
+{
+ va_list args;
+
+ unsigned long flags;
+ u32 reg;
+
+ va_start(args, channel);
+
+ spin_lock_irqsave(&card->lock, flags);
+ while ((reg = va_arg(args, u32)) != TAGLIST_END) {
+ u32 data = va_arg(args, u32);
+ u32 regptr = (((reg << 16) & PTR_ADDRESS_MASK)
+ | (channel & PTR_CHANNELNUM_MASK));
+ outl(regptr, card->iobase + PTR);
+ if (reg & 0xff000000) {
+ int size = (reg >> 24) & 0x3f;
+ int offset = (reg >> 16) & 0x1f;
+ u32 mask = ((1 << size) - 1) << offset;
+ data = (data << offset) & mask;
+
+ data |= inl(card->iobase + DATA) & ~mask;
+ }
+ outl(data, card->iobase + DATA);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ va_end(args);
return;
}
}
}
+void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask)
+{
+ u32 val;
+ unsigned long flags;
+
+ DPF(2,"emu10k1_irq_enable()\n");
+
+ spin_lock_irqsave(&card->lock, flags);
+ val = inl(card->iobase + INTE) | irq_mask;
+ outl(val, card->iobase + INTE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ return;
+}
+
+void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask)
+{
+ u32 val;
+ unsigned long flags;
+
+ DPF(2,"emu10k1_irq_disable()\n");
+
+ spin_lock_irqsave(&card->lock, flags);
+ val = inl(card->iobase + INTE) & ~irq_mask;
+ outl(val, card->iobase + INTE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ return;
+}
+
void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
{
/* Voice interrupt */
volatile unsigned uCount;
u32 newtime = 0, curtime;
- curtime = READ_FN0(card, WC_SAMPLECOUNTER);
+ curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
while (wait--) {
uCount = 0;
while (uCount++ < TIMEOUT) {
- newtime = READ_FN0(card, WC_SAMPLECOUNTER);
+ newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
if (newtime != curtime)
break;
}
spin_lock_irqsave(&card->lock, flags);
- outb(index, card->mixeraddx + 2);
- *data = inw(card->mixeraddx);
+ outb(index, card->iobase + AC97ADDRESS);
+ *data = inw(card->iobase + AC97DATA);
spin_unlock_irqrestore(&card->lock, flags);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data)
spin_lock_irqsave(&card->lock, flags);
- outb(index, card->mixeraddx + 2);
- outw(data, card->mixeraddx);
+ outb(index, card->iobase + AC97ADDRESS);
+ outw(data, card->iobase + AC97DATA);
spin_unlock_irqrestore(&card->lock, flags);
- return CTSTATUS_SUCCESS;
+ return 0;
}
int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask)
spin_lock_irqsave(&card->lock, flags);
- outb(index, card->mixeraddx + 2);
- temp = inw(card->mixeraddx);
+ outb(index, card->iobase + AC97ADDRESS);
+ temp = inw(card->iobase + AC97DATA);
temp &= ~mask;
data &= mask;
temp |= data;
- outw(temp, card->mixeraddx);
+ outw(temp, card->iobase + AC97DATA);
spin_unlock_irqrestore(&card->lock, flags);
- return CTSTATUS_SUCCESS;
+ return 0;
}
/*********************************************************
if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
outb(data, card->iobase + MUDATA);
- ret = CTSTATUS_SUCCESS;
+ ret = 0;
} else
- ret = CTSTATUS_BUSY;
+ ret = -1;
spin_unlock_irqrestore(&card->lock, flags);
if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
*data = inb(card->iobase + MUDATA);
- ret = CTSTATUS_SUCCESS;
+ ret = 0;
} else
- ret = CTSTATUS_NODATA;
+ ret = -1;
spin_unlock_irqrestore(&card->lock, flags);
spin_unlock_irqrestore(&card->lock, flags);
if (status == 0xfe)
- return CTSTATUS_SUCCESS;
+ return 0;
else
- return CTSTATUS_ERROR;
+ return -1;
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
int emu10k1_mpu_acquire(struct emu10k1_card *card)
/* FIXME: This should be a macro */
++card->mpuacqcount;
- return CTSTATUS_SUCCESS;
+ return 0;
}
int emu10k1_mpu_release(struct emu10k1_card *card)
/* FIXME: this should be a macro */
--card->mpuacqcount;
- return CTSTATUS_SUCCESS;
+ return 0;
}
#ifndef _HWACCESS_H
#define _HWACCESS_H
-#include <linux/version.h>
-#include <linux/kernel.h>
#include <linux/fs.h>
-#include <linux/ioport.h>
#include <linux/sound.h>
-#include <linux/malloc.h>
#include <linux/soundcard.h>
#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-#include <asm/dma.h>
+#include "emu_wrapper.h"
-#include <emu_wrapper.h>
-
-enum GlobalErrorCode
-{
- CTSTATUS_SUCCESS = 0x0000,
- CTSTATUS_ERROR,
- CTSTATUS_NOMEMORY,
- CTSTATUS_INUSE,
-};
+#define EMUPAGESIZE 4096 /* don't change */
+#define NUM_G 64 /* use all channels */
+#define NUM_FXSENDS 4 /* don't change */
+/* setting this to other than a power of two may break some applications */
+#define MAXBUFSIZE 65536
+#define MAXPAGES 8192
+#define BUFMAXPAGES (MAXBUFSIZE / PAGE_SIZE)
#define FLAGS_AVAILABLE 0x0001
#define FLAGS_READY 0x0002
struct memhandle
{
- unsigned long busaddx;
- void *virtaddx;
- u32 order;
+ dma_addr_t dma_handle;
+ void *addr;
+ u32 size;
};
-struct memhandle *emu10k1_alloc_memphysical(u32);
-void emu10k1_free_memphysical(struct memhandle *);
-
#define DEBUG_LEVEL 2
#ifdef EMU10K1_DEBUG
# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0)
# define DPF(level,x) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0)
-#define ERROR() DPF(1,"error\n");
#else
-# define DPD(level,x,y...) /* not debugging: nothing */
-# define DPF(level,x)
-#define ERROR()
+# define DPD(level,x,y...) do { } while (0) /* not debugging: nothing */
+# define DPF(level,x) do { } while (0)
#endif /* EMU10K1_DEBUG */
-#include "8010.h"
-#include "voicemgr.h"
+#define ERROR() DPF(1,"error\n")
-int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
-void emu10k1_addxmgr_free(struct emu10k1_card *, int);
+/* DATA STRUCTURES */
-#include "timer.h"
-#include "irqmgr.h"
+struct emu10k1_waveout
+{
+ u16 send_routing[3];
+
+ u8 send_a[3];
+ u8 send_b[3];
+ u8 send_c[3];
+ u8 send_d[3];
+};
+
+struct emu10k1_wavein
+{
+ struct wiinst *ac97;
+ struct wiinst *mic;
+ struct wiinst *fx;
+
+ u8 recsrc;
+ u32 fxwc;
+};
-/* DATA STRUCTURES */
struct emu10k1_card
{
struct list_head list;
- struct memhandle *virtualpagetable;
-
- struct memhandle *tankmem;
- u32 tmemsize;
- struct memhandle *silentpage;
+ struct memhandle virtualpagetable;
+ struct memhandle tankmem;
+ struct memhandle silentpage;
spinlock_t lock;
- struct voice_manager voicemgr;
+ u8 voicetable[NUM_G];
u16 emupagetable[MAXPAGES];
struct list_head timers;
struct pci_dev *pci_dev;
unsigned long iobase;
- unsigned long mixeraddx;
- u32 irq;
+ unsigned long length;
+ unsigned short model;
+ unsigned int irq;
- unsigned long audio1_num;
- unsigned long audio2_num;
- unsigned long mixer_num;
- unsigned long midi_num;
+ int audio_num;
+ int audio1_num;
+ int mixer_num;
+ int midi_num;
- struct emu10k1_waveout *waveout;
- struct emu10k1_wavein *wavein;
+ struct emu10k1_waveout waveout;
+ struct emu10k1_wavein wavein;
struct emu10k1_mpuout *mpuout;
struct emu10k1_mpuin *mpuin;
u16 arrwVol[SOUND_MIXER_NRDEVICES + 1];
/* array is used from the member 1 to save (-1) operation */
- u32 digmix[96];
+ u32 digmix[9 * 6 * 2];
unsigned int modcnt;
struct semaphore open_sem;
mode_t open_mode;
u32 has_toslink; // TOSLink detection
u8 chiprev; /* Chip revision */
+
+ int isaps;
};
+int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
+void emu10k1_addxmgr_free(struct emu10k1_card *, int);
+
#ifdef PRIVATE_PCM_VOLUME
#define MAX_PCM_CHANNELS NUM_G
int opened; // counter - locks element
};
extern struct sblive_pcm_volume_rec sblive_pcm_volume[];
-
+extern u16 pcm_last_mixer;
#endif
-
-#define ENABLE 0xffffffff
-#define DISABLE 0x00000000
-
-#define ENV_ON 0x80
-#define ENV_OFF 0x00
-
#define TIMEOUT 16384
u32 srToPitch(u32);
/* Hardware Abstraction Layer access functions */
-#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f))
-
-#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f)
-
-void sblive_writefn0(struct emu10k1_card *, u8 , u32 );
-void sblive_wrtmskfn0(struct emu10k1_card *, u8 , u32 , u32 );
-
-u32 sblive_readfn0(struct emu10k1_card *, u8 );
-u32 sblive_rdmskfn0(struct emu10k1_card *, u8, u32 );
+void emu10k1_writefn0(struct emu10k1_card *, u32 , u32 );
+u32 emu10k1_readfn0(struct emu10k1_card *, u32 );
void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 );
+void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...);
+#define TAGLIST_END 0
+
u32 sblive_readptr(struct emu10k1_card *, u32 , u32 );
+void emu10k1_irq_enable(struct emu10k1_card *, u32);
+void emu10k1_irq_disable(struct emu10k1_card *, u32);
void emu10k1_set_stop_on_loop(struct emu10k1_card *, u32);
void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32);
#ifndef _ICARDWAV_H
#define _ICARDWAV_H
-/* Enumeration for SetControl */
-enum
-{
- WAVECURPOS = 0x10,
-};
-
struct wave_format
{
- u32 samplingrate;
- u32 bitsperchannel;
- u32 channels; /* 1 = Mono, 2 = Stereo */
+ int samplingrate;
+ u8 bitsperchannel;
+ u8 channels; /* 1 = Mono, 2 = Stereo */
+ u8 bytesperchannel;
+ u8 bytespersample;
+ int bytespersec;
};
/* emu10k1_wave states */
-#define CARDWAVE_STATE_STOPPED 0x0001
-#define CARDWAVE_STATE_STARTED 0x0002
+#define WAVE_STATE_OPEN 0x01
+#define WAVE_STATE_STARTED 0x02
+#define WAVE_STATE_CLOSED 0x04
#endif /* _ICARDWAV_H */
*/
#include "hwaccess.h"
+#include "8010.h"
#include "cardmi.h"
#include "cardmo.h"
#include "irqmgr.h"
void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
- u32 irqstatus, ptr, tmp;
+ u32 irqstatus, tmp;
- if (!(irqstatus = sblive_readfn0(card, IPR)))
+ if (!(irqstatus = emu10k1_readfn0(card, IPR)))
return;
DPD(4, "emu10k1_interrupt called, irq = %u\n", irq);
- /* Preserve PTR register */
- ptr = sblive_readfn0(card, PTR);
-
/*
** NOTE :
** We do a 'while loop' here cos on certain machines, with both
if (irqstatus)
emu10k1_irq_disable(card, irqstatus);
- sblive_writefn0(card, IPR, tmp);
-
- } while ((irqstatus = sblive_readfn0(card, IPR)));
+ emu10k1_writefn0(card, IPR, tmp);
- sblive_writefn0(card, PTR, ptr);
+ } while ((irqstatus = emu10k1_readfn0(card, IPR)));
return;
}
-/* Enables the specified irq service */
-
-int emu10k1_irq_enable(struct emu10k1_card *card, u32 irqtype)
-{
- /*
- * TODO :
- * put protection here so that we don't accidentally
- * screw-up another cardxxx objects irqs
- */
-
- DPD(4, "emu10k1_irq_enable %x\n", irqtype);
- sblive_wrtmskfn0(card, INTE, irqtype, ENABLE);
-
- return CTSTATUS_SUCCESS;
-}
-
-/* Disables the specified irq service */
-
-int emu10k1_irq_disable(struct emu10k1_card *card, u32 irqtype)
-{
- /*
- * TODO :
- * put protection here so that we don't accidentally
- * screw-up another cardxxx objects irqs
- */
-
- DPD(4, "emu10k1_irq_disable %x\n", irqtype);
- sblive_wrtmskfn0(card, INTE, irqtype, DISABLE);
-
- return CTSTATUS_SUCCESS;
-}
#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
#define IRQTYPE_DSP IPR_FXDSP
-struct emu10k1_wavedevice
-{
- struct emu10k1_card *card;
- struct wiinst *wiinst;
- struct woinst *woinst;
- u16 enablebits;
-};
-
void emu10k1_timer_irqhandler(struct emu10k1_card *);
-int emu10k1_irq_enable(struct emu10k1_card *, u32);
-int emu10k1_irq_disable(struct emu10k1_card *, u32);
-
#endif /* _IRQ_H */
-
/*
**********************************************************************
* main.c - Creative EMU10K1 audio driver
* 0.4 Added rear-channel, SPDIF support.
* 0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes,
* moved bh's to tasklets, moved to the new PCI driver initialization style.
+ * 0.6 Make use of pci_alloc_consistent, improve compatibility layer for 2.2 kernels,
+ * code reorganization and cleanup.
+ * 0.7 Support for the Emu-APS. Bug fixes for voice cache setup, mmaped sound + poll().
+ * Support for setting external TRAM size.
+ *
**********************************************************************
*/
/* These are only included once per module */
+#include <linux/version.h>
#include <linux/module.h>
+#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include "hwaccess.h"
+#include "8010.h"
#include "efxmgr.h"
#include "cardwo.h"
#include "cardwi.h"
#include "cardmo.h"
#include "cardmi.h"
#include "recmgr.h"
+#include "ecard.h"
-#define DRIVER_VERSION "0.5"
+#define DRIVER_VERSION "0.7"
/* FIXME: is this right? */
+/* does the card support 32 bit bus master?*/
#define EMU10K1_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
#ifndef PCI_VENDOR_ID_CREATIVE
#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
#endif
-#define EMU10K1_EXTENT 0x20 /* 32 byte I/O space */
-
+#define EMU_APS_SUBID 0x40011102
+
enum {
EMU10K1 = 0,
};
"EMU10K1",
};
-static struct pci_device_id emu10k1_pci_tbl[] __devinitdata = {
+static struct pci_device_id emu10k1_pci_tbl[] = {
{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1},
{0,}
extern void emu10k1_interrupt(int, void *, struct pt_regs *s);
extern int emu10k1_mixer_wrch(struct emu10k1_card *, unsigned int, int);
-static int __devinit audio_init(struct emu10k1_card *card)
+static void __devinit audio_init(struct emu10k1_card *card)
{
- if ((card->waveout = kmalloc(sizeof(struct emu10k1_waveout), GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_waveout: out of memory\n");
- return CTSTATUS_ERROR;
- }
- memset(card->waveout, 0, sizeof(struct emu10k1_waveout));
-
- /* Assign default global volume, reverb, chorus */
- card->waveout->globalvol = 0xffffffff;
- card->waveout->left = 0xffff;
- card->waveout->right = 0xffff;
- card->waveout->mute = 0;
- card->waveout->globalreverb = 0xffffffff;
- card->waveout->globalchorus = 0xffffffff;
-
- if ((card->wavein = kmalloc(sizeof(struct emu10k1_wavein), GFP_KERNEL))
- == NULL) {
- printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_wavein: out of memory\n");
- return CTSTATUS_ERROR;
- }
- memset(card->wavein, 0, sizeof(struct emu10k1_wavein));
+ /* Assign default playback voice parameters */
+ /* mono voice */
+ card->waveout.send_a[0] = 0x00;
+ card->waveout.send_b[0] = 0xff;
+ card->waveout.send_c[0] = 0xff;
+ card->waveout.send_d[0] = 0x00;
+ card->waveout.send_routing[0] = 0xd01c;
+
+ /* stereo voice */
+ card->waveout.send_a[1] = 0x00;
+ card->waveout.send_b[1] = 0xff;
+ card->waveout.send_c[1] = 0x00;
+ card->waveout.send_d[1] = 0x00;
+ card->waveout.send_routing[1] = 0xd01c;
+
+ card->waveout.send_a[2] = 0x00;
+ card->waveout.send_b[2] = 0x00;
+ card->waveout.send_c[2] = 0xff;
+ card->waveout.send_d[2] = 0x00;
+ card->waveout.send_routing[2] = 0xd01c;
+
+ /* Assign default recording parameters */
+ if(card->isaps)
+ card->wavein.recsrc = WAVERECORD_FX;
+ else
+ card->wavein.recsrc = WAVERECORD_AC97;
+
+ card->wavein.fxwc = 0x0003;
- card->wavein->recsrc = WAVERECORD_AC97;
-
- return CTSTATUS_SUCCESS;
+ return;
}
static void __devinit mixer_init(struct emu10k1_card *card)
SOUND_MIXER_PHONEIN, 0x3232}, {
SOUND_MIXER_MIC, 0x0000}, {
SOUND_MIXER_LINE, 0x0000}, {
- SOUND_MIXER_CD, 0x3232}, {
- SOUND_MIXER_LINE1, 0x3232}, {
+ SOUND_MIXER_CD, 0x4b4b}, {
+ SOUND_MIXER_LINE1, 0x4b4b}, {
SOUND_MIXER_LINE3, 0x3232}, {
SOUND_MIXER_DIGITAL1, 0x6464}, {
SOUND_MIXER_DIGITAL2, 0x6464}, {
SOUND_MIXER_PCM, 0x6464}, {
- SOUND_MIXER_RECLEV, 0x3232}, {
+ SOUND_MIXER_RECLEV, 0x0404}, {
SOUND_MIXER_TREBLE, 0x3232}, {
SOUND_MIXER_BASS, 0x3232}, {
- SOUND_MIXER_LINE2, 0x4b4b}};
+ SOUND_MIXER_LINE2, 0x4b4b}};
- int initdig[] = { 0, 1, 2, 3, 6, 7, 16, 17, 18, 19, 22, 23, 64, 65, 66, 67, 70, 71,
- 84, 85
+ int initdig[] = { 0, 1, 2, 3, 6, 7, 18, 19, 20, 21, 24, 25, 72, 73, 74, 75, 78, 79,
+ 94, 95
};
- /* Reset */
- sblive_writeac97(card, AC97_RESET, 0);
-
-#if 0
- /* Check status word */
- {
- u16 reg;
-
- sblive_readac97(card, AC97_RESET, ®);
- DPD(2, "RESET 0x%x\n", reg);
- sblive_readac97(card, AC97_MASTERTONE, ®);
- DPD(2, "MASTER_TONE 0x%x\n", reg);
+ for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) {
+ card->digmix[count] = 0x80000000;
+ sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0);
}
-#endif
- /* Set default recording source to mic in */
- sblive_writeac97(card, AC97_RECORDSELECT, 0);
+ card->modcnt = 0; // Should this be here or in open() ?
- /* Set default AC97 "PCM" volume to acceptable max */
- //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
- //sblive_writeac97(card, AC97_LINE2, 0);
+ if (!card->isaps) {
- /* Set default volumes for all mixer channels */
+ for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) {
+ card->digmix[initdig[count]] = 0x7fffffff;
+ sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff);
+ }
- for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) {
- card->digmix[count] = 0x80000000;
- sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0);
- }
+ /* Reset */
+ sblive_writeac97(card, AC97_RESET, 0);
+
+#if 0
+ /* Check status word */
+ {
+ u16 reg;
+
+ sblive_readac97(card, AC97_RESET, ®);
+ DPD(2, "RESET 0x%x\n", reg);
+ sblive_readac97(card, AC97_MASTERTONE, ®);
+ DPD(2, "MASTER_TONE 0x%x\n", reg);
+ }
+#endif
- for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) {
- card->digmix[initdig[count]] = 0x7fffffff;
- sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff);
+ /* Set default recording source to mic in */
+ sblive_writeac97(card, AC97_RECORDSELECT, 0);
+
+ /* Set default AC97 "PCM" volume to acceptable max */
+ //sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
+ //sblive_writeac97(card, AC97_LINE2, 0);
}
+ /* Set default volumes for all mixer channels */
+
for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++) {
emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol);
}
- card->modcnt = 0; // Should this be here or in open() ?
-
return;
}
if ((card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL))
== NULL) {
printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n");
- return CTSTATUS_ERROR;
+ return -1;
}
memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout));
if ((card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL)) == NULL) {
kfree(card->mpuout);
printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n");
- return CTSTATUS_ERROR;
+ return -1;
}
memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin));
spin_lock_init(&card->mpuin->lock);
/* Reset the MPU port */
- if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) {
+ if (emu10k1_mpu_reset(card) < 0) {
ERROR();
- return CTSTATUS_ERROR;
+ return -1;
}
- return CTSTATUS_SUCCESS;
+ return 0;
}
static void __devinit voice_init(struct emu10k1_card *card)
{
- struct voice_manager *voicemgr = &card->voicemgr;
- struct emu_voice *voice;
int i;
- voicemgr->card = card;
- voicemgr->lock = SPIN_LOCK_UNLOCKED;
-
- voice = voicemgr->voice;
- for (i = 0; i < NUM_G; i++) {
- voice->card = card;
- voice->usage = VOICEMGR_USAGE_FREE;
- voice->num = i;
- voice->linked_voice = NULL;
- voice++;
- }
+ for (i = 0; i < NUM_G; i++)
+ card->voicetable[i] = VOICE_USAGE_FREE;
return;
}
/* Mark first page as used */
/* This page is reserved by the driver */
card->emupagetable[0] = 0x8001;
- card->emupagetable[1] = MAXPAGES - RESERVED - 1;
+ card->emupagetable[1] = MAXPAGES - 1;
return;
}
static void __devinit fx_init(struct emu10k1_card *card)
{
- int i, j, k, l;
+ int i, j, k;
+#ifdef TONE_CONTROL
+ int l;
+#endif
u32 pc = 0;
for (i = 0; i < 512; i++)
OP(6, 0x40, 0x40, 0x40, 0x40);
for (i = 0; i < 256; i++)
- sblive_writeptr(card, FXGPREGBASE + i, 0, 0);
+ sblive_writeptr_tag(card, 0,
+ FXGPREGBASE + i, 0,
+ TANKMEMADDRREGBASE + i, 0,
+ TAGLIST_END);
pc = 0;
OP(4, 0x101, 0x40, j + 2, 0x44);
for (i = 0; i < 6; i++) {
- k = i * 16 + j;
+ k = i * 18 + j;
OP(0, 0x102, 0x40, 0x110 + k, 0x100);
OP(0, 0x102, 0x102, 0x112 + k, 0x101);
OP(0, 0x102, 0x102, 0x114 + k, 0x10 + j);
OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j);
OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j);
OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j);
-
- k = 0x190 + i * 8 + j * 4;
- OP(0, 0x40, 0x40, 0x102, 0x170 + j);
- OP(7, k + 1, k, k + 1, 0x174 + j);
- OP(7, k, 0x102, k, 0x172 + j);
- OP(7, k + 3, k + 2, k + 3, 0x178 + j);
- OP(0, k + 2, 0x56, k + 2, 0x176 + j);
+#ifdef TONE_CONTROL
+ OP(0, 0x102, 0x102, 0x120 + k, 0x1c + j);
+
+ k = 0x1a0 + i * 8 + j * 4;
+ OP(0, 0x40, 0x40, 0x102, 0x180 + j);
+ OP(7, k + 1, k, k + 1, 0x184 + j);
+ OP(7, k, 0x102, k, 0x182 + j);
+ OP(7, k + 3, k + 2, k + 3, 0x188 + j);
+ OP(0, k + 2, 0x56, k + 2, 0x186 + j);
OP(6, k + 2, k + 2, k + 2, 0x40);
- l = 0x1c0 + i * 8 + j * 4;
- OP(0, 0x40, 0x40, k + 2, 0x180 + j);
- OP(7, l + 1, l, l + 1, 0x184 + j);
- OP(7, l, k + 2, l, 0x182 + j);
- OP(7, l + 3, l + 2, l + 3, 0x188 + j);
- OP(0, l + 2, 0x56, l + 2, 0x186 + j);
+ l = 0x1d0 + i * 8 + j * 4;
+ OP(0, 0x40, 0x40, k + 2, 0x190 + j);
+ OP(7, l + 1, l, l + 1, 0x194 + j);
+ OP(7, l, k + 2, l, 0x192 + j);
+ OP(7, l + 3, l + 2, l + 3, 0x198 + j);
+ OP(0, l + 2, 0x56, l + 2, 0x196 + j);
OP(4, l + 2, 0x40, l + 2, 0x46);
- OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40);
-
+ if ((i == 0) && !card->isaps)
+ OP(4, 0x20 + (i * 2) + j, 0x40, l + 2, 0x50); /* FIXME: Is this really needed? */
+ else
+ OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40);
+#else
+ OP(0, 0x20 + (i * 2) + j, 0x102, 0x120 + k, 0x1c + j);
+#endif
}
}
sblive_writeptr(card, DBG, 0, 0);
static int __devinit hw_init(struct emu10k1_card *card)
{
int nCh;
-
-#ifdef TANKMEM
- u32 size = 0;
-#endif
- u32 sizeIdx = 0;
- u32 pagecount, tmp;
+ u32 pagecount; /* tmp */
/* Disable audio and lock cache */
- sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
+ emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE);
/* Reset recording buffers */
- sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE);
- sblive_writeptr(card, MICBA, 0, 0);
- sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE);
- sblive_writeptr(card, FXBA, 0, 0);
- sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE);
- sblive_writeptr(card, ADCBA, 0, 0);
+ sblive_writeptr_tag(card, 0,
+ MICBS, ADCBS_BUFSIZE_NONE,
+ MICBA, 0,
+ FXBS, ADCBS_BUFSIZE_NONE,
+ FXBA, 0,
+ ADCBS, ADCBS_BUFSIZE_NONE,
+ ADCBA, 0,
+ TAGLIST_END);
/* Disable channel interrupt */
- sblive_writefn0(card, INTE, DISABLE);
- sblive_writeptr(card, CLIEL, 0, 0);
- sblive_writeptr(card, CLIEH, 0, 0);
- sblive_writeptr(card, SOLEL, 0, 0);
- sblive_writeptr(card, SOLEH, 0, 0);
+ emu10k1_writefn0(card, INTE, 0);
+ sblive_writeptr_tag(card, 0,
+ CLIEL, 0,
+ CLIEH, 0,
+ SOLEL, 0,
+ SOLEH, 0,
+ TAGLIST_END);
/* Init envelope engine */
for (nCh = 0; nCh < NUM_G; nCh++) {
- sblive_writeptr(card, DCYSUSV, nCh, ENV_OFF);
- sblive_writeptr(card, IP, nCh, 0);
- sblive_writeptr(card, VTFT, nCh, 0xffff);
- sblive_writeptr(card, CVCF, nCh, 0xffff);
- sblive_writeptr(card, PTRX, nCh, 0);
- sblive_writeptr(card, CPF, nCh, 0);
- sblive_writeptr(card, CCR, nCh, 0);
-
- sblive_writeptr(card, PSST, nCh, 0);
- sblive_writeptr(card, DSL, nCh, 0x10);
- sblive_writeptr(card, CCCA, nCh, 0);
- sblive_writeptr(card, Z1, nCh, 0);
- sblive_writeptr(card, Z2, nCh, 0);
- sblive_writeptr(card, FXRT, nCh, 0xd01c0000);
-
- sblive_writeptr(card, ATKHLDM, nCh, 0);
- sblive_writeptr(card, DCYSUSM, nCh, 0);
- sblive_writeptr(card, IFATN, nCh, 0xffff);
- sblive_writeptr(card, PEFE, nCh, 0);
- sblive_writeptr(card, FMMOD, nCh, 0);
- sblive_writeptr(card, TREMFRQ, nCh, 24); /* 1 Hz */
- sblive_writeptr(card, FM2FRQ2, nCh, 24); /* 1 Hz */
- sblive_writeptr(card, TEMPENV, nCh, 0);
-
- /*** These are last so OFF prevents writing ***/
- sblive_writeptr(card, LFOVAL2, nCh, 0);
- sblive_writeptr(card, LFOVAL1, nCh, 0);
- sblive_writeptr(card, ATKHLDV, nCh, 0);
- sblive_writeptr(card, ENVVOL, nCh, 0);
- sblive_writeptr(card, ENVVAL, nCh, 0);
+ sblive_writeptr_tag(card, nCh,
+ DCYSUSV, 0,
+ IP, 0,
+ VTFT, 0xffff,
+ CVCF, 0xffff,
+ PTRX, 0,
+ CPF, 0,
+ CCR, 0,
+
+ PSST, 0,
+ DSL, 0x10,
+ CCCA, 0,
+ Z1, 0,
+ Z2, 0,
+ FXRT, 0xd01c0000,
+
+ ATKHLDM, 0,
+ DCYSUSM, 0,
+ IFATN, 0xffff,
+ PEFE, 0,
+ FMMOD, 0,
+ TREMFRQ, 24, /* 1 Hz */
+ FM2FRQ2, 24, /* 1 Hz */
+ TEMPENV, 0,
+
+ /*** These are last so OFF prevents writing ***/
+ LFOVAL2, 0,
+ LFOVAL1, 0,
+ ATKHLDV, 0,
+ ENVVOL, 0,
+ ENVVAL, 0,
+ TAGLIST_END);
}
/*
** P = 0 (Consumer)
*/
- /* SPDIF0 */
- sblive_writeptr(card, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+ sblive_writeptr_tag(card, 0,
- /* SPDIF1 */
- sblive_writeptr(card, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+ /* SPDIF0 */
+ SPCS0, (SPCS_CLKACCY_1000PPM | 0x002000000 |
+ SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT),
- /* SPDIF2 & SPDIF3 */
- sblive_writeptr(card, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+ /* SPDIF1 */
+ SPCS1, (SPCS_CLKACCY_1000PPM | 0x002000000 |
+ SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT),
- fx_init(card); /* initialize effects engine */
+ /* SPDIF2 & SPDIF3 */
+ SPCS2, (SPCS_CLKACCY_1000PPM | 0x002000000 |
+ SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT),
- card->tankmem = NULL;
+ TAGLIST_END);
-#ifdef TANKMEM
- size = TMEMSIZE;
- sizeIdx = TMEMSIZEREG;
- while (size > 16384) {
- if ((card->tankmem = emu10k1_alloc_memphysical(size)) != NULL)
- break;
-
- size /= 2;
- sizeIdx -= 1;
- }
+ fx_init(card); /* initialize effects engine */
- if (card->tankmem == NULL) {
- card->tmemsize = 0;
- return CTSTATUS_ERROR;
- }
+ card->tankmem.size = 0;
- card->tmemsize = size;
-#else /* !TANKMEM */
- card->tmemsize = 0;
-#endif /* TANKMEM */
+ card->virtualpagetable.size = MAXPAGES * sizeof(u32);
- if ((card->virtualpagetable = emu10k1_alloc_memphysical((MAXPAGES - RESERVED) * sizeof(u32))) == NULL) {
+ if ((card->virtualpagetable.addr = pci_alloc_consistent(card->pci_dev, card->virtualpagetable.size, &card->virtualpagetable.dma_handle)) ==
+ NULL) {
ERROR();
- emu10k1_free_memphysical(card->tankmem);
- return CTSTATUS_ERROR;
+ return -1;
}
- if ((card->silentpage = emu10k1_alloc_memphysical(EMUPAGESIZE)) == NULL) {
- ERROR();
- emu10k1_free_memphysical(card->tankmem);
- emu10k1_free_memphysical(card->virtualpagetable);
- return CTSTATUS_ERROR;
- } else
- memset(card->silentpage->virtaddx, 0, EMUPAGESIZE);
+ card->silentpage.size = EMUPAGESIZE;
- for (pagecount = 0; pagecount < (MAXPAGES - RESERVED); pagecount++)
+ if ((card->silentpage.addr = pci_alloc_consistent(card->pci_dev, card->silentpage.size, &card->silentpage.dma_handle)) == NULL) {
+ ERROR();
+ pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle);
+ return -1;
+ }
- ((u32 *) card->virtualpagetable->virtaddx)[pagecount] = (card->silentpage->busaddx * 2) | pagecount;
+ for (pagecount = 0; pagecount < MAXPAGES; pagecount++)
+ ((u32 *) card->virtualpagetable.addr)[pagecount] = (card->silentpage.dma_handle * 2) | pagecount;
/* Init page table & tank memory base register */
- sblive_writeptr(card, PTB, 0, card->virtualpagetable->busaddx);
-#ifdef TANKMEM
- sblive_writeptr(card, TCB, 0, card->tankmem->busaddx);
-#else
- sblive_writeptr(card, TCB, 0, 0);
-#endif
- sblive_writeptr(card, TCBS, 0, sizeIdx);
+ sblive_writeptr_tag(card, 0,
+ PTB, card->virtualpagetable.dma_handle,
+ TCB, 0,
+ TCBS, 0,
+ TAGLIST_END);
for (nCh = 0; nCh < NUM_G; nCh++) {
- sblive_writeptr(card, MAPA, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
- sblive_writeptr(card, MAPB, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+ sblive_writeptr_tag(card, nCh,
+ MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2),
+ MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2),
+ TAGLIST_END);
}
/* Hokay, now enable the AUD bit */
sblive_writeac97(card, AC97_MASTERVOLUME, 0);
sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
- sblive_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
+ if(card->model == 0x20 || card->model == 0xc400 ||
+ (card->model == 0x21 && card->chiprev < 6))
+ emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE);
+ else
+ emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE);
- /* TOSLink detection */
+ /* FIXME: TOSLink detection */
card->has_toslink = 0;
- tmp = sblive_readfn0(card, HCFG);
+/* tmp = sblive_readfn0(card, HCFG);
if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
sblive_writefn0(card, HCFG, tmp | 0x800);
sblive_writefn0(card, HCFG, tmp);
}
}
-
- return CTSTATUS_SUCCESS;
+*/
+ return 0;
}
static int __devinit emu10k1_init(struct emu10k1_card *card)
{
/* Init Card */
- if (hw_init(card) != CTSTATUS_SUCCESS)
- return CTSTATUS_ERROR;
+ if (hw_init(card) < 0)
+ return -1;
voice_init(card);
timer_init(card);
addxmgr_init(card);
- DPD(2, " hw control register -> %x\n", sblive_readfn0(card, HCFG));
-
- return CTSTATUS_SUCCESS;
-}
+ DPD(2, " hw control register -> 0x%x\n", emu10k1_readfn0(card, HCFG));
-static void __devexit audio_exit(struct emu10k1_card *card)
-{
- kfree(card->waveout);
- kfree(card->wavein);
- return;
+ return 0;
}
static void __devexit midi_exit(struct emu10k1_card *card)
return;
}
-static void __devexit emu10k1_exit(struct emu10k1_card *card)
+static void __devinit emu10k1_exit(struct emu10k1_card *card)
{
int ch;
- sblive_writefn0(card, INTE, DISABLE);
+ emu10k1_writefn0(card, INTE, 0);
/** Shutdown the chip **/
for (ch = 0; ch < NUM_G; ch++)
- sblive_writeptr(card, DCYSUSV, ch, ENV_OFF);
+ sblive_writeptr(card, DCYSUSV, ch, 0);
for (ch = 0; ch < NUM_G; ch++) {
- sblive_writeptr(card, VTFT, ch, 0);
- sblive_writeptr(card, CVCF, ch, 0);
- sblive_writeptr(card, PTRX, ch, 0);
- sblive_writeptr(card, CPF, ch, 0);
+ sblive_writeptr_tag(card, ch,
+ VTFT, 0,
+ CVCF, 0,
+ PTRX, 0,
+ CPF, 0,
+ TAGLIST_END);
}
- /* Reset recording buffers */
- sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE);
- sblive_writeptr(card, MICBA, 0, 0);
- sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE);
- sblive_writeptr(card, FXBA, 0, 0);
- sblive_writeptr(card, FXWC, 0, 0);
- sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE);
- sblive_writeptr(card, ADCBA, 0, 0);
- sblive_writeptr(card, TCBS, 0, TCBS_BUFFSIZE_16K);
- sblive_writeptr(card, TCB, 0, 0);
- sblive_writeptr(card, DBG, 0, 0x8000);
-
- /* Disable channel interrupt */
- sblive_writeptr(card, CLIEL, 0, 0);
- sblive_writeptr(card, CLIEH, 0, 0);
- sblive_writeptr(card, SOLEL, 0, 0);
- sblive_writeptr(card, SOLEH, 0, 0);
-
/* Disable audio and lock cache */
- sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
- sblive_writeptr(card, PTB, 0, 0);
+ emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE);
+
+ sblive_writeptr_tag(card, 0,
+ PTB, 0,
+
+ /* Reset recording buffers */
+ MICBS, ADCBS_BUFSIZE_NONE,
+ MICBA, 0,
+ FXBS, ADCBS_BUFSIZE_NONE,
+ FXBA, 0,
+ FXWC, 0,
+ ADCBS, ADCBS_BUFSIZE_NONE,
+ ADCBA, 0,
+ TCBS, 0,
+ TCB, 0,
+ DBG, 0x8000,
+
+ /* Disable channel interrupt */
+ CLIEL, 0,
+ CLIEH, 0,
+ SOLEL, 0,
+ SOLEH, 0,
+ TAGLIST_END);
+
+
+ pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle);
+ pci_free_consistent(card->pci_dev, card->silentpage.size, card->silentpage.addr, card->silentpage.dma_handle);
+
+ if(card->tankmem.size != 0)
+ pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle);
- emu10k1_free_memphysical(card->silentpage);
- emu10k1_free_memphysical(card->virtualpagetable);
-#ifdef TANKMEM
- emu10k1_free_memphysical(card->tankmem);
-#endif
return;
}
static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
struct emu10k1_card *card;
+ u32 subsysvid;
if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "emu10k1: out of memory\n");
}
memset(card, 0, sizeof(struct emu10k1_card));
-#if LINUX_VERSION_CODE > 0x020320
if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) {
printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n");
kfree(card);
pci_set_master(pci_dev);
card->iobase = pci_resource_start(pci_dev, 0);
+ card->length = pci_resource_len(pci_dev, 0);
- if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) {
+ if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
printk(KERN_ERR "emu10k1: IO space in use\n");
kfree(card);
return -ENODEV;
}
- pci_dev->driver_data = card;
- pci_dev->dma_mask = EMU10K1_DMA_MASK;
-#else
- pci_set_master(pci_dev);
- card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+ PCI_SET_DRIVER_DATA(pci_dev, card);
+ PCI_SET_DMA_MASK(pci_dev, EMU10K1_DMA_MASK);
- if (check_region(card->iobase, EMU10K1_EXTENT)) {
- printk(KERN_ERR "emu10k1: IO space in use\n");
- kfree(card);
- return -ENODEV;
- }
-
- request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]);
-#endif
card->irq = pci_dev->irq;
card->pci_dev = pci_dev;
}
pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev);
+ pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &card->model);
- printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq);
+ printk(KERN_INFO "emu10k1: %s rev %d model 0x%x found, IO at 0x%04lx-0x%04lx, IRQ %d\n",
+ card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase,
+ card->iobase + card->length - 1, card->irq);
+
+ pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
+ card->isaps = (subsysvid == EMU_APS_SUBID);
spin_lock_init(&card->lock);
- card->mixeraddx = card->iobase + AC97DATA;
init_MUTEX(&card->open_sem);
card->open_mode = 0;
init_waitqueue_head(&card->open_wait);
/* Register devices */
- if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
+ if ((card->audio_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
printk(KERN_ERR "emu10k1: cannot register first audio device!\n");
goto err_dev0;
}
- if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
+ if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
printk(KERN_ERR "emu10k1: cannot register second audio device!\n");
goto err_dev1;
}
goto err_dev3;
}
- if (emu10k1_init(card) != CTSTATUS_SUCCESS) {
+ if (emu10k1_init(card) < 0) {
printk(KERN_ERR "emu10k1: cannot initialize device!\n");
goto err_emu10k1_init;
}
- if (audio_init(card) != CTSTATUS_SUCCESS) {
- printk(KERN_ERR "emu10k1: cannot initialize audio!\n");
- goto err_audio_init;
- }
-
- if (midi_init(card) != CTSTATUS_SUCCESS) {
+ if (midi_init(card) < 0) {
printk(KERN_ERR "emu10k1: cannot initialize midi!\n");
goto err_midi_init;
}
+ audio_init(card);
mixer_init(card);
- DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize);
+ if (card->isaps)
+ emu10k1_ecard_init(card);
list_add(&card->list, &emu10k1_devs);
return 0;
err_midi_init:
- audio_exit(card);
-
- err_audio_init:
emu10k1_exit(card);
err_emu10k1_init:
unregister_sound_mixer(card->mixer_num);
err_dev2:
- unregister_sound_dsp(card->audio2_num);
+ unregister_sound_dsp(card->audio1_num);
err_dev1:
- unregister_sound_dsp(card->audio1_num);
+ unregister_sound_dsp(card->audio_num);
err_dev0:
free_irq(card->irq, card);
err_irq:
- release_region(card->iobase, EMU10K1_EXTENT);
+ release_region(card->iobase, card->length);
kfree(card);
return -ENODEV;
static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
{
-#if LINUX_VERSION_CODE > 0x020320
- struct emu10k1_card *card = pci_dev->driver_data;
-#else
- struct emu10k1_card *card = list_entry(emu10k1_devs.next, struct emu10k1_card, list);
-#endif
+ struct emu10k1_card *card = PCI_GET_DRIVER_DATA(pci_dev);
+
midi_exit(card);
- audio_exit(card);
emu10k1_exit(card);
unregister_sound_midi(card->midi_num);
+
unregister_sound_mixer(card->mixer_num);
- unregister_sound_dsp(card->audio2_num);
+
unregister_sound_dsp(card->audio1_num);
+ unregister_sound_dsp(card->audio_num);
free_irq(card->irq, card);
- release_region(card->iobase, EMU10K1_EXTENT);
+ release_region(card->iobase, card->length);
list_del(&card->list);
kfree(card);
+
return;
}
remove:emu10k1_remove,
};
-#if LINUX_VERSION_CODE > 0x020320
static int __init emu10k1_init_module(void)
{
printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
static void __exit emu10k1_cleanup_module(void)
{
pci_unregister_driver(&emu10k1_pci_driver);
- return;
-}
-
-#else
-
-static int __init emu10k1_init_module(void)
-{
- struct pci_dev *dev = NULL;
- const struct pci_device_id *pci_id = emu10k1_pci_driver.id_table;
-
- printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
- if (!pci_present())
- return -ENODEV;
-
- while (pci_id->vendor) {
- while ((dev = pci_find_device(pci_id->vendor, pci_id->device, dev)))
- emu10k1_probe(dev, pci_id);
-
- pci_id++;
- }
- return 0;
-}
-
-static void __exit emu10k1_cleanup_module(void)
-{
- struct emu10k1_card *card;
-
- while (!list_empty(&emu10k1_devs)) {
- card = list_entry(emu10k1_devs.next, struct emu10k1_card, list);
-
- emu10k1_remove(card->pci_dev);
- }
return;
}
-#endif
-
module_init(emu10k1_init_module);
module_exit(emu10k1_cleanup_module);
#define __NO_VERSION__
#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) {
ERROR();
kfree(midihdr);
- return CTSTATUS_ERROR;
+ return -1;
}
- if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) {
+ if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) < 0) {
ERROR();
kfree(midihdr->data);
kfree(midihdr);
- return CTSTATUS_ERROR;
+ return -1;
}
*midihdrptr = midihdr;
list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
- return CTSTATUS_SUCCESS;
+ return 0;
}
static int emu10k1_midi_open(struct inode *inode, struct file *file)
dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
- if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo)
- != CTSTATUS_SUCCESS) {
+ if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) < 0) {
ERROR();
kfree(midi_dev);
return -ENODEV;
}
/* Add two buffers to receive sysex buffer */
- if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) {
+ if (midiin_add_buffer(midi_dev, &midihdr1) < 0) {
kfree(midi_dev);
return -ENODEV;
}
- if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) {
+ if (midiin_add_buffer(midi_dev, &midihdr2) < 0) {
list_del(&midihdr1->list);
kfree(midihdr1->data);
kfree(midihdr1);
dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
- if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo)
- != CTSTATUS_SUCCESS) {
+ if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
ERROR();
kfree(midi_dev);
return -ENODEV;
struct emu10k1_card *card;
lock_kernel();
+
card = midi_dev->card;
DPF(2, "emu10k1_midi_release()\n");
card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
up(&card->open_sem);
wake_up_interruptible(&card->open_wait);
+
unlock_kernel();
return 0;
return -EFAULT;
if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
- if (emu10k1_mpuin_start(midi_dev->card)
- != CTSTATUS_SUCCESS) {
+ if (emu10k1_mpuin_start(midi_dev->card) < 0) {
ERROR();
return -EINVAL;
}
spin_lock_irqsave(&midi_spinlock, flags);
- if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) {
+ if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) < 0) {
ERROR();
kfree(midihdr->data);
kfree(midihdr);
break;
default: /* Unknown message */
- return CTSTATUS_ERROR;
+ return -1;
}
spin_unlock_irqrestore(&midi_spinlock, flags);
- return CTSTATUS_SUCCESS;
+ return 0;
}
/* MIDI file operations */
struct file_operations emu10k1_midi_fops = {
- owner:THIS_MODULE,
- read:emu10k1_midi_read,
- write:emu10k1_midi_write,
- poll:emu10k1_midi_poll,
- open:emu10k1_midi_open,
- release:emu10k1_midi_release,
+ owner: THIS_MODULE,
+ read: emu10k1_midi_read,
+ write: emu10k1_midi_write,
+ poll: emu10k1_midi_poll,
+ open: emu10k1_midi_open,
+ release: emu10k1_midi_release,
};
-
/*
**********************************************************************
* mixer.c - /dev/mixer interface for emu10k1 driver
#define __NO_VERSION__ /* Kernel version only defined once */
#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/bitops.h>
#include <asm/uaccess.h>
#include "hwaccess.h"
+#include "8010.h"
+#include "recmgr.h"
#define AC97_PESSIMISTIC
#undef OSS_DOCUMENTED_MIXER_SEMANTICS
#define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31)
#define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15)
+#define DM_MUTE 0x80000000
+
#ifdef PRIVATE_PCM_VOLUME
struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS];
+u16 pcm_last_mixer = 0x6464;
#endif
-/* --------------------------------------------------------------------- */
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-extern __inline__ unsigned int hweight32(unsigned int w)
-{
- unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-
- res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
- res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
- res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
- return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
/* Mapping arrays */
static const unsigned int recsrc[] = {
SOUND_MASK_MIC,
SOUND_MASK_VOLUME,
SOUND_MASK_OGAIN, /* Used to be PHONEOUT */
SOUND_MASK_PHONEIN,
+#ifdef TONE_CONTROL
SOUND_MASK_TREBLE,
SOUND_MASK_BASS,
- SOUND_MASK_MONITOR,
- SOUND_MASK_PCM,
+#endif
};
static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = {
/* 4 bit mono */
[SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC,
/* test code */
- [SOUND_MIXER_BASS] = AC97_GENERALPUPOSE,
+ [SOUND_MIXER_BASS] = AC97_GENERALPURPOSE,
[SOUND_MIXER_TREBLE] = AC97_MASTERTONE,
[SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME,
[SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME
int j;
int nL, nR;
+ switch (ch) {
+ case SOUND_MIXER_PCM:
+ case SOUND_MIXER_VOLUME:
+#ifdef TONE_CONTROL
+ case SOUND_MIXER_TREBLE:
+ case SOUND_MIXER_BASS:
+#endif
+ return put_user(0x0000, (int *) arg);
+ default:
+ break;
+ }
+
+ if(card->isaps)
+ return -EINVAL;
+
switch (ch) {
case SOUND_MIXER_LINE:
case SOUND_MIXER_CD:
case SOUND_MIXER_VIDEO:
case SOUND_MIXER_LINE1:
- case SOUND_MIXER_PCM:
- case SOUND_MIXER_VOLUME:
sblive_readac97(card, volreg[ch], ®);
nL = ((~(reg >> 8) & 0x1f) * 100) / 32;
nR = (~(reg & 0x1f) * 100) / 32;
nR = (~(reg & 0x1f) * 100) / 16;
return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
- case SOUND_MIXER_TREBLE:
- case SOUND_MIXER_BASS:
- return put_user(0x0000, (int *) arg);
default:
return -EINVAL;
}
[SOUND_MIXER_DIGITAL2] = 19
};
-u32 bass_table[41][5] = {
+#ifdef TONE_CONTROL
+
+static const u32 bass_table[41][5] = {
{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
{ 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
{ 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
};
-u32 treble_table[41][5] = {
+static const u32 treble_table[41][5] = {
{ 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
{ 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
{ 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
l = (l * 40 + 50) / 100;
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++) {
- sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2), 0, bass_table[l][i]);
- sblive_writeptr(card, FXGPREGBASE + 0x70 + (i * 2) + 1, 0, bass_table[r][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, bass_table[l][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, bass_table[r][i]);
}
}
l = (l * 40 + 50) / 100;
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++) {
- sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, treble_table[l][i]);
- sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, treble_table[r][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2), 0, treble_table[l][i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2) + 1, 0, treble_table[r][i]);
}
}
-u32 db_table[101] = {
+#endif
+
+static const u32 db_table[101] = {
0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
0x7fffffff,
};
+static void aps_update_digital(struct emu10k1_card *card)
+{
+ int i, l1, r1, l2, r2;
+
+ i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]];
+ l1 = (i & 0xff);
+ r1 = ((i >> 8) & 0xff);
+
+ i = card->arrwVol[volidx[SOUND_MIXER_PCM]];
+ l2 = (i & 0xff);
+ r2 = ((i >> 8) & 0xff);
+
+ for (i = 0; i < 108; i++) {
+ if (card->digmix[i] != DM_MUTE) {
+ if ((i % 18 >= 0) && (i % 18 < 4))
+ card->digmix[i] = ((i & 1) ? ((u64) db_table[r1] * (u64) db_table[r2]) : ((u64) db_table[l1] * (u64) db_table[l2])) >> 31;
+ else
+ card->digmix[i] = (i & 1) ? db_table[r1] : db_table[l1];
+ sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
+ }
+ }
+}
+
static void update_digital(struct emu10k1_card *card)
{
int i, k, l1, r1, l2, r2, l3, r3, l4, r4;
l1 = i;
}
- for (i = 0; i < 16; i++) {
- if (card->digmix[i] != 0x80000000) {
- if ((i >= 0) && (i < 4))
+ for (i = 0; i < 36; i++) {
+ if (card->digmix[i] != DM_MUTE) {
+ if (((i >= 0) && (i < 4)) || ((i >= 18) && (i < 22)))
j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]);
- else if ((i == 6) || (i == 7))
+ else if ((i == 6) || (i == 7) || (i == 24) || (i == 25))
j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]);
else
j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31;
}
}
- for (i = 64; i < 80; i++) {
- if (card->digmix[i] != 0x80000000) {
- if ((i >= 64) && (i < 68))
+ for (i = 72; i < 90; i++) {
+ if (card->digmix[i] != DM_MUTE) {
+ if ((i >= 72) && (i < 76))
j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]);
- else if ((i == 70) || (i == 71))
+ else if ((i == 78) || (i == 79))
j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]);
else
j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31;
}
}
- for (i = 16; i <= 80; i += 16) {
- if (i != 64) {
+ for (i = 36; i <= 90; i += 18) {
+ if (i != 72) {
for (k = 0; k < 4; k++)
- if (card->digmix[i + k] != 0x80000000) {
+ if (card->digmix[i + k] != DM_MUTE) {
card->digmix[i + k] = db_table[l3];
sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]);
}
- if (card->digmix[i + 6] != 0x80000000) {
+ if (card->digmix[i + 6] != DM_MUTE) {
card->digmix[i + 6] = db_table[l4];
sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]);
}
- if (card->digmix[i + 7] != 0x80000000) {
+ if (card->digmix[i + 7] != DM_MUTE) {
card->digmix[i + 7] = db_table[r4];
sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]);
}
static int set_pcm_attn(struct emu10k1_card *card, int ch, int l)
{
#ifndef PCMLEVEL
-#define PCMLEVEL 140 // almost silence
+#define PCMLEVEL 110 /* almost silence */
#endif
- int vol = IFATN_ATTENUATION_MASK; // silence
+ int vol = IFATN_ATTENUATION_MASK; /* silence */
if (l > 0)
vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100);
for (i = 0; i < MAX_PCM_CHANNELS; i++) {
if (sblive_pcm_volume[i].files == current->files) {
- sblive_pcm_volume[i].mixer = mixer;
+ sblive_pcm_volume[i].mixer = pcm_last_mixer = mixer;
if (sblive_pcm_volume[i].opened) {
if (sblive_pcm_volume[i].channel_r < NUM_G) {
+ sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
if (sblive_pcm_volume[i].channel_l < NUM_G)
sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1);
- sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
} else {
- // mono voice
+ /* mono voice */
if (sblive_pcm_volume[i].channel_l < NUM_G)
sblive_pcm_volume[i].attn_l =
set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1);
- // to correctly handle mono voice here we would need
- // to go into stereo mode and move the voice to the right & left
- // looks a bit overcomlicated...
+ /* to correctly handle mono voice here we would need
+ to go into stereo mode and move the voice to the right & left
+ looks a bit overcomplicated... */
}
-
}
+
return 1;
+
}
}
- if (i == MAX_PCM_CHANNELS)
- card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
+ card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
return 0;
}
#endif
switch (ch) {
case SOUND_MIXER_VOLUME:
- case SOUND_MIXER_DIGITAL1:
- case SOUND_MIXER_LINE3:
- DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
- update_digital(card);
+ DPF(4, "SOUND_MIXER_VOLUME:\n");
+ if (card->isaps)
+ aps_update_digital(card);
+ else
+ update_digital(card);
return 0;
case SOUND_MIXER_PCM:
DPF(4, "SOUND_MIXER_PCM\n");
if (update_pcm_attn(card, l1, r1))
return 0;
#endif
+ if (card->isaps)
+ aps_update_digital(card);
+ else
+ update_digital(card);
+ return 0;
+#ifdef TONE_CONTROL
+ case SOUND_MIXER_TREBLE:
+ DPF(4, "SOUND_MIXER_TREBLE:\n");
+ set_treble(card, l1, r1);
+ return 0;
+
+ case SOUND_MIXER_BASS:
+ DPF(4, "SOUND_MIXER_BASS:\n");
+ set_bass(card, l1, r1);
+ return 0;
+#endif
+ default:
+ break;
+ }
+
+
+ if (card->isaps)
+ return -EINVAL;
+
+ switch (ch) {
+ case SOUND_MIXER_DIGITAL1:
+ case SOUND_MIXER_LINE3:
+ DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
update_digital(card);
return 0;
case SOUND_MIXER_DIGITAL2:
DPF(4, "SOUND_MIXER_MIC:\n");
i = 0;
if (l1 >= 30)
- // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30
+ /* 20dB / (34.5dB + 12dB + 20dB) * 100 = 30 */
{
l1 -= 30;
i = 0x40;
sblive_writeac97(card, volreg[ch], wval);
return 0;
- case SOUND_MIXER_TREBLE:
- DPF(4, "SOUND_MIXER_TREBLE:\n");
- set_treble(card, l1, r1);
- return 0;
-
- case SOUND_MIXER_BASS:
- DPF(4, "SOUND_MIXER_BASS:\n");
- set_bass(card, l1, r1);
- return 0;
-
default:
DPF(2, "Got unknown SOUND_MIXER ioctl\n");
return -EINVAL;
/* Mixer file operations */
/* FIXME: Do we need spinlocks in here? */
+/* WARNING! not all the ioctl's are supported by the emu-APS
+ (anything AC97 related). As a general rule keep the AC97 related ioctls
+ separate from the rest. This will make it easier to rewrite the mixer
+ using the kernel AC97 interface. */
static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
static const char id[] = "SBLive";
return -EFAULT;
for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++)
- sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]);
+ sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & DM_MUTE) ? 0 : card->digmix[i]);
return 0;
break;
+ case SOUND_MIXER_PRIVATE3: {
+ struct mixer_private_ioctl ctl;
+
+ if (copy_from_user(&ctl, (void *) arg, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ switch (ctl.cmd) {
+#ifdef EMU10K1_DEBUG
+ case CMD_WRITEFN0:
+ emu10k1_writefn0(card, ctl.val[0], ctl.val[1]);
+ return 0;
+ break;
+
+ case CMD_WRITEPTR:
+ if(ctl.val[1] >= 0x40)
+ return -EINVAL;
+
+ if(ctl.val[0] > 0xff)
+ return -EINVAL;
+
+ if((ctl.val[0] & 0x7ff) > 0x3f)
+ ctl.val[1] = 0x00;
+
+ sblive_writeptr(card, ctl.val[0], ctl.val[1], ctl.val[2]);
+
+ return 0;
+ break;
+#endif
+ case CMD_READFN0:
+ ctl.val[2] = emu10k1_readfn0(card, ctl.val[0]);
+
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_READPTR:
+ if(ctl.val[1] >= 0x40)
+ return -EINVAL;
+
+ if((ctl.val[0] & 0x7ff) > 0xff)
+ return -EINVAL;
+
+ if((ctl.val[0] & 0x7ff) > 0x3f)
+ ctl.val[1] = 0x00;
+
+ ctl.val[2] = sblive_readptr(card, ctl.val[0], ctl.val[1]);
+
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_SETRECSRC:
+ switch(ctl.val[0]){
+ case WAVERECORD_AC97:
+ if(card->isaps)
+ return -EINVAL;
+ card->wavein.recsrc = WAVERECORD_AC97;
+ break;
+ case WAVERECORD_MIC:
+ card->wavein.recsrc = WAVERECORD_MIC;
+ break;
+ case WAVERECORD_FX:
+ card->wavein.recsrc = WAVERECORD_FX;
+ card->wavein.fxwc = ctl.val[1] & 0xffff;
+ if(!card->wavein.fxwc)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ break;
+
+ case CMD_GETRECSRC:
+ ctl.val[0] = card->wavein.recsrc;
+ ctl.val[1] = card->wavein.fxwc;
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_GETVOICEPARAM:
+
+ ctl.val[0] = card->waveout.send_routing[0];
+ ctl.val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 |
+ card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24;
+
+ ctl.val[2] = card->waveout.send_routing[1];
+ ctl.val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 |
+ card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24;
+
+ ctl.val[4] = card->waveout.send_routing[2];
+ ctl.val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 |
+ card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24;
+
+ if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+ return -EFAULT;
+
+ return 0;
+ break;
+
+ case CMD_SETVOICEPARAM:
+ card->waveout.send_routing[0] = ctl.val[0] & 0xffff;
+ card->waveout.send_a[0] = ctl.val[1] & 0xff;
+ card->waveout.send_b[0] = (ctl.val[1] >> 8) & 0xff;
+ card->waveout.send_c[0] = (ctl.val[1] >> 16) & 0xff;
+ card->waveout.send_d[0] = (ctl.val[1] >> 24) & 0xff;
+
+ card->waveout.send_routing[1] = ctl.val[2] & 0xffff;
+ card->waveout.send_a[1] = ctl.val[3] & 0xff;
+ card->waveout.send_b[1] = (ctl.val[3] >> 8) & 0xff;
+ card->waveout.send_c[1] = (ctl.val[3] >> 16) & 0xff;
+ card->waveout.send_d[1] = (ctl.val[3] >> 24) & 0xff;
+
+ card->waveout.send_routing[2] = ctl.val[4] & 0xffff;
+ card->waveout.send_a[2] = ctl.val[5] & 0xff;
+ card->waveout.send_b[2] = (ctl.val[5] >> 8) & 0xff;
+ card->waveout.send_c[2] = (ctl.val[5] >> 16) & 0xff;
+ card->waveout.send_d[2] = (ctl.val[5] >> 24) & 0xff;
+
+ return 0;
+ break;
+
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+ break;
+
+ case SOUND_MIXER_PRIVATE4:{
+ u32 size;
+ int size_reg = 0;
+
+ if (copy_from_user(&size, (void *) arg, sizeof(size)))
+ return -EFAULT;
+
+ DPD(2,"External tram size 0x%x\n", size);
+
+ if(size > 0x1fffff)
+ return -EINVAL;
+
+ if (size != 0) {
+ size = (size - 1) >> 14;
+
+ while (size) {
+ size >>= 1;
+ size_reg++;
+ }
+
+ size = 0x4000 << size_reg;
+ }
+
+ DPD(2,"External tram size 0x%x 0x%x\n", size, size_reg);
+
+ if (size != card->tankmem.size) {
+ if (card->tankmem.size > 0) {
+ emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1);
+
+ sblive_writeptr_tag(card, 0, TCB, 0,
+ TCBS, 0,
+ TAGLIST_END);
+
+ pci_free_consistent(card->pci_dev, card->tankmem.size,
+ card->tankmem.addr, card->tankmem.dma_handle);
+
+ card->tankmem.size = 0;
+ }
+
+ if (size != 0) {
+ if ((card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size,
+ &card->tankmem.dma_handle)) == NULL)
+ return -ENOMEM;
+
+ card->tankmem.size = size;
+
+ sblive_writeptr_tag(card, 0, TCB, card->tankmem.dma_handle,
+ TCBS, size_reg,
+ TAGLIST_END);
+
+ emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
+ }
+ }
+ return 0;
+ }
+ break;
default:
break;
if (_IOC_DIR(cmd) == _IOC_READ) {
switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- DPF(2, "SOUND_MIXER_READ_RECSRC\n");
- sblive_readac97(card, AC97_RECORDSELECT, ®);
- return put_user(recsrc[reg & 7], (int *) arg);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+ case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+ DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+ if (card->isaps)
+#ifdef TONE_CONTROL
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE,
+ (int *) arg);
+#else
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME,
+ (int *) arg);
+#endif
+
+#ifdef TONE_CONTROL
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+ SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+ SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+ SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
+ SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
+#else
return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+ SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+ SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+ SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
+ SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
+#endif
+
+ case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+ DPF(2, "SOUND_MIXER_READ_RECMASK\n");
+ if (card->isaps)
+ return put_user(0, (int *) arg);
+
+ return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
+ SOUND_MASK_LINE1 | SOUND_MASK_LINE |
+ SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
+ SOUND_MASK_PHONEIN, (int *) arg);
+
+ case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+ DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
+
+ if (card->isaps)
+#ifdef TONE_CONTROL
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE,
+ (int *) arg);
+#else
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME,
+ (int *) arg);
+#endif
+
+#ifdef TONE_CONTROL
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
SOUND_MASK_PCM | SOUND_MASK_VOLUME |
- SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
SOUND_MASK_BASS | SOUND_MASK_TREBLE |
- SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
- SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
- SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- DPF(2, "SOUND_MIXER_READ_RECMASK\n");
- return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
- SOUND_MASK_LINE1 | SOUND_MASK_LINE |
- SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
- SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR |
- SOUND_MASK_PCM, (int *) arg);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
- return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
+ SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
+ SOUND_MASK_LINE2, (int *) arg);
+#else
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
SOUND_MASK_PCM | SOUND_MASK_VOLUME |
- SOUND_MASK_BASS | SOUND_MASK_TREBLE |
SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
- SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
+ SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
SOUND_MASK_LINE2, (int *) arg);
+#endif
- case SOUND_MIXER_CAPS:
- DPF(2, "SOUND_MIXER_READ_CAPS\n");
- return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
-
+ case SOUND_MIXER_CAPS:
+ DPF(2, "SOUND_MIXER_READ_CAPS\n");
+ return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
#ifdef PRIVATE_PCM_VOLUME
- case SOUND_MIXER_PCM:
- // needs to be before default: !!
- {
- int i;
-
- for (i = 0; i < MAX_PCM_CHANNELS; i++) {
- if (sblive_pcm_volume[i].files == current->files) {
- return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
- }
- }
- }
+ case SOUND_MIXER_PCM:
+ /* needs to be before default: !!*/
+ {
+ int i;
+
+ for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+ if (sblive_pcm_volume[i].files == current->files) {
+ return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
+ }
+ }
+ }
#endif
+ default:
+ break;
+ }
+
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ DPF(2, "SOUND_MIXER_READ_RECSRC\n");
+ if (card->isaps)
+ return put_user(0, (int *) arg);
+
+ sblive_readac97(card, AC97_RECORDSELECT, ®);
+ return put_user(recsrc[reg & 7], (int *) arg);
+
default:
i = _IOC_NR(cmd);
DPD(4, "SOUND_MIXER_READ(%d)\n", i);
#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
}
}
+
/* End of _IOC_READ */
if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
return -EINVAL;
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
+ if (card->isaps)
+ return -EINVAL;
+
get_user_ret(val, (int *) arg, -EFAULT);
i = hweight32(val);
if (i == 0)
- return 0; /*val = mixer_recmask(s); */
+ return 0; /* val = mixer_recmask(s); */
else if (i > 1) {
sblive_readac97(card, AC97_RECORDSELECT, ®);
val &= ~recsrc[reg & 7];
static int emu10k1_mixer_release(struct inode *inode, struct file *file)
{
- DPF(3, "emu10k1_mixer_release()\n");
+ DPF(4, "emu10k1_mixer_release()\n");
return 0;
}
struct file_operations emu10k1_mixer_fops = {
- owner:THIS_MODULE,
- llseek:emu10k1_mixer_llseek,
- ioctl:emu10k1_mixer_ioctl,
- open:emu10k1_mixer_open,
- release:emu10k1_mixer_release,
+ owner: THIS_MODULE,
+ llseek: emu10k1_mixer_llseek,
+ ioctl: emu10k1_mixer_ioctl,
+ open: emu10k1_mixer_open,
+ release: emu10k1_mixer_release,
};
+++ /dev/null
-
-/*
- **********************************************************************
- * osutils.c - OS Services layer for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-#include "hwaccess.h"
-
-struct memhandle *emu10k1_alloc_memphysical(u32 size)
-{
- struct memhandle *handle;
- u32 reqpage, order;
-
- if ((handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL)) == NULL)
- return handle;
-
- DPD(3, "kmalloc: [%p]\n", handle);
-
- order = 0;
- reqpage = size / PAGE_SIZE;
-
- if (size % PAGE_SIZE)
- reqpage++;
-
- if (reqpage != 0) {
- reqpage--;
- while (reqpage > 0) {
- reqpage >>= 1;
- order++;
- }
- }
-
- if ((handle->virtaddx = (void *) __get_free_pages(GFP_KERNEL, order)) == NULL) {
- kfree(handle);
-
- DPD(3, "kfree: [%p]\n", handle);
- return (void *) NULL;
- }
-
- /* in linux, we can directly access physical address, don't need to do
- * phys_to_virt.
- * In linux kernel 2.0.36, virt_to_bus does nothing, get_free_pages
- * returns physical address. But in kernel 2.2.1 upwards,
- * get_free_pages returns virtual address, we need to convert it
- * to physical address. Then this physical address can be used to
- * program hardware registers. */
- handle->busaddx = virt_to_bus(handle->virtaddx);
- handle->order = order;
-
- DPD(3, "__get_free_pages: [%p] %lx\n", handle->virtaddx, handle->busaddx);
-
- return handle;
-}
-
-void emu10k1_free_memphysical(struct memhandle *handle)
-{
- free_pages((unsigned long) handle->virtaddx, handle->order);
- kfree(handle);
-
- DPD(3, "free_pages: [%p]\n", handle->virtaddx);
- DPD(3, "kfree: [%p]\n", handle);
-
- return;
-}
-
/*
**********************************************************************
* recmgr.c -- Recording manager for emu10k1 driver
**********************************************************************
*/
-#include "hwaccess.h"
+#include "8010.h"
#include "recmgr.h"
-void emu10k1_start_record(struct record *rec_ptr)
+void emu10k1_start_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
- struct emu10k1_card *hw_ptr = rec_ptr->card;
-
DPF(2, "emu10k1_start_record()\n");
- DPD(2, "bus addx: %lx\n", rec_ptr->busaddx);
- sblive_writeptr(hw_ptr, rec_ptr->bufaddrreg, 0, rec_ptr->busaddx);
- sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, rec_ptr->bufsize);
+ sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval);
- if (rec_ptr->adcctl)
- sblive_writeptr(hw_ptr, ADCCR, 0, rec_ptr->adcctl);
+ if (buffer->adcctl)
+ sblive_writeptr(card, ADCCR, 0, buffer->adcctl);
return;
}
-void emu10k1_stop_record(struct record *rec_ptr)
+void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
- struct emu10k1_card *hw_ptr = rec_ptr->card;
-
DPF(2, "emu10k1_stop_record()\n");
/* Disable record transfer */
- if (rec_ptr->adcctl)
- sblive_writeptr(hw_ptr, ADCCR, 0, 0);
+ if (buffer->adcctl)
+ sblive_writeptr(card, ADCCR, 0, 0);
- sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, ADCBS_BUFSIZE_NONE);
+ sblive_writeptr(card, buffer->sizereg, 0, ADCBS_BUFSIZE_NONE);
return;
}
-void emu10k1_set_record_src(struct record *rec_ptr, u8 recsrc)
+void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
{
+ struct wavein_buffer *buffer = &wiinst->buffer;
+
DPF(2, "emu10k1_set_record_src()\n");
- switch (recsrc) {
+ switch (wiinst->recsrc) {
case WAVERECORD_AC97:
DPF(2, "recording source: AC97\n");
- rec_ptr->bufsizereg = ADCBS;
- rec_ptr->bufaddrreg = ADCBA;
- rec_ptr->bufidxreg = ADCIDX_IDX;
+ buffer->sizereg = ADCBS;
+ buffer->addrreg = ADCBA;
+ buffer->idxreg = ADCIDX_IDX;
- switch (rec_ptr->samplingrate) {
+ switch (wiinst->format.samplingrate) {
case 0xBB80:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_48;
+ buffer->adcctl = ADCCR_SAMPLERATE_48;
break;
case 0xAC44:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_44;
+ buffer->adcctl = ADCCR_SAMPLERATE_44;
break;
case 0x7D00:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_32;
+ buffer->adcctl = ADCCR_SAMPLERATE_32;
break;
case 0x5DC0:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_24;
+ buffer->adcctl = ADCCR_SAMPLERATE_24;
break;
case 0x5622:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_22;
+ buffer->adcctl = ADCCR_SAMPLERATE_22;
break;
case 0x3E80:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_16;
+ buffer->adcctl = ADCCR_SAMPLERATE_16;
break;
case 0x2B11:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_11;
+ buffer->adcctl = ADCCR_SAMPLERATE_11;
break;
case 0x1F40:
- rec_ptr->adcctl = ADCCR_SAMPLERATE_8;
+ buffer->adcctl = ADCCR_SAMPLERATE_8;
break;
default:
+ BUG();
break;
}
- rec_ptr->adcctl |= ADCCR_LCHANENABLE;
+ buffer->adcctl |= ADCCR_LCHANENABLE;
- if (rec_ptr->is_stereo)
- rec_ptr->adcctl |= ADCCR_RCHANENABLE;
-
- // rec_ptr->fxwc = 0;
+ if (wiinst->format.channels == 2)
+ buffer->adcctl |= ADCCR_RCHANENABLE;
break;
case WAVERECORD_MIC:
DPF(2, "recording source: MIC\n");
- rec_ptr->bufsizereg = MICBS;
- rec_ptr->bufaddrreg = MICBA;
- rec_ptr->bufidxreg = MICIDX_IDX;
- rec_ptr->adcctl = 0;
- // rec_ptr->fxwc = 0;
+ buffer->sizereg = MICBS;
+ buffer->addrreg = MICBA;
+ buffer->idxreg = MICIDX_IDX;
+ buffer->adcctl = 0;
break;
case WAVERECORD_FX:
DPF(2, "recording source: FX\n");
- rec_ptr->bufsizereg = FXBS;
- rec_ptr->bufaddrreg = FXBA;
- rec_ptr->bufidxreg = FXIDX_IDX;
- rec_ptr->adcctl = 0;
- // rec_ptr->fxwc = 0x000ffff;
+ buffer->sizereg = FXBS;
+ buffer->addrreg = FXBA;
+ buffer->idxreg = FXIDX_IDX;
+ buffer->adcctl = 0;
+
+ sblive_writeptr(card, FXWC, 0, wiinst->fxwc);
break;
default:
+ BUG();
break;
}
+ DPD(2, "bus addx: %x\n", buffer->dma_handle);
+
+ sblive_writeptr(card, buffer->addrreg, 0, buffer->dma_handle);
+
return;
}
#ifndef _RECORDMGR_H
#define _RECORDMGR_H
-struct record
-{
- struct emu10k1_card *card;
- u8 *recbuffer;
- u32 recpos;
- int is_stereo;
- int is_16bit;
- u32 recbufsize;
- u32 bufsize;
- u32 bufsizereg;
- u32 bufaddrreg;
- u32 bufidxreg;
- u32 adcctl;
- unsigned long busaddx;
- u32 samplingrate;
-};
+#include "hwaccess.h"
+#include "cardwi.h"
/* Recording resources */
#define WAVERECORD_AC97 0x01
#define WAVERECORD_MIC 0x02
#define WAVERECORD_FX 0x03
-void emu10k1_start_record(struct record *);
-void emu10k1_stop_record(struct record *);
-void emu10k1_set_record_src(struct record *, u8);
+void emu10k1_start_record(struct emu10k1_card *, struct wavein_buffer *);
+void emu10k1_stop_record(struct emu10k1_card *, struct wavein_buffer *);
+void emu10k1_set_record_src(struct emu10k1_card *, struct wiinst *wiinst);
#endif /* _RECORDMGR_H */
/* 4/3/2000 Implemented timer list using list.h Rui Sousa */
#include "hwaccess.h"
+#include "8010.h"
+#include "irqmgr.h"
+#include "timer.h"
/* Try to schedule only once per fragment */
list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list);
- if (t->active) {
+ if (t->state & TIMER_STATE_ACTIVE) {
t->count++;
if (t->count == t->count_max) {
t->count = 0;
return;
}
-struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) (unsigned long), unsigned long data, u32 delay)
+void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u32 delay)
{
- struct emu_timer *timer;
struct emu_timer *t;
struct list_head *entry;
unsigned long flags;
- if ((timer = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL)) == NULL)
- return timer;
-
if (delay < 5)
delay = 5;
timer->delay = delay;
- tasklet_init(&timer->tasklet, func, data);
- timer->active = 0;
+ timer->state = TIMER_STATE_INSTALLED;
spin_lock_irqsave(&card->timer_lock, flags);
card->timer_delay = delay;
delay = (delay < 1024 ? delay : 1024);
- WRITE_FN0(card, TIMER_RATE, delay);
+ emu10k1_writefn0(card, TIMER_RATE, delay);
list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list);
spin_unlock_irqrestore(&card->timer_lock, flags);
- return timer;
+ return;
}
void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer)
u32 delay = TIMER_STOPPED;
unsigned long flags;
+ if (timer->state == TIMER_STATE_UNINSTALLED)
+ return;
+
spin_lock_irqsave(&card->timer_lock, flags);
list_del(&timer->list);
else {
delay = (delay < 1024 ? delay : 1024);
- WRITE_FN0(card, TIMER_RATE, delay);
+ emu10k1_writefn0(card, TIMER_RATE, delay);
list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list);
spin_unlock_irqrestore(&card->timer_lock, flags);
- tasklet_unlock_wait(&timer->tasklet);
- kfree(timer);
+ timer->state = TIMER_STATE_UNINSTALLED;
return;
}
unsigned long flags;
spin_lock_irqsave(&card->timer_lock, flags);
- timer->active = 1;
+ timer->state |= TIMER_STATE_ACTIVE;
spin_unlock_irqrestore(&card->timer_lock, flags);
return;
unsigned long flags;
spin_lock_irqsave(&card->timer_lock, flags);
- timer->active = 0;
+ timer->state &= ~TIMER_STATE_ACTIVE;
spin_unlock_irqrestore(&card->timer_lock, flags);
return;
#ifndef _TIMER_H
#define _TIMER_H
+#include <linux/interrupt.h>
+#include "hwaccess.h"
+
struct emu_timer
{
struct list_head list;
struct tasklet_struct tasklet;
- int active;
+ u8 state;
u32 count; /* current number of interrupts */
u32 count_max; /* number of interrupts needed to schedule the bh */
u32 delay; /* timer delay */
};
-struct emu_timer *emu10k1_timer_install(struct emu10k1_card *, void (*)(unsigned long), unsigned long, u32);
+void emu10k1_timer_install(struct emu10k1_card *, struct emu_timer *, u32);
void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *);
void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *);
void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *);
-#define TIMER_STOPPED 0xffffffff
+#define TIMER_STOPPED 0xffffffff
+#define TIMER_STATE_INSTALLED 0x01
+#define TIMER_STATE_ACTIVE 0x02
+#define TIMER_STATE_UNINSTALLED 0x04
#endif /* _TIMER_H */
-
/*
**********************************************************************
* voicemgr.c - Voice manager for emu10k1 driver
**********************************************************************
*/
-#include "hwaccess.h"
+#include "voicemgr.h"
+#include "8010.h"
-struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc)
+int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice)
{
- struct emu10k1_card *card = voicemgr->card;
- struct emu_voice *voice_tmp = voicemgr->voice;
- struct emu_voice *voice = NULL;
+ u8 *voicetable = card->voicetable;
int i;
unsigned long flags;
DPF(2, "emu10k1_voice_alloc()\n");
- spin_lock_irqsave(&voicemgr->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
- if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) {
- for (i = 0; i < NUM_G; i++)
- if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) {
- voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
- voice_tmp[i].usage = voiceallocdesc->usage;
- voice = &voice_tmp[i];
+ if (voice->flags & VOICE_FLAGS_STEREO) {
+ for (i = 0; i < NUM_G; i += 2)
+ if ((voicetable[i] == VOICE_USAGE_FREE) && (voicetable[i + 1] == VOICE_USAGE_FREE)) {
+ voicetable[i] = voice->usage;
+ voicetable[i + 1] = voice->usage;
break;
}
} else {
- for (i = 0; i < NUM_G; i += 2)
- if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE)
- && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) {
- voice_tmp[i].linked_voice = &voice_tmp[i + 1];
- voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
- voice_tmp[i].usage = voiceallocdesc->usage;
- voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags;
- voice_tmp[i + 1].usage = voiceallocdesc->usage;
- voice = &voice_tmp[i];
+ for (i = 0; i < NUM_G; i++)
+ if (voicetable[i] == VOICE_USAGE_FREE) {
+ voicetable[i] = voice->usage;
break;
}
}
- spin_unlock_irqrestore(&voicemgr->lock, flags);
+ spin_unlock_irqrestore(&card->lock, flags);
- voice_tmp = voice;
+ if (i >= NUM_G)
+ return -1;
- while (voice_tmp != NULL) {
+ voice->card = card;
+ voice->num = i;
- DPD(2, " voice allocated -> %d\n", voice_tmp->num);
+#ifdef PRIVATE_PCM_VOLUME
- sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff);
- sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF);
- sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff);
- sblive_writeptr(card, PTRX, voice_tmp->num, 0);
+ for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+ if (sblive_pcm_volume[i].files == current->files) {
+ sblive_pcm_volume[i].channel_l = voice->num;
+ DPD(2, "preset left: %d\n", voice->num);
+ if (voice->flags & VOICE_FLAGS_STEREO) {
+ sblive_pcm_volume[i].channel_r = voice->num + 1;
+ DPD(2, "preset right: %d\n", voice->num + 1);
+ }
+ break;
+ }
+ }
+#endif
+
+ for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
+ DPD(2, " voice allocated -> %d\n", voice->num + i);
- voice_tmp = voice_tmp->linked_voice;
+ sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff,
+ DCYSUSV, 0,
+ VTFT, 0x0000ffff,
+ PTRX, 0,
+ TAGLIST_END);
}
- return voice;
+ return 0;
}
-void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice)
+void emu10k1_voice_free(struct emu_voice *voice)
{
struct emu10k1_card *card = voice->card;
- struct emu_voice *voice_tmp;
- unsigned dcysusv;
- u32 cra, sample;
int i;
unsigned long flags;
DPF(2, "emu10k1_voice_free()\n");
- voice_tmp = voice;
-
- while (voice_tmp != NULL) {
-
- DPD(2, " voice freed -> %d\n", voice_tmp->num);
+ if (voice->usage == VOICE_USAGE_FREE)
+ return;
- sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK);
- sblive_writeptr(card, IP, voice_tmp->num, 0);
+#ifdef PRIVATE_PCM_VOLUME
+ for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+ if (sblive_pcm_volume[i].files == current->files) {
+ if (voice->num == sblive_pcm_volume[i].channel_l)
+ sblive_pcm_volume[i].channel_l = NUM_G;
+ if ((voice->flags & VOICE_FLAGS_STEREO)
+ && (voice->num + 1) == sblive_pcm_volume[i].channel_r) {
+ sblive_pcm_volume[i].channel_r = NUM_G;
+ }
+ break;
+ }
+ }
+#endif
- dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK);
- sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF);
+ for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
+ DPD(2, " voice released -> %d\n", voice->num + i);
- sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK);
- sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0);
- sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK);
- sblive_writeptr(card, CPF, voice_tmp->num, 0);
+ sblive_writeptr_tag(card, voice->num + i, DCYSUSV, 0,
+ VTFT, 0x0000ffff,
+ PTRX_PITCHTARGET, 0,
+ CVCF, 0x0000ffff,
+ CPF, 0,
+ TAGLIST_END);
+ }
- sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080;
- cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK;
- sblive_writeptr(card, CCR, voice_tmp->num, cra);
- cra = (cra >> 18) & 0xf;
- sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
- cra = (cra + 0x1) & 0xf;
- sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
+ voice->usage = VOICE_USAGE_FREE;
- for (i = 0; i < NUM_FXSENDS; i++)
- voice_tmp->sendhandle[i] = 0;
+ spin_lock_irqsave(&card->lock, flags);
- voice_tmp->flags = 0;
+ card->voicetable[voice->num] = VOICE_USAGE_FREE;
- spin_lock_irqsave(&voicemgr->lock, flags);
- voice_tmp->usage = VOICEMGR_USAGE_FREE;
+ if (voice->flags & VOICE_FLAGS_STEREO)
+ card->voicetable[voice->num + 1] = VOICE_USAGE_FREE;
- voice_tmp = voice_tmp->linked_voice;
- voice->linked_voice = NULL;
- spin_unlock_irqrestore(&voicemgr->lock, flags);
- }
+ spin_unlock_irqrestore(&card->lock, flags);
return;
}
-/* Sets up a voices for Wave Playback */
-
void emu10k1_voice_playback_setup(struct emu_voice *voice)
{
struct emu10k1_card *card = voice->card;
- u32 sample, cra = 0, start = 0;
+ u32 start;
+ int i;
DPF(2, "emu10k1_voice_playback_setup()\n");
- while (voice != NULL) {
- sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF);
- sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK);
- sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK);
- sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000);
-
- /* Stop CA */
- /* Assumption that PT is alreadt 0 so no harm overwriting */
- sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b);
-
- if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) {
- if (voice->linked_voice != NULL) {
- /* Set stereo bit */
- cra = 64;
- sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
- sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
- } else {
- cra = 32;
- sblive_writeptr(card, CPF, voice->num, 0);
- }
-
- if (voice->flags & VOICEMGR_FLAGS_16BIT)
- sample = 0;
- else {
- cra = cra * 2;
- sample = 0x80808080;
- }
- cra -= 4;
-
- if (voice->linked_voice != NULL) {
- /* CCR_READADDRESS_MASK */
- sblive_writeptr(card, CCR, voice->num, 0x3c << 16);
- sblive_writeptr(card, CCR, voice->num + 1, cra << 16);
- sblive_writeptr(card, CDE, voice->num + 1, sample);
- sblive_writeptr(card, CDF, voice->num + 1, sample);
- start = voice->params.start + cra / 2;
- } else {
- sblive_writeptr(card, CCR, voice->num, 0x1c << 16); /* FIXME: Is 0x1c correct? */
- sblive_writeptr(card, CDE, voice->num, sample);
- sblive_writeptr(card, CDF, voice->num, sample);
- start = voice->params.start + cra;
- }
-
- if (start > voice->params.endloop) {
- start -= voice->params.endloop;
-
- if (voice->linked_voice != NULL)
- cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9);
- else
- cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9);
-
- start += voice->params.startloop;
-
- if (start >= voice->params.endloop)
- start = voice->params.endloop - 1;
- } else if (voice->linked_voice != NULL)
- cra = (cra << 25) | (0x3c << 16);
- else
- cra = (cra << 25) | (0x1c << 16);
-
- start |= CCCA_INTERPROM_0;
- }
-
- /* CSL, ST, CA */
- sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24));
- sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24));
+ if (voice->flags & VOICE_FLAGS_STEREO) {
+ /* Set stereo bit */
+ start = 28;
+ sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
+ sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
+ } else {
+ start = 30;
+ sblive_writeptr(card, CPF, voice->num, 0);
+ }
- if (voice->flags & VOICEMGR_FLAGS_16BIT)
- sblive_writeptr(card, CCCA, voice->num, start);
- else
- sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT);
+ if(!(voice->flags & VOICE_FLAGS_16BIT))
+ start *= 2;
- /* Clear filter delay memory */
- sblive_writeptr(card, Z1, voice->num, 0);
- sblive_writeptr(card, Z2, voice->num, 0);
+ voice->start += start;
- /* Invalidate maps */
- sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
- sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+ for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
+ sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
- /* Fill cache */
- if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
- sblive_writeptr(card, CCR, voice->num, cra);
-
- sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
- sblive_writeptr(card, LFOVAL1, voice->num, 0x8000);
- sblive_writeptr(card, ATKHLDM, voice->num, 0);
- sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK);
- sblive_writeptr(card, LFOVAL2, voice->num, 0x8000);
- sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch);
- sblive_writeptr(card, PEFE, voice->num, 0x7f);
- sblive_writeptr(card, FMMOD, voice->num, 0);
- sblive_writeptr(card, TREMFRQ, voice->num, 0);
- sblive_writeptr(card, FM2FRQ2, voice->num, 0);
- sblive_writeptr(card, ENVVAL, voice->num, 0xbfff);
- sblive_writeptr(card, ENVVOL, voice->num, 0xbfff);
+ /* Stop CA */
+ /* Assumption that PT is already 0 so no harm overwriting */
+ sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b);
+
+ sblive_writeptr_tag(card, voice->num + i,
+ /* CSL, ST, CA */
+ DSL, voice->endloop | (voice->params[i].send_d << 24),
+ PSST, voice->startloop | (voice->params[i].send_c << 24),
+ CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
+ /* Clear filter delay memory */
+ Z1, 0,
+ Z2, 0,
+ /* Invalidate maps */
+ MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2),
+ MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2),
+ /* modulation envelope */
+ CVCF, 0x0000ffff,
+ VTFT, 0x0000ffff,
+ ATKHLDM, 0,
+ DCYSUSM, 0x007f,
+ LFOVAL1, 0x8000,
+ LFOVAL2, 0x8000,
+ FMMOD, 0,
+ TREMFRQ, 0,
+ FM2FRQ2, 0,
+ ENVVAL, 0x8000,
+ /* volume envelope */
+ ATKHLDV, 0x7f7f,
+ ENVVOL, 0x8000,
+ /* filter envelope */
+ PEFE_FILTERAMOUNT, 0x7f,
+ /* pitch envelope */
+ PEFE_PITCHAMOUNT, 0, TAGLIST_END);
#ifdef PRIVATE_PCM_VOLUME
- {
- int i;
-
- for (i = 0; i < MAX_PCM_CHANNELS; i++) {
- if (sblive_pcm_volume[i].channel_l == voice->num) {
- voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l :
- // test for mono channel (reverse logic is correct here!)
- (sblive_pcm_volume[i].attn_r >
- sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r;
- DPD(2, "set left volume %d\n", voice->params.initial_attn);
- break;
- } else if (sblive_pcm_volume[i].channel_r == voice->num) {
- voice->params.initial_attn = sblive_pcm_volume[i].attn_r;
- DPD(2, "set right volume %d\n", voice->params.initial_attn);
- break;
- }
- }
- }
+{
+int j;
+ for (j = 0; j < MAX_PCM_CHANNELS; j++) {
+ if (sblive_pcm_volume[j].channel_l == voice->num + i) {
+ voice->params[i].initial_attn = (sblive_pcm_volume[j].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l :
+ // test for mono channel (reverse logic is correct here!)
+ (sblive_pcm_volume[j].attn_r >
+ sblive_pcm_volume[j].attn_l) ? sblive_pcm_volume[j].attn_l : sblive_pcm_volume[j].attn_r;
+ DPD(2, "set left volume %d\n", voice->params[i].initial_attn);
+ break;
+ } else if (sblive_pcm_volume[j].channel_r == voice->num + i) {
+ voice->params[i].initial_attn = sblive_pcm_volume[j].attn_r;
+ DPD(2, "set right volume %d\n", voice->params[i].initial_attn);
+ break;
+ }
+ }
+ }
#endif
- sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn);
-
- voice->params.FC_target = 0xffff;
- voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16);
- voice = voice->linked_voice;
+ voice->params[i].fc_target = 0xffff;
}
return;
}
-void emu10k1_voice_start(struct emu_voice *voice)
+void emu10k1_voice_start(struct emu_voice *voice, int set)
{
struct emu10k1_card *card = voice->card;
+ int i;
DPF(2, "emu10k1_voice_start()\n");
- while (voice != NULL) {
- sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target);
-
- if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
- sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target);
-
- sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16)
- | voice->params.FC_target);
- sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16)
- | voice->params.FC_target);
- sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8)
- | ENV_ON | voice->params.byampl_env_decay);
-
- /* Using StopOnLoop for MIDI stops the playback
- too early, which may cause a DC level to be played
- until the note is released. */
-
- if (voice->usage == VOICEMGR_USAGE_MIDI)
- emu10k1_clear_stop_on_loop(card, voice->num);
- else {
- if (voice->params.startloop > voice->params.end)
- emu10k1_set_stop_on_loop(card, voice->num);
- else
- emu10k1_clear_stop_on_loop(card, voice->num);
+ if (!set) {
+ u32 cra, ccis, cs, sample;
+ if (voice->flags & VOICE_FLAGS_STEREO) {
+ cra = 64;
+ ccis = 28;
+ cs = 4;
+ } else {
+ cra = 64;
+ ccis = 30;
+ cs = 2;
}
- voice = voice->linked_voice;
- }
- return;
-}
+ if(voice->flags & VOICE_FLAGS_16BIT) {
+ sample = 0x00000000;
+ } else {
+ sample = 0x80808080;
+ ccis *= 2;
+ }
-void emu10k1_voice_stop(struct emu_voice *voice)
-{
- struct emu10k1_card *card = voice->card;
+ for(i = 0; i < cs; i++)
+ sblive_writeptr(card, CD0 + i, voice->num, sample);
- DPF(2, "emu10k1_voice_stop()\n");
+ /* Reset cache */
+ sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, 0);
+ if (voice->flags & VOICE_FLAGS_STEREO)
+ sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num + 1, 0);
+
+ sblive_writeptr(card, CCR_READADDRESS, voice->num, cra);
+
+ if (voice->flags & VOICE_FLAGS_STEREO)
+ sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra);
- while (voice != NULL) {
- sblive_writeptr(card, IFATN, voice->num, 0xffff);
- sblive_writeptr(card, IP, voice->num, 0);
- sblive_writeptr(card, VTFT, voice->num, 0xffff);
- sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0);
- voice = voice->linked_voice;
+ /* Fill cache */
+ sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis);
}
- return;
-}
+ for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
+ sblive_writeptr_tag(card, voice->num + i,
+ IFATN, (voice->params[i].initial_fc << 8) | voice->params[i].initial_attn,
+ VTFT, (voice->params[i].volume_target << 16) | voice->params[i].fc_target,
+ CVCF, (voice->params[i].volume_target << 16) | voice->params[i].fc_target,
+ DCYSUSV, (voice->params[i].byampl_env_sustain << 8) | voice->params[i].byampl_env_decay,
+ TAGLIST_END);
-void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam)
-{
- struct emu10k1_card *card = voice->card;
- int count;
+ emu10k1_clear_stop_on_loop(card, voice->num + i);
+
+ sblive_writeptr(card, PTRX_PITCHTARGET, voice->num + i, voice->pitch_target);
- for (count = 0; count < numparam; count++)
- sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value);
+ if (i == 0)
+ sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->pitch_target);
+
+ sblive_writeptr(card, IP, voice->num + i, voice->initial_pitch);
+ }
return;
}
-void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value)
+void emu10k1_voice_stop(struct emu_voice *voice)
{
struct emu10k1_card *card = voice->card;
+ int i;
- *value = sblive_readptr(card, controlid, voice->num);
+ DPF(2, "emu10k1_voice_stop()\n");
+
+ for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
+ sblive_writeptr_tag(card, voice->num + i,
+ PTRX_PITCHTARGET, 0,
+ CPF_CURRENTPITCH, 0,
+ IFATN, 0xffff,
+ VTFT, 0x0000ffff,
+ CVCF, 0x0000ffff,
+ IP, 0,
+ TAGLIST_END);
+ }
return;
}
+
#ifndef _VOICEMGR_H
#define _VOICEMGR_H
+
+#include "hwaccess.h"
+
/* struct emu_voice.usage flags */
-#define VOICEMGR_USAGE_FREE 0x00000000
-#define VOICEMGR_USAGE_MIDI 0x00000001
-#define VOICEMGR_USAGE_PLAYBACK 0x00000002
+#define VOICE_USAGE_FREE 0x01
+#define VOICE_USAGE_MIDI 0x02
+#define VOICE_USAGE_PLAYBACK 0x04
/* struct emu_voice.flags flags */
-#define VOICEMGR_FLAGS_MONO 0x00000002
-#define VOICEMGR_FLAGS_16BIT 0x00000004
-#define VOICEMGR_FLAGS_STEREOSLAVE 0x00000008
-#define VOICEMGR_FLAGS_VOICEMASTER 0x80000000
-#define VOICEMGR_FLAGS_FXRT2 0x00000010
+#define VOICE_FLAGS_STEREO 0x02
+#define VOICE_FLAGS_16BIT 0x04
struct voice_param
{
- /* Sound engine */
- u32 start;
- u32 startloop;
- u32 endloop;
- u32 end;
-
- u16 current_pitch;
- u16 pitch_target;
-
- u16 current_volume;
- u16 volume_target;
-
- u16 current_FC;
- u16 FC_target;
-
- u8 pan_target;
- u8 aux_target;
-
/* FX bus amount send */
+ u32 send_routing;
+
u32 send_a;
u32 send_b;
u32 send_c;
u32 send_d;
- /* Envelope engine */
- u16 ampl_env_delay;
- u8 byampl_env_attack;
- u8 byampl_env_hold;
- u8 byampl_env_decay;
- u8 byampl_env_sustain;
- u8 byampl_env_release;
-
- u16 aux_env_delay;
- u8 byaux_env_attack;
- u8 byaux_env_hold;
- u8 byaux_env_decay;
- u8 byaux_env_sustain;
- u8 byaux_env_release;
-
- u16 mod_LFO_delay; /* LFO1 */
- u16 vib_LFO_delay; /* LFO2 */
- u8 mod_LFO_freq; /* LFO1 */
- u8 vib_LFO_freq; /* LFO2 */
-
- s8 aux_env_to_pitch;
- s8 aux_env_to_FC;
- s8 mod_LFO_to_pitch;
- s8 vib_LFO_to_pitch;
- s8 mod_LFO_to_FC;
- s8 mod_LFO_to_volume;
-
- u16 sample_pitch;
- u16 initial_pitch;
- u8 initial_attn;
- u8 initial_FC;
-};
+ u32 initial_fc;
+ u32 fc_target;
-struct voice_allocdesc
-{
- u32 usage; /* playback, Midi */
- u32 flags; /* stereo/mono rec/playback 8/16 bit*/
+ u32 initial_attn;
+ u32 volume_target;
+
+ u32 byampl_env_sustain;
+ u32 byampl_env_decay;
};
+
struct emu_voice
{
- struct list_head list;
-
struct emu10k1_card *card;
- u32 usage; /* Free, MIDI, playback */
- u32 num; /* Voice ID */
- u32 flags; /* Stereo/mono, rec/playback, 8/16 bit */
-
- struct voice_param params;
-
- struct emu_voice *linked_voice; /*for stereo voice*/
-
- u32 sendhandle[NUM_FXSENDS];
-};
+ u8 usage; /* Free, MIDI, playback */
+ u8 num; /* Voice ID */
+ u8 flags; /* Stereo/mono, 8/16 bit */
-struct voice_manager
-{
- struct emu10k1_card *card;
- spinlock_t lock;
+ u32 startloop;
+ u32 endloop;
+ u32 start;
- struct emu_voice voice[NUM_G];
-};
+ u32 initial_pitch;
+ u32 pitch_target;
-struct voice_cntlset
-{
- u32 paramID;
- u32 value;
+ struct voice_param params[2];
};
-struct emu_voice *emu10k1_voice_alloc(struct voice_manager *, struct voice_allocdesc *);
-void emu10k1_voice_free(struct voice_manager *, struct emu_voice *);
+int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *);
+void emu10k1_voice_free(struct emu_voice *);
void emu10k1_voice_playback_setup(struct emu_voice *);
-void emu10k1_voice_start(struct emu_voice *);
+void emu10k1_voice_start(struct emu_voice *, int);
void emu10k1_voice_stop(struct emu_voice *);
-void emu10k1_voice_setcontrol(struct emu_voice *, struct voice_cntlset *, u32);
-void emu10k1_voice_getcontrol(struct emu_voice *, u32, u32 *);
#endif /* _VOICEMGR_H */
#include <asm/dec21285.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/system.h>
#include "sound_config.h"
export-objs := usb.o input.o
+# Objects which appear many times
+
+common-objs := input.o
+
# Multipart objects.
list-multi := usbcore.o
obj-n :=
obj- :=
-# Object files in subdirectories
-
-ifeq ($(CONFIG_USB_SERIAL),y)
- SUB_DIRS += serial
- obj-y += serial/usb-serial.o
-else
- ifeq ($(CONFIG_USB_SERIAL),m)
- MOD_IN_SUB_DIRS += serial
- endif
-endif
-
-ifeq ($(CONFIG_USB_STORAGE),y)
- SUB_DIRS += storage
- obj-y += storage/usb-storage.o
-else
- ifeq ($(CONFIG_USB_STORAGE),m)
- MOD_IN_SUB_DIRS += storage
- endif
-endif
-
-
# Each configuration option enables a list of files.
obj-$(CONFIG_USB) += usbcore.o
obj-$(CONFIG_USB_MICROTEK) += microtek.o
obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o
+# Object files in subdirectories
+
+ifeq ($(CONFIG_USB_SERIAL),y)
+ SUB_DIRS += serial
+ obj-y += serial/usb-serial.o
+else
+ ifeq ($(CONFIG_USB_SERIAL),m)
+ MOD_IN_SUB_DIRS += serial
+ endif
+endif
+
+ifeq ($(CONFIG_USB_STORAGE),y)
+ SUB_DIRS += storage
+ obj-y += storage/usb-storage.o
+else
+ ifeq ($(CONFIG_USB_STORAGE),m)
+ MOD_IN_SUB_DIRS += storage
+ endif
+endif
+
+# Remove duplicates.
+# The 'common-*' lists are intermediate lists used to filter out
+# duplicates.
+
+common-y := $(filter $(obj-y),$(common-obj))
+obj-y := $(filter-out $(common-y), $(obj-y)) $(common-y)
+
# Extract lists of the multi-part drivers.
# The 'int-*' lists are the intermediate files used to build the multi's.
# Translate to Rules.make lists.
-O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
-OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
/*
- * bluetooth.c Version 0.3
+ * bluetooth.c Version 0.4
*
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
* USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
*
*
+ * (07/11/2000) Version 0.4 gkh
+ * Fixed bug in disconnect for when we call tty_hangup
+ * Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not
+ * getting attached to the control urb properly.
+ * Fixed bug in bluetooth_write where we pay attention to the result
+ * of bluetooth_ctrl_msg.
+ *
* (08/03/2000) Version 0.3 gkh mdc
* Merged in Mark's changes to make the driver play nice with the Axis
* stack.
dr->length = cpu_to_le16p(&len);
FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
- (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, 0);
+ (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, bluetooth);
/* send it down the pipe */
status = usb_submit_urb(urb);
else
memcpy (new_buffer, buf+1, count-1);
- bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1);
+ if (bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1) != 0) {
+ kfree (new_buffer);
+ return 0;
+ }
/* need to free new_buffer somehow... FIXME */
return count;
int i;
if (bluetooth) {
+ if ((bluetooth->active) && (bluetooth->tty))
+ tty_hangup(bluetooth->tty);
+
bluetooth->active = 0;
if (bluetooth->read_urb) {
tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor);
- if (bluetooth->tty)
- tty_hangup(bluetooth->tty);
-
for (i = 0; i < NUM_BULK_URBS; ++i) {
if (bluetooth->write_urb_pool[i]) {
usb_unlink_urb (bluetooth->write_urb_pool[i]);
else
pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
- usb_clear_halt(ps->dev, pipe);
- return 0;
+ return usb_clear_halt(ps->dev, pipe);
}
* Peter Berger (pberger@brimson.com)
* Al Borchers (borchers@steinerpoint.com)
*
+* (8/8/2000) pberger and borchers
+* -- Fixed close so that
+* - it can timeout while waiting for transmit idle, if needed;
+* - it ignores interrupts when flushing the port, turning
+* of modem signalling, and so on;
+* - it waits for the flush to really complete before returning.
+* -- Read_bulk_callback and write_bulk_callback check for a closed
+* port before using the tty struct or writing to the port.
+* -- The two changes above fix the oops caused by interrupted closes.
+* -- Added interruptible args to write_oob_command and set_modem_signals
+* and added a timeout arg to transmit_idle; needed for fixes to
+* close.
+* -- Added code for rx_throttle and rx_unthrottle so that input flow
+* control works.
+* -- Added code to set overrun, parity, framing, and break errors
+* (untested).
+* -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length
+* bulk writes are done. These hung the Digi USB device. The
+* 0 length bulk writes were a new feature of usb-uhci added in
+* the 2.4.0-test6 kernels.
+* -- Fixed mod inc race in open; do mod inc before sleeping to wait
+* for a close to finish.
+*
+* (7/31/2000) pberger
+* -- Fixed bugs with hardware handshaking:
+* - Added code to set/clear tty->hw_stopped in digi_read_oob_callback()
+* and digi_set_termios()
+* -- Added code in digi_set_termios() to
+* - add conditional in code handling transition from B0 to only
+* set RTS if RTS/CTS flow control is either not in use or if
+* the port is not currently throttled.
+* - handle turning off CRTSCTS.
+*
+* (7/30/2000) borchers
+* -- Added support for more than one Digi USB device by moving
+* globals to a private structure in the pointed to from the
+* usb_serial structure.
+* -- Moved the modem change and transmit idle wait queues into
+* the port private structure, so each port has its own queue
+* rather than sharing global queues.
+* -- Added support for break signals.
+*
+* (7/25/2000) pberger
+* -- Added USB-2 support. Note: the USB-2 supports 3 devices: two
+* serial and a parallel port. The parallel port is implemented
+* as a serial-to-parallel converter. That is, the driver actually
+* presents all three USB-2 interfaces as serial ports, but the third
+* one physically connects to a parallel device. Thus, for example,
+* one could plug a parallel printer into the USB-2's third port,
+* but from the kernel's (and userland's) point of view what's
+* actually out there is a serial device.
+*
* (7/15/2000) borchers
* -- Fixed race in open when a close is in progress.
* -- Keep count of opens and dec the module use count for each
* callbacks, and no longer restart read chains if there is
* a status error or a sanity error. This fixed the seg
* faults and other errors we used to get on disconnect.
-* -- Port->active is once again a flag, not a count, as it was
-* intended by usb-serial. Since it was only a char it would
+* -- Port->active is once again a flag as usb-serial intended it
+* to be, not a count. Since it was only a char it would
* have been limited to 256 simultaneous opens. Now the open
* count is kept in the port private structure in dp_open_count.
* -- Added code for modularization of the digi_acceleport driver.
*
* (6/4/2000) pberger and borchers
* -- Replaced separate calls to spin_unlock_irqrestore and
-* interruptible_sleep_on_interruptible with a new function
+* interruptible_sleep_on_timeout with a new function
* cond_wait_interruptible_timeout_irqrestore. This eliminates
* the race condition where the wake up could happen after
* the unlock and before the sleep.
* - Following Documentation/DocBook/kernel-locking.pdf no spin locks
* are held when calling copy_to/from_user or printk.
*
-* $Id: digi_acceleport.c,v 1.5 2000/07/18 04:52:43 root Exp $
+* $Id: digi_acceleport.c,v 1.80 2000/08/09 06:36:18 root Exp $
*/
#include <linux/config.h>
/* Defines */
-/* port buffer length -- must be <= transfer buffer length - 2 */
+/* port output buffer length -- must be <= transfer buffer length - 2 */
/* so we can be sure to send the full buffer in one urb */
-#define DIGI_PORT_BUF_LEN 8
+#define DIGI_OUT_BUF_SIZE 8
+
+/* port input buffer length -- must be >= transfer buffer length - 3 */
+/* so we can be sure to hold at least one full buffer from one urb */
+#define DIGI_IN_BUF_SIZE 64
/* retry timeout while sleeping */
#define DIGI_RETRY_TIMEOUT (HZ/10)
/* ids */
#define DIGI_VENDOR_ID 0x05c5
-#define DIGI_ID 0x0004
+#define DIGI_2_ID 0x0002 /* USB-2 */
+#define DIGI_4_ID 0x0004 /* USB-4 */
/* commands
* "INB": can be used on the in-band endpoint
/* Structures */
-typedef struct digi_private {
- int dp_port_num;
+typedef struct digi_serial {
+ spinlock_t ds_serial_lock;
+ struct usb_serial_port *ds_oob_port; /* out-of-band port */
+ int ds_oob_port_num; /* index of out-of-band port */
+ int ds_device_started;
+} digi_serial_t;
+
+typedef struct digi_port {
spinlock_t dp_port_lock;
- int dp_buf_len;
- unsigned char dp_buf[DIGI_PORT_BUF_LEN];
+ int dp_port_num;
+ int dp_out_buf_len;
+ unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
+ int dp_in_buf_len;
+ unsigned char dp_in_buf[DIGI_IN_BUF_SIZE];
+ unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE];
unsigned int dp_modem_signals;
+ wait_queue_head_t dp_modem_change_wait;
int dp_open_count; /* inc on open, dec on close */
int dp_transmit_idle;
+ wait_queue_head_t dp_transmit_idle_wait;
+ int dp_throttled;
+ int dp_throttle_restart;
+ wait_queue_head_t dp_flush_wait;
int dp_in_close; /* close in progress */
wait_queue_head_t dp_close_wait; /* wait queue for close */
struct tq_struct dp_wakeup_task;
-} digi_private_t;
+} digi_port_t;
/* Local Function Declarations */
static void digi_wakeup_write( struct usb_serial_port *port );
static void digi_wakeup_write_lock( struct usb_serial_port *port );
-static int digi_write_oob_command( unsigned char *buf, int count );
+static int digi_write_oob_command( struct usb_serial_port *port,
+ unsigned char *buf, int count, int interruptible );
static int digi_write_inb_command( struct usb_serial_port *port,
- unsigned char *buf, int count ) __attribute__((unused));
+ unsigned char *buf, int count, unsigned long timeout );
static int digi_set_modem_signals( struct usb_serial_port *port,
- unsigned int modem_signals );
+ unsigned int modem_signals, int interruptible );
static int digi_transmit_idle( struct usb_serial_port *port,
unsigned long timeout );
static void digi_rx_throttle (struct usb_serial_port *port);
/* device info needed for the Digi serial converter */
static u16 digi_vendor_id = DIGI_VENDOR_ID;
-static u16 digi_product_id = DIGI_ID;
-
-/* out of band port */
-static int oob_port_num; /* index of out-of-band port */
-static struct usb_serial_port *oob_port; /* out-of-band port */
-static int device_startup = 0;
-
-spinlock_t startup_lock; /* used by startup_device */
-
-static wait_queue_head_t modem_change_wait;
-static wait_queue_head_t transmit_idle_wait;
+static u16 digi_product_2_id = DIGI_2_ID; /* USB 2 */
+static u16 digi_product_4_id = DIGI_4_ID; /* USB 4 */
+static struct usb_serial_device_type digi_acceleport_2_device = {
+ name: "Digi USB",
+ idVendor: &digi_vendor_id,
+ idProduct: &digi_product_2_id,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 0,
+ num_bulk_in: 4,
+ num_bulk_out: 4,
+ num_ports: 3,
+ open: digi_open,
+ close: digi_close,
+ write: digi_write,
+ write_room: digi_write_room,
+ write_bulk_callback: digi_write_bulk_callback,
+ read_bulk_callback: digi_read_bulk_callback,
+ chars_in_buffer: digi_chars_in_buffer,
+ throttle: digi_rx_throttle,
+ unthrottle: digi_rx_unthrottle,
+ ioctl: digi_ioctl,
+ set_termios: digi_set_termios,
+ break_ctl: digi_break_ctl,
+ startup: digi_startup,
+ shutdown: digi_shutdown,
+};
-/* Globals */
-
-struct usb_serial_device_type digi_acceleport_device = {
+static struct usb_serial_device_type digi_acceleport_4_device = {
name: "Digi USB",
idVendor: &digi_vendor_id,
- idProduct: &digi_product_id,
+ idProduct: &digi_product_4_id,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: MUST_HAVE,
needs_bulk_out: MUST_HAVE,
{
unsigned long flags;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
spin_lock_irqsave( &priv->dp_port_lock, flags );
* Write commands on the out of band port. Commands are 4
* bytes each, multiple commands can be sent at once, and
* no command will be split across USB packets. Returns 0
-* if successful, -EINTR if interrupted while sleeping, or
-* a negative error returned by usb_submit_urb.
+* if successful, -EINTR if interrupted while sleeping and
+* the interruptible flag is true, or a negative error
+* returned by usb_submit_urb.
*/
-static int digi_write_oob_command( unsigned char *buf, int count )
+static int digi_write_oob_command( struct usb_serial_port *port,
+ unsigned char *buf, int count, int interruptible )
{
int ret = 0;
int len;
- digi_private_t *oob_priv = (digi_private_t *)(oob_port->private);
+ struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
+ digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
unsigned long flags = 0;
-dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count );
+dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count );
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags );
- if( signal_pending(current) ) {
+ if( interruptible && signal_pending(current) ) {
return( -EINTR );
}
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
if( ret ) {
- dbg( "digi_write_oob_command: usb_submit_urb failed, ret=%d",
- ret );
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
+ ret );
}
return( ret );
*
* Write commands on the given port. Commands are 4
* bytes each, multiple commands can be sent at once, and
-* no command will be split across USB packets. Returns 0
-* if successful, or a negative error returned by digi_write.
+* no command will be split across USB packets. If timeout
+* is non-zero, write in band command will return after
+* waiting unsuccessfully for the URB status to clear for
+* timeout ticks. Returns 0 if successful, or a negative
+* error returned by digi_write.
*/
static int digi_write_inb_command( struct usb_serial_port *port,
- unsigned char *buf, int count )
+ unsigned char *buf, int count, unsigned long timeout )
{
int ret = 0;
int len;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned char *data = port->write_urb->transfer_buffer;
unsigned long flags = 0;
dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num,
count );
+ if( timeout )
+ timeout += jiffies;
+ else
+ timeout = ULONG_MAX;
+
spin_lock_irqsave( &priv->dp_port_lock, flags );
- while( count > 0 ) {
+ while( count > 0 && ret == 0 ) {
- while( port->write_urb->status == -EINPROGRESS ) {
+ while( port->write_urb->status == -EINPROGRESS
+ && jiffies < timeout ) {
cond_wait_interruptible_timeout_irqrestore(
&port->write_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
/* len must be a multiple of 4 and small enough to */
/* guarantee the write will send buffered data first, */
/* so commands are in order with data and not split */
- len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
+ len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
if( len > 4 )
len &= ~3;
/* write any buffered data first */
- if( priv->dp_buf_len > 0 ) {
+ if( priv->dp_out_buf_len > 0 ) {
data[0] = DIGI_CMD_SEND_DATA;
- data[1] = priv->dp_buf_len;
- memcpy( data+2, priv->dp_buf, priv->dp_buf_len );
- memcpy( data+2+priv->dp_buf_len, buf, len );
+ data[1] = priv->dp_out_buf_len;
+ memcpy( data+2, priv->dp_out_buf,
+ priv->dp_out_buf_len );
+ memcpy( data+2+priv->dp_out_buf_len, buf, len );
port->write_urb->transfer_buffer_length
- = priv->dp_buf_len+2+len;
+ = priv->dp_out_buf_len+2+len;
} else {
memcpy( data, buf, len );
port->write_urb->transfer_buffer_length = len;
}
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
count -= len;
buf += len;
}
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
if( ret ) {
- dbg( "digi_write_inb_command: usb_submit_urb failed, ret=%d",
- ret );
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, priv->dp_port_num );
}
return( ret );
*/
static int digi_set_modem_signals( struct usb_serial_port *port,
- unsigned int modem_signals )
+ unsigned int modem_signals, int interruptible )
{
int ret;
+ digi_port_t *port_priv = (digi_port_t *)port->private;
+ struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
+ digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
unsigned char *data = oob_port->write_urb->transfer_buffer;
- digi_private_t *port_priv = (digi_private_t *)(port->private);
- digi_private_t *oob_priv = (digi_private_t *)(oob_port->private);
unsigned long flags = 0;
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags );
- if( signal_pending(current) ) {
+ if( interruptible && signal_pending(current) ) {
return( -EINTR );
}
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
if( ret ) {
- dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d",
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
ret );
}
int ret;
unsigned char buf[2];
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned long flags = 0;
buf[0] = DIGI_CMD_TRANSMIT_IDLE;
buf[1] = 0;
- if( (ret=digi_write_inb_command( port, buf, 2 )) != 0 )
- return( ret );
-
timeout += jiffies;
+ if( (ret=digi_write_inb_command( port, buf, 2, timeout-jiffies )) != 0 )
+ return( ret );
+
spin_lock_irqsave( &priv->dp_port_lock, flags );
while( jiffies < timeout && !priv->dp_transmit_idle ) {
cond_wait_interruptible_timeout_irqrestore(
- &transmit_idle_wait, DIGI_RETRY_TIMEOUT,
+ &priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
if( signal_pending(current) ) {
return( -EINTR );
static void digi_rx_throttle( struct usb_serial_port *port )
{
-#ifdef DEBUG
- digi_private_t *priv = (digi_private_t *)(port->private);
-#endif
+ unsigned long flags;
+ digi_port_t *priv = (digi_port_t *)(port->private);
dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
- /* stop receiving characters. We just turn off the URB request, and
- let chars pile up in the device. If we're doing hardware
- flowcontrol, the device will signal the other end when its buffer
- fills up. If we're doing XON/XOFF, this would be a good time to
- send an XOFF, although it might make sense to foist that off
- upon the device too. */
-
- // usb_unlink_urb(port->interrupt_in_urb);
+ /* stop receiving characters by not resubmitting the read urb */
+ spin_lock_irqsave( &priv->dp_port_lock, flags );
+ priv->dp_throttled = 1;
+ priv->dp_throttle_restart = 0;
+ priv->dp_in_buf_len = 0;
+ spin_unlock_irqrestore( &priv->dp_port_lock, flags );
}
static void digi_rx_unthrottle( struct usb_serial_port *port )
{
-#ifdef DEBUG
- digi_private_t *priv = (digi_private_t *)(port->private);
-#endif
+ int ret = 0;
+ int len;
+ unsigned long flags;
+ digi_port_t *priv = (digi_port_t *)(port->private);
+ struct tty_struct *tty = port->tty;
dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
- /* just restart the receive interrupt URB */
- //if (usb_submit_urb(port->interrupt_in_urb))
- // dbg( "digi_rx_unthrottle: usb_submit_urb failed" );
+ spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+ /* send any buffered chars from throttle time on to tty subsystem */
+ len = MIN( priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
+ if( len > 0 ) {
+ memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len );
+ memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len );
+ tty->flip.char_buf_ptr += len;
+ tty->flip.flag_buf_ptr += len;
+ tty->flip.count += len;
+ tty_flip_buffer_push( tty );
+ }
+
+ /* restart read chain */
+ if( priv->dp_throttle_restart )
+ ret = usb_submit_urb( port->read_urb );
+
+ /* turn throttle off */
+ priv->dp_throttled = 0;
+ priv->dp_in_buf_len = 0;
+ priv->dp_throttle_restart = 0;
+
+ spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+ if( ret ) {
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, priv->dp_port_num );
+ }
}
struct termios *old_termios )
{
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned int iflag = port->tty->termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_iflag = old_termios->c_iflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned char buf[32];
+ unsigned int modem_signals;
int arg,ret;
int i = 0;
/* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag&CBAUD) == B0 ) {
/* don't set RTS if using hardware flow control */
- /* and throttling input -- not implemented yet */
- digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS );
+ /* and throttling input */
+ modem_signals = TIOCM_DTR;
+ if( !(port->tty->termios->c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &port->tty->flags) ) {
+ modem_signals |= TIOCM_RTS;
+ }
+ digi_set_modem_signals( port, modem_signals, 1 );
}
switch( (cflag&CBAUD) ) {
/* drop DTR and RTS on transition to B0 */
- case B0: digi_set_modem_signals( port, 0 ); break;
+ case B0: digi_set_modem_signals( port, 0, 1 ); break;
case B50: arg = DIGI_BAUD_50; break;
case B75: arg = DIGI_BAUD_75; break;
case B110: arg = DIGI_BAUD_110; break;
else
arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
- if( (cflag&CRTSCTS) )
+ if( (cflag&CRTSCTS) ) {
+
arg |= DIGI_INPUT_FLOW_CONTROL_RTS;
- else
+
+ /* On USB-4 it is necessary to assert RTS prior */
+ /* to selecting RTS input flow control. */
+ buf[i++] = DIGI_CMD_SET_RTS_SIGNAL;
+ buf[i++] = priv->dp_port_num;
+ buf[i++] = DIGI_RTS_ACTIVE;
+ buf[i++] = 0;
+
+ } else {
arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS;
+ }
buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
buf[i++] = priv->dp_port_num;
}
/* set output flow control */
- /*if( (iflag&IXON) != (old_iflag&IXON)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) )*/ {
+ if( (iflag&IXON) != (old_iflag&IXON)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
arg = 0;
else
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
- if( (cflag&CRTSCTS) )
+ if( (cflag&CRTSCTS) ) {
arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
- else
+ } else {
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
+ port->tty->hw_stopped = 0;
+ }
buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
buf[i++] = priv->dp_port_num;
}
- if( (ret=digi_write_oob_command( buf, i )) != 0 )
+ if( (ret=digi_write_oob_command( port, buf, i, 1 )) != 0 )
dbg( "digi_set_termios: write oob failed, ret=%d", ret );
}
static void digi_break_ctl( struct usb_serial_port *port, int break_state )
{
-#ifdef DEBUG
- digi_private_t *priv = (digi_private_t *)(port->private);
-#endif
+ unsigned char buf[4];
-dbg( "digi_break_ctl: TOP: port=%d", priv->dp_port_num );
+ buf[0] = DIGI_CMD_BREAK_CONTROL;
+ buf[1] = 2; /* length */
+ buf[2] = break_state ? 1 : 0;
+ buf[3] = 0; /* pad */
+
+ digi_write_inb_command( port, buf, 4, 0 );
}
unsigned int cmd, unsigned long arg )
{
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned int val;
unsigned long flags = 0;
else if( cmd == TIOCMBIC )
val = priv->dp_modem_signals & ~val;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return( digi_set_modem_signals( port, val ) );
+ return( digi_set_modem_signals( port, val, 1 ) );
case TIOCMIWAIT:
/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
{
int ret,data_len,new_len;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned char *data = port->write_urb->transfer_buffer;
unsigned char user_buf[64]; /* 64 bytes is max USB bulk packet */
unsigned long flags = 0;
/* buffer data if count is 1 (probably put_char) if possible */
if( count == 1 ) {
new_len = MIN( count,
- DIGI_PORT_BUF_LEN-priv->dp_buf_len );
- memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len );
- priv->dp_buf_len += new_len;
+ DIGI_OUT_BUF_SIZE-priv->dp_out_buf_len );
+ memcpy( priv->dp_out_buf+priv->dp_out_buf_len, buf,
+ new_len );
+ priv->dp_out_buf_len += new_len;
} else {
new_len = 0;
}
/* allow space for any buffered data and for new data, up to */
/* transfer buffer size - 2 (for command and length bytes) */
- new_len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
- data_len = new_len + priv->dp_buf_len;
+ new_len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
+ data_len = new_len + priv->dp_out_buf_len;
if( data_len == 0 ) {
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
*data++ = data_len;
/* copy in buffered data first */
- memcpy( data, priv->dp_buf, priv->dp_buf_len );
- data += priv->dp_buf_len;
+ memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len );
+ data += priv->dp_out_buf_len;
/* copy in new data */
memcpy( data, from_user ? user_buf : buf, new_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
ret = new_len;
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
}
/* return length of new data written, or error */
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
if( ret < 0 ) {
- dbg( "digi_write: usb_submit_urb failed, ret=%d", ret );
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, priv->dp_port_num );
}
+
dbg( "digi_write: returning %d", ret );
return( ret );
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial;
- digi_private_t *priv;
+ digi_port_t *priv;
int ret = 0;
-dbg( "digi_write_bulk_callback: TOP" );
+dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
- /* port sanity check */
- if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) {
+ /* port and serial sanity check */
+ if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
err( __FUNCTION__ ": port or port->private is NULL, status=%d",
urb->status );
return;
}
+ serial = port->serial;
+ if( serial == NULL || serial->private == NULL ) {
+ err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status );
+ return;
+ }
/* handle oob callback */
- if( priv->dp_port_num == oob_port_num ) {
+ if( priv->dp_port_num
+ == ((digi_serial_t *)(serial->private))->ds_oob_port_num ) {
dbg( "digi_write_bulk_callback: oob callback" );
spin_lock( &priv->dp_port_lock );
wake_up_interruptible( &port->write_wait );
return;
}
- /* sanity checks */
- if( port_paranoia_check( port, "digi_write_bulk_callback" ) )
- return;
- serial = port->serial;
- if( serial_paranoia_check( serial, "digi_write_bulk_callback" ) )
+ /* further sanity checks */
+ if( port_paranoia_check( port, __FUNCTION__ )
+ || serial_paranoia_check( serial, __FUNCTION__ ) )
return;
- /* try to send any buffered data on this port */
+ /* try to send any buffered data on this port, if it is open */
spin_lock( &priv->dp_port_lock );
- if( port->write_urb->status != -EINPROGRESS && priv->dp_buf_len > 0 ) {
+ if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS
+ && priv->dp_out_buf_len > 0 ) {
*((unsigned char *)(port->write_urb->transfer_buffer))
= (unsigned char)DIGI_CMD_SEND_DATA;
*((unsigned char *)(port->write_urb->transfer_buffer)+1)
- = (unsigned char)priv->dp_buf_len;
+ = (unsigned char)priv->dp_out_buf_len;
- port->write_urb->transfer_buffer_length = priv->dp_buf_len+2;
+ port->write_urb->transfer_buffer_length
+ = priv->dp_out_buf_len+2;
- memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
- priv->dp_buf_len );
+ memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf,
+ priv->dp_out_buf_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
}
}
{
int room;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned long flags = 0;
if( port->write_urb->status == -EINPROGRESS )
room = 0;
else
- room = port->bulk_out_size - 2 - priv->dp_buf_len;
+ room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
static int digi_chars_in_buffer( struct usb_serial_port *port )
{
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
if( port->write_urb->status == -EINPROGRESS ) {
/* return( port->bulk_out_size - 2 ); */
return( 256 );
} else {
-dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_buf_len );
- return( priv->dp_buf_len );
+dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len );
+ return( priv->dp_out_buf_len );
}
}
int ret;
unsigned char buf[32];
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
struct termios not_termios;
unsigned long flags = 0;
return( -EAGAIN );
}
+ /* inc module use count before sleeping to wait for closes */
+ ++priv->dp_open_count;
+ MOD_INC_USE_COUNT;
+
/* wait for a close in progress to finish */
while( priv->dp_in_close ) {
cond_wait_interruptible_timeout_irqrestore(
&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
if( signal_pending(current) ) {
+ --priv->dp_open_count;
+ MOD_DEC_USE_COUNT;
return( -EINTR );
}
spin_lock_irqsave( &priv->dp_port_lock, flags );
/* if port is already open, just return */
/* be sure exactly one open proceeds */
if( port->active ) {
- ++priv->dp_open_count;
- MOD_INC_USE_COUNT;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
return( 0 );
}
- /* open is certain */
+ /* first open, mark port as active */
port->active = 1;
- ++priv->dp_open_count;
- MOD_INC_USE_COUNT;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
/* read modem signals automatically whenever they change */
buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
buf[7] = 0;
- if( (ret=digi_write_oob_command( buf, 8 )) != 0 )
+ if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 )
dbg( "digi_open: write oob failed, ret=%d", ret );
/* set termios settings */
digi_set_termios( port, ¬_termios );
/* set DTR and RTS */
- digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS );
+ digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 );
return( 0 );
int ret;
unsigned char buf[32];
struct tty_struct *tty = port->tty;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)port->private;
unsigned long flags = 0;
}
/* drop DTR and RTS */
- digi_set_modem_signals( port, 0 );
+ digi_set_modem_signals( port, 0, 0 );
/* disable input flow control */
buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
buf[10] = DIGI_DISABLE;
buf[11] = 0;
- /* flush fifos */
- buf[12] = DIGI_CMD_IFLUSH_FIFO;
+ /* disable receive */
+ buf[12] = DIGI_CMD_RECEIVE_ENABLE;
buf[13] = priv->dp_port_num;
- buf[14] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+ buf[14] = DIGI_DISABLE;
buf[15] = 0;
- /* disable receive */
- buf[16] = DIGI_CMD_RECEIVE_ENABLE;
+ /* flush fifos */
+ buf[16] = DIGI_CMD_IFLUSH_FIFO;
buf[17] = priv->dp_port_num;
- buf[18] = DIGI_DISABLE;
+ buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
buf[19] = 0;
- if( (ret=digi_write_oob_command( buf, 20 )) != 0 )
+ if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )
dbg( "digi_close: write oob failed, ret=%d", ret );
/* wait for final commands on oob port to complete */
- while( oob_port->write_urb->status == -EINPROGRESS ) {
- interruptible_sleep_on_timeout( &oob_port->write_wait,
- DIGI_RETRY_TIMEOUT );
- if( signal_pending(current) ) {
- break;
- }
- }
+ interruptible_sleep_on_timeout( &priv->dp_flush_wait,
+ DIGI_CLOSE_TIMEOUT );
/* shutdown any outstanding bulk writes */
usb_unlink_urb (port->write_urb);
{
int i,ret = 0;
+ digi_serial_t *serial_priv = (digi_serial_t *)serial->private;
+ struct usb_serial_port *port;
/* be sure this happens exactly once */
- spin_lock( &startup_lock );
- if( device_startup ) {
- spin_unlock( &startup_lock );
+ spin_lock( &serial_priv->ds_serial_lock );
+ if( serial_priv->ds_device_started ) {
+ spin_unlock( &serial_priv->ds_serial_lock );
return( 0 );
}
- device_startup = 1;
- spin_unlock( &startup_lock );
+ serial_priv->ds_device_started = 1;
+ spin_unlock( &serial_priv->ds_serial_lock );
/* start reading from each bulk in endpoint for the device */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ /* set USB_DISABLE_SPD flag for write bulk urbs */
+ for( i=0; i<serial->type->num_ports+1; i++ ) {
- if( (ret=usb_submit_urb(serial->port[i].read_urb)) != 0 ) {
- dbg( "digi_startup_device: usb_submit_urb failed, port=%d, ret=%d",
- i, ret );
+ port = &serial->port[i];
+
+ port->write_urb->transfer_flags |= USB_DISABLE_SPD;
+
+ if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
+ err(
+ __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, i );
break;
}
{
int i;
- digi_private_t *priv;
+ digi_port_t *priv;
+ digi_serial_t *serial_priv;
dbg( "digi_startup: TOP" );
- spin_lock_init( &startup_lock );
- init_waitqueue_head( &modem_change_wait );
- init_waitqueue_head( &transmit_idle_wait );
-
/* allocate the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ for( i=0; i<serial->type->num_ports+1; i++ ) {
serial->port[i].active = 0;
- /* allocate private structure */
+ /* allocate port private structure */
priv = serial->port[i].private =
- (digi_private_t *)kmalloc( sizeof(digi_private_t),
+ (digi_port_t *)kmalloc( sizeof(digi_port_t),
GFP_KERNEL );
- if( priv == (digi_private_t *)0 )
+ if( priv == (digi_port_t *)0 ) {
+ while( --i >= 0 )
+ kfree( serial->port[i].private );
return( 1 ); /* error */
+ }
- /* initialize private structure */
+ /* initialize port private structure */
+ spin_lock_init( &priv->dp_port_lock );
priv->dp_port_num = i;
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
+ priv->dp_in_buf_len = 0;
priv->dp_modem_signals = 0;
+ init_waitqueue_head( &priv->dp_modem_change_wait );
priv->dp_open_count = 0;
priv->dp_transmit_idle = 0;
+ init_waitqueue_head( &priv->dp_transmit_idle_wait );
+ priv->dp_throttled = 0;
+ priv->dp_throttle_restart = 0;
+ init_waitqueue_head( &priv->dp_flush_wait );
priv->dp_in_close = 0;
init_waitqueue_head( &priv->dp_close_wait );
priv->dp_wakeup_task.next = NULL;
priv->dp_wakeup_task.sync = 0;
priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock;
priv->dp_wakeup_task.data = (void *)(&serial->port[i]);
- spin_lock_init( &priv->dp_port_lock );
/* initialize write wait queue for this port */
- init_waitqueue_head(&serial->port[i].write_wait);
+ init_waitqueue_head( &serial->port[i].write_wait );
+
+ }
+ /* allocate serial private structure */
+ serial_priv = serial->private =
+ (digi_serial_t *)kmalloc( sizeof(digi_serial_t),
+ GFP_KERNEL );
+ if( serial_priv == (digi_serial_t *)0 ) {
+ for( i=0; i<serial->type->num_ports+1; i++ )
+ kfree( serial->port[i].private );
+ return( 1 ); /* error */
}
- /* initialize out of band port info */
- oob_port_num = digi_acceleport_device.num_ports;
- oob_port = &serial->port[oob_port_num];
- device_startup = 0;
+ /* initialize serial private structure */
+ spin_lock_init( &serial_priv->ds_serial_lock );
+ serial_priv->ds_oob_port_num = serial->type->num_ports;
+ serial_priv->ds_oob_port = &serial->port[serial_priv->ds_oob_port_num];
+ serial_priv->ds_device_started = 0;
return( 0 );
{
int i;
- digi_private_t *priv;
+ digi_port_t *priv;
unsigned long flags;
dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
/* stop reads and writes on all ports */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ for( i=0; i<serial->type->num_ports+1; i++ ) {
usb_unlink_urb( serial->port[i].read_urb );
usb_unlink_urb( serial->port[i].write_urb );
}
- device_startup = 0;
-
/* dec module use count */
- for( i=0; i<digi_acceleport_device.num_ports; i++ ) {
+ for( i=0; i<serial->type->num_ports; i++ ) {
priv = serial->port[i].private;
spin_lock_irqsave( &priv->dp_port_lock, flags );
while( priv->dp_open_count > 0 ) {
/* free the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ )
+ for( i=0; i<serial->type->num_ports+1; i++ )
kfree( serial->port[i].private );
+ kfree( serial->private );
}
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- digi_private_t *priv;
+ digi_port_t *priv;
int ret;
dbg( "digi_read_bulk_callback: TOP" );
/* port sanity check, do not resubmit if port is not valid */
- if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) {
+ if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
err( __FUNCTION__ ": port or port->private is NULL, status=%d",
urb->status );
return;
}
+ if( port->serial == NULL
+ || serial_paranoia_check( port->serial, __FUNCTION__ )
+ || port->serial->private == NULL ) {
+ err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status );
+ return;
+ }
/* do not resubmit urb if it has any status error */
if( urb->status ) {
}
/* handle oob or inb callback, do not resubmit if error */
- if( priv->dp_port_num == oob_port_num ) {
+ if( priv->dp_port_num
+ == ((digi_serial_t *)(port->serial->private))->ds_oob_port_num ) {
if( digi_read_oob_callback( urb ) != 0 )
return;
} else {
*
* Digi Read INB Callback handles reads on the in band ports, sending
* the data on to the tty subsystem. When called we know port and
-* port->private are not NULL. It returns 0 if successful, and -1 if
-* the sanity checks failed.
+* port->private are not NULL and port->serial has been validated.
+* It returns 0 if successful, 1 if successful but the port is
+* throttled, and -1 if the sanity checks failed.
*/
static int digi_read_inb_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = port->serial;
struct tty_struct *tty = port->tty;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
int opcode = ((unsigned char *)urb->transfer_buffer)[0];
int len = ((unsigned char *)urb->transfer_buffer)[1];
int status = ((unsigned char *)urb->transfer_buffer)[2];
unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;
- int i;
+ int flag,throttled;
- /* sanity checks */
- if( port_paranoia_check( port, __FUNCTION__ )
- || serial_paranoia_check( serial, __FUNCTION__ ) )
+ /* sanity check */
+ if( port_paranoia_check( port, __FUNCTION__ ) )
return( -1 );
- /* short packet check */
+ /* do not process callbacks on closed ports */
+ /* but do continue the read chain */
+ if( priv->dp_open_count == 0 )
+ return( 0 );
+
+ /* short/multiple packet check */
if( urb->actual_length != len + 2 ) {
- err( __FUNCTION__ ": INCOMPLETE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
+ err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
return( -1 );
}
+ spin_lock( &priv->dp_port_lock );
+
+ /* check for throttle; if set, do not resubmit read urb */
+ /* indicate the read chain needs to be restarted on unthrottle */
+ throttled = priv->dp_throttled;
+ if( throttled )
+ priv->dp_throttle_restart = 1;
+
/* receive data */
- if( opcode == DIGI_CMD_RECEIVE_DATA && urb->actual_length > 3 ) {
- len = MIN( len, urb->actual_length-3 );
- for( i=0; i<len; ++i ) {
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
+ if( opcode == DIGI_CMD_RECEIVE_DATA ) {
+
+ /* get flag from status */
+ flag = 0;
+
+ /* overrun is special, not associated with a char */
+ if( status & DIGI_OVERRUN_ERROR ) {
+ tty_insert_flip_char( tty, 0, TTY_OVERRUN );
+ }
+
+ /* break takes precedence over parity, */
+ /* which takes precedence over framing errors */
+ if( status & DIGI_BREAK_ERROR ) {
+ flag = TTY_BREAK;
+ } else if( status & DIGI_PARITY_ERROR ) {
+ flag = TTY_PARITY;
+ } else if( status & DIGI_FRAMING_ERROR ) {
+ flag = TTY_FRAME;
+ }
+
+ /* data length is len-1 (one byte of len is status) */
+ --len;
+
+ if( throttled ) {
+
+ len = MIN( len,
+ DIGI_IN_BUF_SIZE - priv->dp_in_buf_len );
+
+ if( len > 0 ) {
+ memcpy( priv->dp_in_buf + priv->dp_in_buf_len,
+ data, len );
+ memset( priv->dp_in_flag_buf
+ + priv->dp_in_buf_len, flag, len );
+ priv->dp_in_buf_len += len;
+ }
+
+ } else {
+
+ len = MIN( len, TTY_FLIPBUF_SIZE - tty->flip.count );
+
+ if( len > 0 ) {
+ memcpy( tty->flip.char_buf_ptr, data, len );
+ memset( tty->flip.flag_buf_ptr, flag, len );
+ tty->flip.char_buf_ptr += len;
+ tty->flip.flag_buf_ptr += len;
+ tty->flip.count += len;
+ tty_flip_buffer_push( tty );
+ }
+
+ }
+
}
- return( 0 );
+ spin_unlock( &priv->dp_port_lock );
+
+ if( opcode == DIGI_CMD_RECEIVE_DISABLE ) {
+ dbg( __FUNCTION__ ": got RECEIVE_DISABLE" );
+ } else if( opcode != DIGI_CMD_RECEIVE_DATA ) {
+ dbg( __FUNCTION__ ": unknown opcode: %d", opcode );
+ }
+
+ return( throttled ? 1 : 0 );
}
* Digi Read OOB Callback
*
* Digi Read OOB Callback handles reads on the out of band port.
-* When called we know port and port->private are not NULL. It
-* returns 0 if successful, and -1 if the sanity checks failed.
+* When called we know port and port->private are not NULL and
+* the port->serial is valid. It returns 0 if successful, and
+* -1 if the sanity checks failed.
*/
static int digi_read_oob_callback( struct urb *urb )
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
int opcode, line, status, val;
int i;
-dbg( "digi_read_oob_callback: len=%d", urb->actual_length );
-
- /* sanity check */
- if( serial == NULL ) {
- err( __FUNCTION__ ": port->serial is NULL, status=%d, port=%d",
- urb->status, priv->dp_port_num );
- return( -1 );
- }
+dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num,
+urb->actual_length );
/* handle each oob command */
for( i=0; i<urb->actual_length-3; ) {
status = ((unsigned char *)urb->transfer_buffer)[i++];
val = ((unsigned char *)urb->transfer_buffer)[i++];
-dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, line, status, val );
+dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
+opcode, line, status, val );
- if( status != 0 )
+ if( status != 0 || line >= serial->type->num_ports )
continue;
- if( (priv=serial->port[line].private) == NULL ) {
- dbg( __FUNCTION__ ": port[%d].private is NULL!", line );
- continue;
- }
+ port = &serial->port[line];
+
+ if( port_paranoia_check( port, __FUNCTION__ )
+ || (priv=port->private) == NULL )
+ return( -1 );
if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) {
spin_lock( &priv->dp_port_lock );
/* convert from digi flags to termiox flags */
- if( val & DIGI_READ_INPUT_SIGNALS_CTS )
+ if( val & DIGI_READ_INPUT_SIGNALS_CTS ) {
priv->dp_modem_signals |= TIOCM_CTS;
- else
+ /* port must be open to use tty struct */
+ if( priv->dp_open_count
+ && port->tty->termios->c_cflag & CRTSCTS ) {
+ port->tty->hw_stopped = 0;
+ digi_wakeup_write( port );
+ }
+ } else {
priv->dp_modem_signals &= ~TIOCM_CTS;
+ /* port must be open to use tty struct */
+ if( priv->dp_open_count
+ && port->tty->termios->c_cflag & CRTSCTS ) {
+ port->tty->hw_stopped = 1;
+ }
+ }
if( val & DIGI_READ_INPUT_SIGNALS_DSR )
priv->dp_modem_signals |= TIOCM_DSR;
else
else
priv->dp_modem_signals &= ~TIOCM_CD;
- wake_up_interruptible( &modem_change_wait );
+ wake_up_interruptible( &priv->dp_modem_change_wait );
spin_unlock( &priv->dp_port_lock );
} else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) {
spin_lock( &priv->dp_port_lock );
priv->dp_transmit_idle = 1;
- wake_up_interruptible( &transmit_idle_wait );
+ wake_up_interruptible( &priv->dp_transmit_idle_wait );
spin_unlock( &priv->dp_port_lock );
+ } else if( opcode == DIGI_CMD_IFLUSH_FIFO ) {
+
+ wake_up_interruptible( &priv->dp_flush_wait );
+
}
}
int digi_init (void)
{
- usb_serial_register (&digi_acceleport_device);
+ usb_serial_register (&digi_acceleport_2_device);
+ usb_serial_register (&digi_acceleport_4_device);
return 0;
}
void digi_exit (void)
{
- usb_serial_deregister (&digi_acceleport_device);
+ usb_serial_deregister (&digi_acceleport_2_device);
+ usb_serial_deregister (&digi_acceleport_4_device);
}
module_init(digi_init);
module_exit(digi_exit);
+
MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>");
MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver");
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (08/08/2000) gkh
+ * Added open_count to port structure.
+ *
* (07/23/2000) gkh
* Added bulk_out_endpointAddress to port structure.
*
wait_queue_head_t write_wait;
struct tq_struct tqueue; /* task queue for line discipline waking up */
+ int open_count; /* number of times this port has been opened */
void * private; /* data private to the specific port */
};
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (08/08/2000) gkh
+ * Fixed endian problem in visor_startup.
+ * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
+ * than once.
+ *
* (07/23/2000) gkh
* Added pool of write urbs to speed up transfers to the visor.
*
static void visor_throttle (struct usb_serial_port *port);
static void visor_unthrottle (struct usb_serial_port *port);
static int visor_startup (struct usb_serial *serial);
+static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios);
static void visor_write_bulk_callback (struct urb *urb);
throttle: visor_throttle,
unthrottle: visor_unthrottle,
startup: visor_startup,
+ shutdown: visor_shutdown,
ioctl: visor_ioctl,
set_termios: visor_set_termios,
write: visor_write,
return -EINVAL;
}
- port->active = 1;
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ if (!port->active) {
+ port->active = 1;
- return (0);
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+ }
+
+ return 0;
}
dbg(__FUNCTION__ " - port %d", port->number);
- if (!transfer_buffer) {
- err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
- } else {
- /* send a shutdown message to the device */
- usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
- 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
- kfree (transfer_buffer);
- }
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+
+ if (port->open_count <= 0) {
+ if (!transfer_buffer) {
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+ } else {
+ /* send a shutdown message to the device */
+ usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
+ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ kfree (transfer_buffer);
+ }
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
+ /* shutdown our bulk read */
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+ port->open_count = 0;
+ }
}
} else {
struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
char *string;
+
+ le16_to_cpus(&connection_info->num_ports);
info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
for (i = 0; i < connection_info->num_ports; ++i) {
switch (connection_info->connections[i].port_function_id) {
}
+static void visor_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ visor_close (&serial->port[i], NULL);
+ }
+ }
+}
+
+
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/usb.h>
/*
int uhci_init(void);
int ohci_hcd_init(void);
-#ifdef MODULE
-
/*
* Cleanup
*/
-void cleanup_module(void)
+static void __exit usb_exit(void)
{
usb_major_cleanup();
usbdevfs_cleanup();
* Init
*/
-int init_module(void)
-#else
-int usb_init(void)
-#endif
+static int __init usb_init(void)
{
usb_major_init();
usbdevfs_init();
#endif
return 0;
}
+
+module_init(usb_init);
+module_exit(usb_exit);
(OHCI_CTRL_CBSR & 0x3) \
| OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
-static DECLARE_WAIT_QUEUE_HEAD (op_wakeup);
static LIST_HEAD (ohci_hcd_list);
static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
{
unsigned long flags;
ohci_t * ohci;
- DECLARE_WAITQUEUE (wait, current);
if (!urb) /* just to be sure */
return -EINVAL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+ DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
+ DECLARE_WAITQUEUE (wait, current);
+
usb_dec_dev_use (urb->dev);
- add_wait_queue (&op_wakeup, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
/* wait until all TDs are deleted */
- if (!schedule_timeout (HZ / 10))
- err("unlink URB timeout!");
- remove_wait_queue (&op_wakeup, &wait);
+ add_wait_queue (&unlink_wakeup, &wait);
+ urb_priv->wait = &unlink_wakeup;
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule ();
+ remove_wait_queue (&unlink_wakeup, &wait);
urb->status = -ENOENT;
+ urb_priv->wait = 0;
} else {
/* usb_dec_dev_use done in dl_del_list() */
urb->status = -EINPROGRESS;
unsigned long flags;
int i, cnt = 0;
ed_t * ed;
- DECLARE_WAITQUEUE (wait, current);
struct ohci_device * dev = usb_to_ohci (usb_dev);
ohci_t * ohci = usb_dev->bus->hcpriv;
if (usb_dev->devnum >= 0) {
- /* delete all TDs of all EDs */
+ /* driver disconnects should have unlinked all urbs
+ * (freeing all the TDs, unlinking EDs) but we need
+ * to defend against bugs that prevent that.
+ */
spin_lock_irqsave (&usb_ed_lock, flags);
for(i = 0; i < NUM_EDS; i++) {
ed = &(dev->ed[i]);
if (ed->state != ED_NEW) {
- if (ed->state == ED_OPER)
+ if (ed->state == ED_OPER) {
+ /* driver on that interface didn't unlink an urb */
+ dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",
+ ohci->ohci_dev->slot_name, usb_dev->devnum, i);
ep_unlink (ohci, ed);
+ }
ep_rm_ed (usb_dev, ed);
ed->state = ED_DEL;
cnt++;
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
+ /* if the controller is running, tds for those unlinked
+ * urbs get freed by dl_del_list at the next SF interrupt
+ */
if (cnt > 0) {
if (ohci->disabled) {
warn ("TD leak, %d", cnt);
} else if (!in_interrupt ()) {
+ DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup);
+ DECLARE_WAITQUEUE (wait, current);
+
/* SF interrupt handler calls dl_del_list */
- add_wait_queue (&op_wakeup, &wait);
+ add_wait_queue (&freedev_wakeup, &wait);
+ dev->wait = &freedev_wakeup;
current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout (HZ / 10);
- remove_wait_queue (&op_wakeup, &wait);
+ schedule ();
+ remove_wait_queue (&freedev_wakeup, &wait);
} else {
- /* drivers mustn't expect this to work */
- err ("can't free tds, interrupt context");
+ /* likely some interface's driver has a refcount bug */
+ err ("bus %s devnum %d deletion in interrupt",
+ ohci->ohci_dev->slot_name, usb_dev->devnum);
+ BUG ();
}
}
}
#endif
break;
- case ISO:
- if (ohci->ed_isotail == ed)
- ohci->ed_isotail = ed->ed_prev;
+ case ISO:
+ if (ohci->ed_isotail == ed)
+ ohci->ed_isotail = ed->ed_prev;
if (ed->hwNextED != 0)
- ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-
+ ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+
if (ed->ed_prev != NULL) {
ed->ed_prev->hwNextED = ed->hwNextED;
} else {
- for (i = 0; i < 32; i += inter) {
- inter = 1;
+ for (i = 0; i < 32; i++) {
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]);
- *ed_p != 0;
- ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
- inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
- if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
+ *ed_p != 0;
+ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
+ // inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+ if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ }
}
}
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_ISO");
#endif
break;
- }
- ed->state = ED_UNLINK;
- return 0;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
}
tdINFO = le32_to_cpup (&td->hwINFO);
if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td);
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
- if(++ (urb_priv->td_cnt) == urb_priv->length)
+ /* URB is done; clean up */
+ if (++(urb_priv->td_cnt) == urb_priv->length) {
+ void *condition = urb_priv->wait;
+
urb_rm_priv (urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
usb_dec_dev_use (urb->dev);
urb->status = -ECONNRESET;
urb->complete (urb);
- } else {
- wake_up (&op_wakeup);
+ } else if (condition) {
+ /* unblock sohci_unlink_urb */
+ wake_up (condition);
}
+ }
} else {
td_p = &td->hwNextTD;
}
-
}
+
if (ed->state & ED_DEL) { /* set by sohci_free_dev */
struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
- OHCI_FREE (tdTailP); /* free dummy td */
+ OHCI_FREE (tdTailP); /* free dummy td */
ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
ed->state = ED_NEW;
/* if all eds are removed wake up sohci_free_dev */
- if (!--dev->ed_cnt)
- wake_up (&op_wakeup);
+ if (!--dev->ed_cnt && dev->wait)
+ wake_up (dev->wait);
}
else {
ed->state &= ~ED_URB_DEL;
/* start controller operations */
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
writel (ohci->hc_control, &ohci->regs->control);
/* Choose the interrupts we care about now, others later on demand */
writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
&ohci->regs->roothub.a);
writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
-#endif /* OHCI_USE_NPS */
/* connect the virtual root hub */
ohci->rh.devnum = 0;
usb_dev = usb_alloc_dev (NULL, ohci->bus);
- if (!usb_dev)
+ if (!usb_dev) {
+ ohci->disabled = 1;
return -ENOMEM;
+ }
dev = usb_to_ohci (usb_dev);
ohci->bus->root_hub = usb_dev;
usb_connect (usb_dev);
if (usb_new_device (usb_dev) != 0) {
usb_free_dev (usb_dev);
+ ohci->disabled = 1;
return -ENODEV;
}
- ohci->disabled = 0;
return 0;
}
/* allocate OHCI */
-static ohci_t * __devinit hc_alloc_ohci (void * mem_base)
+static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
{
ohci_t * ohci;
struct usb_bus * bus;
memset (ohci, 0, sizeof (ohci_t));
+ ohci->disabled = 1;
ohci->irq = -1;
ohci->regs = mem_base;
+ ohci->ohci_dev = dev;
+ dev->driver_data = ohci;
+
+ INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+ list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+
bus = usb_alloc_bus (&sohci_device_operations);
if (!bus) {
kfree (ohci);
ohci->bus = bus;
bus->hcpriv = (void *) ohci;
- ohci->disabled = 1;
-
+
return ohci;
}
hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
{
ohci_t * ohci;
+ u8 latency, limit;
char buf[8], *bufp = buf;
#ifndef __sparc__
(unsigned long) mem_base, bufp);
printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
- ohci = hc_alloc_ohci (mem_base);
+ ohci = hc_alloc_ohci (dev, mem_base);
if (!ohci) {
return -ENOMEM;
}
- ohci->ohci_dev = dev;
- dev->driver_data = ohci;
- INIT_LIST_HEAD (&ohci->ohci_hcd_list);
- list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+ /* bad pci latencies can contribute to overruns */
+ pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+ if (latency) {
+ pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
+ if (limit && limit < latency) {
+ dbg ("PCI latency reduced to max %d", limit);
+ pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
+ ohci->pci_latency = limit;
+ } else {
+ /* it might already have been reduced */
+ ohci->pci_latency = latency;
+ }
+ }
if (hc_reset (ohci) < 0) {
hc_release_ohci (ohci);
if (request_irq (irq, hc_interrupt, SA_SHIRQ,
ohci_pci_driver.name, ohci) != 0) {
- err ("request interrupt %d failed", irq);
+ err ("request interrupt %s failed", bufp);
hc_release_ohci (ohci);
return -EBUSY;
}
int temp;
int i;
+ if (ohci->pci_latency)
+ pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
+
ohci->disabled = 1;
if (ohci->bus->root_hub)
usb_disconnect (&ohci->bus->root_hub);
ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned long mem_resource, mem_len;
- u8 latency, limit;
void *mem_base;
if (pci_enable_device(dev) < 0)
/* controller writes into our memory */
pci_set_master (dev);
- pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
- if (latency) {
- pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
- if (limit && limit < latency) {
- dbg ("PCI latency reduced to max %d", limit);
- pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
- }
- }
return hc_found_ohci (dev, dev->irq, mem_base);
}
ohci->disabled ? " (disabled)" : "",
in_interrupt () ? " in interrupt" : ""
);
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
/* don't wake up sleeping controllers, or block in interrupt context */
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {
ohci_t *ohci = (ohci_t *) dev->driver_data;
int temp;
+ /* guard against multiple resumes */
+ atomic_inc (&ohci->resume_count);
+ if (atomic_read (&ohci->resume_count) != 1) {
+ err ("concurrent PCI resumes for usb-%s", dev->slot_name);
+ atomic_dec (&ohci->resume_count);
+ return;
+ }
+
/* did we suspend, or were we powered off? */
ohci->hc_control = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS;
default:
warn ("odd PCI resume for usb-%s", dev->slot_name);
}
+
+ /* controller is operational, extra resumes are harmless */
+ atomic_dec (&ohci->resume_count);
}
#endif /* CONFIG_PM */
int irq;
int disabled; /* e.g. got a UE, we're hung */
+ atomic_t resume_count; /* defending against multiple resumes */
struct ohci_regs * regs; /* OHCI controller's memory */
struct list_head ohci_hcd_list; /* list of all ohci_hcd */
struct usb_bus * bus;
struct usb_device * dev[128];
struct virt_root_hub rh;
- struct pci_dev *ohci_dev;
+
+ /* PCI device handle and settings */
+ struct pci_dev *ohci_dev;
+ u8 pci_latency;
} ohci_t;
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: usb-uhci.c,v 1.236 2000/08/02 20:28:28 acher Exp $
+ * $Id: usb-uhci.c,v 1.237 2000/08/08 14:58:17 acher Exp $
*/
#include <linux/config.h>
/* This enables an extra UHCI slab for memory debugging */
#define DEBUG_SLAB
-#define VERSTR "$Revision: 1.236 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.237 $ time " __TIME__ " " __DATE__
#include <linux/usb.h>
#include "usb-uhci.h"
data += pktsze;
len -= pktsze;
- last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || (urb->transfer_flags & USB_DISABLE_SPD)));
+ last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_DISABLE_SPD)));
if (last)
td->hw.td.status |= TD_CTRL_IOC; // last one generates INT
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/fb.h>
-#include <linux/wrapper.h>
#include <asm/hardware.h>
#include <asm/io.h>
virtual_end = PAGE_ALIGN(virtual_end);
while (virtual_start < virtual_end) {
+ struct page *page;
+
/*
* Clear page reserved bit,
* set count to 1, and free
* the page.
*/
- mem_map_unreserve(virt_to_page(virtual_start));
- atomic_set(&virt_to_page(virtual_start)->count, 1);
+ page = virt_to_page(virtual_start);
+ ClearPageReserved(page);
+ atomic_set(&page->count, 1);
free_page(virtual_start);
virtual_start += PAGE_SIZE;
for (page = current_par.screen_base;
page < PAGE_ALIGN(current_par.screen_base + size);
page += PAGE_SIZE)
- mem_map_reserve(virt_to_page(page));
+ SetPageReserved(virt_to_page(page));
/* Hand back any excess pages that we allocated. */
for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE)
free_page(page);
/*
* Code Status:
- * 4/1/99 - Driver appears to be working for Brutus 320x200x8bpp mode. Other
- * resolutions are working, but only the 8bpp mode is supported.
- * Changes need to be made to the palette encode and decode routines
- * to support 4 and 16 bpp modes.
- * Driver is not designed to be a module. The FrameBuffer is statically
- * allocated since dynamic allocation of a 300k buffer cannot be guaranteed.
- *
- * 6/17/99 - FrameBuffer memory is now allocated at run-time when the
- * driver is initialized.
+ * 1999/04/01:
+ * Driver appears to be working for Brutus 320x200x8bpp mode. Other
+ * resolutions are working, but only the 8bpp mode is supported.
+ * Changes need to be made to the palette encode and decode routines
+ * to support 4 and 16 bpp modes.
+ * Driver is not designed to be a module. The FrameBuffer is statically
+ * allocated since dynamic allocation of a 300k buffer cannot be
+ * guaranteed.
+ *
+ * 1999/06/17:
+ * FrameBuffer memory is now allocated at run-time when the
+ * driver is initialized.
*
+ * 2000/04/10:
+ * Big cleanup for dynamic selection of machine type at run time.
+ * Nicolas Pitre <nico@cam.org>
+ *
+ * 2000/07/19:
+ * Support for Bitsy aka Compaq iPAQ H3600 added.
+ * Jamey Hicks <jamey@crl.dec.com>
+ *
+ * 2000/08/07:
+ * Resolved an issue caused by a change made to the Assabet's PLD
+ * earlier this year which broke the framebuffer driver for newer
+ * Phase 4 Assabets. Some other parameters were changed to optimize for
+ * the Sharp display.
+ * Tak-Shing Chan <tchan.rd@idthk.com>
+ * Jeff Sutherland <jsutherland@accelent.com>
+ *
+ * 2000/08/09:
+ * XP860 support added
+ * Kunihiko IMAI <???>
*/
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <asm/proc/pgtable.h>
sa1100fb_encode_var(struct fb_var_screeninfo *var,
struct sa1100fb_par *par)
{
- // Don't know if really want to var on entry.
+ // Don't know if really want to zero var on entry.
// Look at set_var to see. If so, may need to add extra params to par
// memset(var, 0, sizeof(struct fb_var_screeninfo));
break;
case 12: // This case should differ for Active/Passive mode
case 16:
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- var->transp.length = 0;
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->transp.offset = 0;
- break;
+ if (machine_is_bitsy()) {
+ var->red.length = 4;
+ var->blue.length = 4;
+ var->green.length = 4;
+ var->transp.length = 0;
+ var->red.offset = 12;
+ var->green.offset = 7;
+ var->blue.offset = 1;
+ var->transp.offset = 0;
+ } else {
+ var->red.length = 5;
+ var->blue.length = 5;
+ var->green.length = 6;
+ var->transp.length = 0;
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->transp.offset = 0;
+ }
+ break;
}
return 0;
}
DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base);
DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base);
+ DPRINTK("palette_size = 0x%08lx\n",(u_long)par->palette_size);
+ DPRINTK("palette_mem_size = 0x%08lx\n",(u_long)palette_mem_size);
DPRINTK("p_screen_base = 0x%08lx\n",(u_long)par->p_screen_base);
DPRINTK("v_screen_base = 0x%08lx\n",(u_long)par->v_screen_base);
DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion);
DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys);
+
return 0;
}
else
display = &global_disp; /* Default display settings */
-
- DPRINTK("xres = %d, yres = %d\n",var->xres, var->yres);
/* Decode var contents into a par structure, adjusting any */
/* out of range values. */
if ((err = sa1100fb_decode_var(var, &par)))
(memcmp(&display->var.blue, &var->blue, sizeof(var->blue))))
chgvar = 1;
}
- DPRINTK("chgvar=%d\n", chgvar);
display->var = *var;
display->screen_base = par.v_screen_base;
display->can_soft_blank = 1;
display->inverse = 0;
- DPRINTK("display->var.bits_per_pixel=%d xres=%d yres=%d display->dispsw=%p\n",
- display->var.bits_per_pixel, var->xres, var->yres, display->dispsw);
switch (display->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4:
cmap = &display->cmap;
else
cmap = fb_default_cmap(current_par.palette_size);
- DPRINTK("visual=%d palette_size=%d cmap=%p\n", current_par.visual, current_par.palette_size, cmap);
fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info);
}
init_var.blue.length = 5;
init_var.grayscale = 0;
init_var.sync = 0;
+ init_var.pixclock = 171521;
} else if (machine_is_bitsy()) {
current_par.max_xres = 320;
current_par.max_yres = 240;
current_par.max_bpp = 16;
- init_var.red.length = 5;
- init_var.green.length = 6;
- init_var.blue.length = 5;
- init_var.grayscale = 0;
+ init_var.red.length = 4;
+ init_var.green.length = 4;
+ init_var.blue.length = 4;
+ init_var.red.offset = 12;
+ init_var.green.offset = 7;
+ init_var.blue.offset = 1;
+ init_var.grayscale = 0;
} else if (machine_is_brutus()) {
current_par.max_xres = 320;
current_par.max_yres = 240;
init_var.vsync_len = 1;
init_var.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
init_var.vmode = 0;
+ } else if (machine_is_xp860()) {
+ current_par.max_xres = 1024;
+ current_par.max_yres = 768;
+
+ current_par.max_bpp = 8;
+ init_var.red.length = 4;
+ init_var.green = init_var.red;
+ init_var.blue = init_var.red;
+
+ init_var.hsync_len = 4;
+ init_var.left_margin = 3;
+ init_var.right_margin = 2;
+
+ init_var.vsync_len = 3;
+ init_var.upper_margin = 2;
+ init_var.lower_margin = 1;
+
}
current_par.p_palette_base = NULL;
L_PTE_YOUNG |
L_PTE_DIRTY |
L_PTE_WRITE);
- memset(VideoMemRegion, 0xAA, ALLOCATED_FB_MEM_SIZE);
return (VideoMemRegion == NULL ? -EINVAL : 0);
}
/* the last multiplication by 1.2 is to handle */
/* sync problems */
}
+ if (machine_is_assabet()) {
+ pcd = frequency[PPCR & 0xf] / 1000;
+ pcd *= pixclock / 1000;
+ pcd = pcd / 1000000;
+ pcd++; /* make up for integer math truncations */
+ }
return pcd;
}
LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) +
LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(2) +
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
lcd_shadow.lccr3 =
LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
LCCR3_HorSnchH + LCCR3_ACBsCntOff +
- LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
+ LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd);
/* Set board control register to handle new color depth */
sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16);
LCCR0_DMADel(0);
lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
LCCR1_HorSnchWdth( 4 ) +
- LCCR1_BegLnDel( 0x1f ) +
- LCCR1_EndLnDel( 0x1f );
- lcd_shadow.lccr2 = LCCR2_DisHght( var->yres ) +
- LCCR2_VrtSnchWdth( 1 )+
- LCCR2_BegFrmDel( 0 ) +
- LCCR2_EndFrmDel( 0 );
- lcd_shadow.lccr3 = 15;
+ LCCR1_BegLnDel( 0xC ) +
+ LCCR1_EndLnDel( 0x11 );
+ lcd_shadow.lccr2 = LCCR2_DisHght( var->yres + 1 ) +
+ LCCR2_VrtSnchWdth( 3 )+
+ LCCR2_BegFrmDel( 10 ) +
+ LCCR2_EndFrmDel( 1 );
+ lcd_shadow.lccr3 = (/* PCD */ 0x10
+ | /* ACB */ 0
+ | /* API */ 0
+ | LCCR3_VrtSnchL
+ | LCCR3_HorSnchL);
} else if (machine_is_brutus()) {
- DPRINTK("Configuring Brutus LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas +
- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
- LCCR0_DMADel(0);
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) +
- LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
- LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
- lcd_shadow.lccr3 =
- LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
- LCCR3_HorSnchH + LCCR3_ACBsCntOff +
- LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
+ DPRINTK("Configuring Brutus LCD\n");
+ lcd_shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ lcd_shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) +
+ LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+ lcd_shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+ lcd_shadow.lccr3 =
+ LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
+ LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+ LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
} else if (machine_is_lart()) {
DPRINTK("Configuring LART LCD\n");
lcd_shadow.lccr0 =
((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) +
((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
*/
+ } else if (machine_is_xp860()) {
+ DPRINTK("Configuring XP860 LCD\n");
+ lcd_shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ lcd_shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) +
+ LCCR1_HorSnchWdth(var->hsync_len) +
+ LCCR1_BegLnDel(var->left_margin) +
+ LCCR1_EndLnDel(var->right_margin);
+ lcd_shadow.lccr2 =
+ LCCR2_DisHght(var->yres) +
+ LCCR2_VrtSnchWdth(var->vsync_len) +
+ LCCR2_BegFrmDel(var->upper_margin) +
+ LCCR2_EndFrmDel(var->lower_margin);
+ lcd_shadow.lccr3 =
+ LCCR3_PixClkDiv(6) +
+ LCCR3_HorSnchL + LCCR3_VrtSnchL;
}
/* Restore interrupt status */
static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs)
{
if (LCSR & LCSR_LDD) {
+ int controller_state = current_par.controller_state;
/* Disable Done Flag is set */
LCCR0 |= LCCR0_LDM; /* Mask LCD Disable Done Interrupt */
current_par.controller_state = LCD_MODE_DISABLED;
- if (current_par.controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) {
+ if (controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) {
+ DPRINTK("sa1100fb_inter_handler: re-enabling LCD controller\n");
sa1100fb_enable_lcd_controller();
}
}
#endif
} else if (machine_is_bitsy()) {
#ifdef CONFIG_SA1100_BITSY
- clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
+ if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE)
+ clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
#endif
} else if (machine_is_penny()) {
#ifdef CONFIG_SA1100_PENNY
#endif
} else if (machine_is_bitsy()) {
#ifdef CONFIG_SA1100_BITSY
- set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON)
+ set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
DPRINTK("DBAR1=%p\n", DBAR1);
DPRINTK("LCCR0=%x\n", LCCR0);
DPRINTK("LCCR1=%x\n", LCCR1);
current_par.currcon, info);
sa1100fb_enable_lcd_controller();
}
+ /* TODO: Bitsy support for blanking display */
}
current_par.montype = 1;
if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL) != 0) {
- printk("sa1100fb: failed in request_irq\n");
+ printk(KERN_ERR "sa1100fb: failed in request_irq\n");
return -EBUSY;
}
DPRINTK("sa1100fb: request_irq succeeded\n");
#endif
} else if (machine_is_tifon()) {
GPDR |= GPIO_GPIO(24); /* set GPIO24 to output */
+ } else if (machine_is_xp860()) {
+ GPDR |= 0x3fc;
+ GAFR |= 0x3fc;
}
if (sa1100fb_set_var(&init_var, -1, &fb_info))
* for them to complete. Clean up the buffer_heads afterwards.
*/
-static int do_kio(int rw, int nr, struct buffer_head *bh[], int size)
+static int wait_kio(int rw, int nr, struct buffer_head *bh[], int size)
{
int iosize;
int i;
struct buffer_head *tmp;
- if (rw == WRITE)
- rw = WRITERAW;
- ll_rw_block(rw, nr, bh);
iosize = 0;
spin_lock(&unused_list_lock);
offset += size;
atomic_inc(&iobuf->io_count);
-
+
+ generic_make_request(rw, tmp);
/*
- * Start the IO if we have got too much
+ * Wait for IO if we have got too much
*/
if (bhind >= KIO_MAX_SECTORS) {
- err = do_kio(rw, bhind, bh, size);
+ err = wait_kio(rw, bhind, bh, size);
if (err >= 0)
transferred += err;
else
/* Is there any IO still left to submit? */
if (bhind) {
- err = do_kio(rw, bhind, bh, size);
+ err = wait_kio(rw, bhind, bh, size);
if (err >= 0)
transferred += err;
else
if (atomic_read(¤t->sig->count) <= 1)
return 0;
- newsig = kmalloc(sizeof(*newsig), GFP_KERNEL);
+ newsig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL);
if (newsig == NULL)
return -ENOMEM;
spin_lock_init(&newsig->siglock);
if (current->sig == oldsig)
return;
if (atomic_dec_and_test(&oldsig->count))
- kfree(oldsig);
+ kmem_cache_free(sigact_cachep, oldsig);
}
/*
static inline void flush_old_files(struct files_struct * files)
{
- unsigned long j;
+ long j = -1;
- j = 0;
write_lock(&files->file_lock);
for (;;) {
unsigned long set, i;
+ j++;
i = j * __NFDBITS;
if (i >= files->max_fds || i >= files->max_fdset)
break;
if (!set)
continue;
files->close_on_exec->fds_bits[j] = 0;
- j++;
write_unlock(&files->file_lock);
for ( ; set ; i++,set >>= 1) {
if (set & 1) {
const char * name,
int name_len,
off_t offset,
- ino_t ino)
+ ino_t ino,
+ unsigned int d_type)
{
struct dirent *d1 = (struct dirent *)buf;
struct dirent *d2 = d1 + 1;
in data block */
secno code_page_data; /* sector number of a code_page_data
containing c.p. array */
- unsigned index; /* index in c.p. array in that sector*/
+ unsigned short index; /* index in c.p. array in that sector*/
+ unsigned short unknown; /* some unknown value; usually 0;
+ 2 in Japanese version */
} array[31]; /* unknown length */
};
struct {
unsigned short ix; /* index */
unsigned short code_page_number; /* code page number */
- unsigned short zero1;
+ unsigned short unknown; /* the same as in cp directory */
unsigned char map[128]; /* upcase table for chars 80..ff */
unsigned short zero2;
} code_page[3];
cpds = cp->array[0].code_page_data;
cpi = cp->array[0].index;
brelse(bh);
+
+ if (cpi >= 3) {
+ printk("HPFS: Code page index out of array\n");
+ return NULL;
+ }
if (!(cpd = hpfs_map_sector(s, cpds, &bh, 0))) return NULL;
if ((unsigned)cpd->offs[cpi] > 0x178) {
#ifndef __ARM_A_OUT_H__
#define __ARM_A_OUT_H__
-#include <linux/types.h>
+#include <asm/types.h>
struct exec
{
* RAM definitions
*/
#define GET_MEMORY_END(p) (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
-#define PARAMS_BASE (PAGE_OFFSET + 0x7c000)
+#define PARAMS_OFFSET 0x7c000
#else
* 29-07-1998 RMK Major re-work of IDE architecture specific code
*/
#include <asm/irq.h>
+#include <asm/mach-types.h>
/*
* Set up a hw structure for a specified data port, control port and IRQ.
*/
#include <asm/ioc.h>
+#ifdef CONFIG_ARCH_ARC
+#define a_clf() clf()
+#define a_stf() stf()
+#else
+#define a_clf() do { } while (0)
+#define a_stf() do { } while (0)
+#endif
+
#define fixup_irq(x) (x)
static void arc_mask_irq_ack_a(unsigned int irq)
{
unsigned int temp;
+ a_clf();
__asm__ __volatile__(
"ldrb %0, [%2]\n"
" bic %0, %0, %1\n"
: "=&r" (temp)
: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)),
"r" (ioaddr(IOC_IRQCLRA)));
+ a_stf();
}
static void arc_mask_irq_a(unsigned int irq)
{
unsigned int temp;
+ a_clf();
__asm__ __volatile__(
"ldrb %0, [%2]\n"
" bic %0, %0, %1\n"
" strb %0, [%2]"
: "=&r" (temp)
: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)));
+ a_stf();
}
static void arc_unmask_irq_a(unsigned int irq)
{
unsigned int temp;
+ a_clf();
__asm__ __volatile__(
"ldrb %0, [%2]\n"
" orr %0, %0, %1\n"
" strb %0, [%2]"
: "=&r" (temp)
: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)));
+ a_stf();
}
static void arc_mask_irq_b(unsigned int irq)
*/
#include <linux/config.h>
-#ifdef CONFIG_ARCH_ARC
-
-#define cliIF() \
- do { \
- unsigned long temp; \
- __asm__ __volatile__( \
-" mov %0, pc\n" \
-" orr %0, %0, #0x0c000000\n" \
-" teqp %0, #0\n" \
- : "=r" (temp) \
- : ); \
- } while(0)
-
-#endif
-
static void arch_idle(void)
{
while (!current->need_resched && !hlt_counter);
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H
+/* DMA is not yet implemented! It should be the same as acorn, copy over.. */
+
/*
* This is the maximum DMA address that can be DMAd to.
* There should not be more than (0xd0000000 - 0xc0000000)
* bytes of RAM.
*/
#define MAX_DMA_ADDRESS 0xd0000000
-#define MAX_DMA_CHANNELS 1
+#define MAX_DMA_CHANNELS 0
#define DMA_S0 0
#define IOEB_BASE ((volatile unsigned char *)0xe0350050)
#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0xe002a000)
#define PCIO_BASE 0xe0010000
+/* in/out bias for the ISA slot region */
+#define ISASLOT_IO 0x80400000
/*
* RAM definitions
p->u1.s.pages_in_bank[2] + \
p->u1.s.pages_in_bank[3]))
-#define PARAMS_BASE 0
-
#define FLUSH_BASE_PHYS 0x00000000 /* ROM */
#else
* 29-07-1998 RMK Major re-work of IDE architecture specific code
*/
#include <asm/irq.h>
+#include <asm/arch/hardware.h>
/*
* Set up a hw structure for a specified data port, control port and IRQ.
static __inline__ void
ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
- ide_ioreg_t reg = (ide_ioreg_t) data_port;
+ ide_ioreg_t reg = data_port;
int i;
memset(hw, 0, sizeof(*hw));
hw->io_ports[i] = reg;
reg += 1;
}
- hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- if (irq)
+ if (ctrl_port) {
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ } else {
+ hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0x206;
+ }
+ if (irq != NULL)
*irq = 0;
+ hw->io_ports[IDE_IRQ_OFFSET] = 0;
}
/*
static __inline__ void
ide_init_default_hwifs(void)
{
+ hw_regs_t hw;
+
+ ide_init_hwif_ports(&hw, ISASLOT_IO + 0x1f0, ISASLOT_IO + 0x3f6, NULL);
+ hw.irq = IRQ_ISA_14;
+ ide_register_hw(&hw, NULL);
}
#ifndef __ASM_ARCH_SERIAL_H
#define __ASM_ARCH_SERIAL_H
+#include <asm/arch/hardware.h>
+
/*
* This assumes you have a 1.8432 MHz clock for your UART.
*
/* UART CLK PORT IRQ FLAGS */
#define STD_SERIAL_PORT_DEFNS \
{ 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0x804002e8, 41, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0x804003e8, 40, STD_COM_FLAGS }, /* ttyS3 */ \
+ { 0, BASE_BAUD, 0x2F8, 0, STD_COM_FLAGS }, /* ttyS1 */ \
+ /* ISA Slot Serial ports */ \
+ { 0, BASE_BAUD, ISASLOT_IO + 0x2e8, 41, STD_COM_FLAGS }, /* ttyS2 */ \
+ { 0, BASE_BAUD, ISASLOT_IO + 0x3e8, 40, STD_COM_FLAGS }, /* ttyS3 */ \
{ 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS4 */ \
{ 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS5 */ \
{ 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS6 */ \
* 10-Oct-1996 RMK Brought up to date with arch-sa110eval
* 04-Dec-1997 RMK Updated for new arch/arm/time.c
*/
-extern void ioctime_init(void);
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
*/
extern __inline__ void setup_timer(void)
{
- ioctime_init();
-
timer_irq.handler = timer_interrupt;
setup_arm_irq(IRQ_TIMER, &timer_irq);
*/
#define BASE 0x03010000
+#define SERBASE (BASE + (0x3f8 << 2))
static __inline__ void putc(char c)
{
- while (!(*((volatile unsigned int *)(BASE + 0xbf4)) & 0x20));
- *((volatile unsigned int *)(BASE + 0xbe0)) = c;
+ while (!(*((volatile unsigned int *)(SERBASE + 0x14)) & 0x20));
+ *((volatile unsigned int *)(SERBASE)) = c;
}
/*
static __inline__ void arch_decomp_setup(void)
{
- int baud = 3686400 / (9600 * 16);
+ int baud = 3686400 / (9600 * 32);
- *((volatile unsigned int *)(BASE + 0xBEC)) = 0x80;
- *((volatile unsigned int *)(BASE + 0xBE0)) = baud & 0xff;
- *((volatile unsigned int *)(BASE + 0xBE4)) = (baud & 0xff00) >> 8;
- *((volatile unsigned int *)(BASE + 0xBEC)) = 3; /* 8 bits */
- *((volatile unsigned int *)(BASE + 0xBF0)) = 3; /* DTR, RTS */
+ *((volatile unsigned int *)(SERBASE + 0xC)) = 0x80;
+ *((volatile unsigned int *)(SERBASE + 0x0)) = baud & 0xff;
+ *((volatile unsigned int *)(SERBASE + 0x4)) = (baud & 0xff00) >> 8;
+ *((volatile unsigned int *)(SERBASE + 0xC)) = 3; /* 8 bits */
+ *((volatile unsigned int *)(SERBASE + 0x10)) = 3; /* DTR, RTS */
}
/*
#define UNCACHEABLE_ADDR 0xf3000000
-#define PARAMS_BASE (PAGE_OFFSET + 0x400)
+#define PARAMS_OFFSET 0x400
#endif
#include <linux/config.h>
#include <asm/arch/memory.h>
-#ifdef CONFIG_FOOTBRIDGE_HOST
+#ifdef CONFIG_ARCH_FOOTBRIDGE
/* Virtual Physical Size
* 0xff800000 0x40000000 1MB X-Bus
* 0xff000000 0x7c000000 1MB PCI I/O space
#define PCIMEM_BASE 0xf0000000
#elif defined(CONFIG_ARCH_CO285)
-
+/*
+ * This is the COEBSA285 cut-down mapping
+ */
#define PCIMEM_SIZE 0x80000000
#define PCIMEM_BASE 0x80000000
#else
-#error Add your add-in architecture here
+#error "Undefined footbridge architecture"
#endif
#define XBUS_SWITCH_J17_9 ((*XBUS_SWITCH) & (1 << 6))
#define PARAMS_OFFSET 0x0100
-#define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET)
#define FLUSH_BASE_PHYS 0x50000000
#define UNCACHEABLE_ADDR (ARMCSR_BASE + 0x108)
#include <asm/hardware.h>
#include <asm/dec21285.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
/*
* Footbridge IRQ translation table
* Converts from our IRQ numbers into FootBridge masks
*/
-static int dc21285_irq_mask[] = {
+static const int dc21285_irq_mask[] = {
IRQ_MASK_UART_RX, /* 0 */
IRQ_MASK_UART_TX, /* 1 */
IRQ_MASK_TIMER1, /* 2 */
static inline int fixup_irq(unsigned int irq)
{
+#ifdef PCIIACK_BASE
if (irq == isa_irq)
irq = *(unsigned char *)PCIIACK_BASE;
+#endif
return irq;
}
* 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder
* 01-Feb-1999 PJB ISA IRQs start at 0 not 16
*/
+#include <asm/mach-types.h>
#define NR_IRQS 36
#define NR_DC21285_IRQS 16
* (C) 1998 Russell King
* (C) 1998 Phil Blundell
*/
+#include <linux/ioport.h>
#include <asm/irq.h>
#include <asm/system.h>
-extern int have_isa_bridge;
-
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
#define SYSRQ_KEY 0x54
/* resource allocation */
-#define kbd_request_region()
+#define kbd_request_region() request_region(0x60, 16, "keyboard")
#define kbd_request_irq(handler) request_irq(KEYBOARD_IRQ, handler, 0, \
"keyboard", NULL)
#include <linux/config.h>
-#if defined(CONFIG_FOOTBRIDGE_HOST)
-
+#if defined(CONFIG_FOOTBRIDGE_ADDIN)
/*
- * Task size: 3GB
+ * If we may be using add-in footbridge mode, then we must
+ * use the out-of-line translation that makes use of the
+ * PCI BAR
*/
-#define TASK_SIZE (0xc0000000UL)
-#define TASK_SIZE_26 (0x04000000UL)
+#ifndef __ASSEMBLY__
+extern unsigned long __virt_to_bus(unsigned long);
+extern unsigned long __bus_to_virt(unsigned long);
+#endif
-/*
- * Page offset: 3GB
- */
-#define PAGE_OFFSET (0xc0000000UL)
-#define PHYS_OFFSET (0x00000000UL)
+#elif defined(CONFIG_FOOTBRIDGE_HOST)
#define __virt_to_bus__is_a_macro
#define __virt_to_bus(x) ((x) - 0xe0000000)
#define __bus_to_virt__is_a_macro
#define __bus_to_virt(x) ((x) + 0xe0000000)
-#elif defined(CONFIG_FOOTBRIDGE_ADDIN)
+#else
-#if defined(CONFIG_ARCH_CO285)
+#error "Undefined footbridge mode"
-/*
- * Task size: 1.5GB
- */
-#define TASK_SIZE (0x60000000UL)
-#define TASK_SIZE_26 (0x04000000UL)
+#endif
-/*
- * Page offset: 1.5GB
- */
+#if defined(CONFIG_ARCH_FOOTBRIDGE)
+
+/* Task size and page offset at 3GB */
+#define TASK_SIZE (0xc0000000UL)
+#define PAGE_OFFSET (0xc0000000UL)
+
+#elif defined(CONFIG_ARCH_CO285)
+
+/* Task size and page offset at 1.5GB */
+#define TASK_SIZE (0x60000000UL)
#define PAGE_OFFSET (0x60000000UL)
-#define PHYS_OFFSET (0x00000000UL)
#else
-#error Add in your architecture here
+#error "Undefined footbridge architecture"
#endif
-#ifndef __ASSEMBLY__
-extern unsigned long __virt_to_bus(unsigned long);
-extern unsigned long __bus_to_virt(unsigned long);
-#endif
-
-#endif
+#define TASK_SIZE_26 (0x04000000UL)
+#define PHYS_OFFSET (0x00000000UL)
/*
- * On Footbridge machines, the dram is contiguous.
- * On Host Footbridge, these conversions are constant.
- * On an add-in footbridge, these depend on register settings.
+ * The DRAM is always contiguous.
*/
#define __virt_to_phys__is_a_macro
#define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET)
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/leds.h>
+#include <asm/mach-types.h>
static void arch_idle(void)
{
#include <asm/dec21285.h>
#include <asm/leds.h>
-#include <asm/system.h>
+#include <asm/mach-types.h>
static int rtc_base;
#define FLUSH_BASE_PHYS 0x40000000 /* ROM */
#define FLUSH_BASE 0xdf000000
-#define PARAMS_BASE (PAGE_OFFSET + 0x0100)
+#define PARAMS_OFFSET (0x0100)
#define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET)
#define PCIO_BASE IO_BASE
* Copyright (c) 2000 Steve Hill (sjhill@cotw.com)
*
* Changelog:
- * 29-03-2000 SJH Created file placeholder
+ * 03-29-2000 SJH Created file placeholder
*/
#include <asm/irq.h>
/*
* linux/include/asm-arm/arch-l7200/io.h
*
- * Copyright (C) 2000 Steven Hill (sjhill@cotw.com)
+ * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
*
* Modifications:
- * 21-03-2000 SJH Created from linux/include/asm-arm/arch-nexuspci/io.h
+ * 03-21-2000 SJH Created from linux/include/asm-arm/arch-nexuspci/io.h
*/
#ifndef __ASM_ARM_ARCH_IO_H
#define __ASM_ARM_ARCH_IO_H
#define IO_SPACE_LIMIT 0xffffffff
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses. PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+
- * and are translated to the start of IO. Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions.
- */
-
-extern __inline__ void __outb (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "strb %1, [%0, %2, lsl #2] @ outb"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-extern __inline__ void __outw (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2] @ outw"
- : "=&r" (temp)
- : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-extern __inline__ void __outl (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2] @ outl"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr) \
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port) \
-{ \
- unsigned long temp, value; \
- __asm__ __volatile__( \
- "tst %2, #0x80000000\n\t" \
- "mov %0, %4\n\t" \
- "addeq %0, %0, %3\n\t" \
- "ldr" ##instr## " %1, [%0, %2, lsl #2] @ in"###fnsuffix \
- : "=&r" (temp), "=r" (value) \
- : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \
- : "cc"); \
- return (unsigned sz)value; \
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port) \
-{ \
- if (__PORT_PCIO(port)) \
- return (unsigned int)(PCIO_BASE + (port << 2)); \
- else \
- return (unsigned int)(IO_BASE + (port << 2)); \
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr) \
- DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(int,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port) \
-({ \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "strb %0, [%1, %2] @ outbc" \
- : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "strb %0, [%1, %2] @ outbc" \
- : : "r" (value), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inbc(port) \
-({ \
- unsigned char result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2] @ inbc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2] @ inbc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define __outwc(value,port) \
-({ \
- unsigned long v = value; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outwc" \
- : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outwc" \
- : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inwc(port) \
-({ \
- unsigned short result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inwc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inwc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result & 0xffff; \
-})
-
-#define __outlc(value,port) \
-({ \
- unsigned long v = value; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outlc" \
- : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outlc" \
- : : "r" (v), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inlc(port) \
-({ \
- unsigned long result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inlc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inlc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define __ioaddrc(port) \
- (__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2))
-
-#define inb(p) (__builtin_constant_p((p)) ? __inbc(p) : __inb(p))
-#define inw(p) (__builtin_constant_p((p)) ? __inwc(p) : __inw(p))
-#define inl(p) (__builtin_constant_p((p)) ? __inlc(p) : __inl(p))
-#define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
-#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
-#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
-#define __ioaddr(p) (__builtin_constant_p((p)) ? __ioaddr(p) : __ioaddrc(p))
-
/*
* Translated address IO functions
*
#define outl_t(v,p) (*(volatile unsigned long *)(p) = (v))
#define inl_t(p) (*(volatile unsigned long *)(p))
+/*
+ * FIXME - These are to allow for linking. On all the other
+ * ARM platforms, the entire IO space is contiguous.
+ * The 7200 has three separate IO spaces. The below
+ * macros will eventually become more involved. Use
+ * with caution and don't be surprised by kernel oopses!!!
+ */
+#define inb(p) inb_t(p)
+#define inw(p) inw_t(p)
+#define inl(p) inl_t(p)
+#define outb(v,p) outb_t(v,p)
+#define outw(v,p) outw_t(v,p)
+#define outl(v,p) outl_t(v,p)
+
#endif
/*
* linux/include/asm-arm/arch-l7200/memory.h
*
- * Copyright (c) 2000 Steven Hill (sjhill@cotw.com)
+ * Copyright (c) 2000 Steve Hill (sjhill@cotw.com)
* Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net)
*
* Changelog:
* 04-13-2000 RS Changed bus macros for new addr
* 05-03-2000 SJH Removed bus macros and fixed virt_to_phys macro
*/
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
/*
* Task size: 3GB
/*
* linux/include/asm-arm/arch-l7200/system.h
*
- * Copyright (c) 2000 Steven Hill (sjhill@cotw.com)
+ * Copyright (c) 2000 Steve Hill (sjhill@cotw.com)
*
* Changelog
* 03-21-2000 SJH Created
* 04-26-2000 SJH Fixed functions
* 05-03-2000 SJH Removed usage of obsolete 'iomd.h'
+ * 05-31-2000 SJH Properly implemented 'arch_idle'
*/
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
static void arch_idle(void)
{
- while (!current->need_resched && !hlt_counter)
- { };
-/* outb(0, IOMD_SUSMODE);*/
+ while (!current->need_resched && !hlt_counter) {
+ cpu_do_idle(IDLE_WAIT_SLOW);
+ }
}
extern inline void arch_reset(char mode)
*/
extern __inline__ void setup_timer(void)
{
- xtime.tv_sec = RTC_RTCDR;
-
RTC_RTCC = 0; /* Clear interrupt */
timer_irq.handler = timer_interrupt;
* linux/include/asm-arm/arch-l7200/uncompress.h
*
* Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ * 05-01-2000 SJH Created
+ * 05-13-2000 SJH Filled in function bodies
+ * 07-26-2000 SJH Removed hard coded buad rate
*/
+#include <asm/hardware.h>
+
+#define IO_UART IO_START + 0x00044000
+
+#define __raw_writeb(v,p) (*(volatile unsigned char *)(p) = (v))
+#define __raw_readb(p) (*(volatile unsigned char *)(p))
+
static __inline__ void putc(char c)
{
+ while(__raw_readb(IO_UART + 0x18) & 0x20 ||
+ __raw_readb(IO_UART + 0x18) & 0x08);
+ __raw_writeb(c, IO_UART + 0x00);
}
static void puts(const char *s)
{
+ while (*s) {
+ if (*s == 10) { /* If a LF, add CR */
+ putc(10);
+ putc(13);
+ }
+ putc(*(s++));
+ }
}
static __inline__ void arch_decomp_setup(void)
{
+ __raw_writeb(0x00, IO_UART + 0x08); /* Set HSB */
+ __raw_writeb(0x00, IO_UART + 0x20); /* Disable IRQs */
+ __raw_writeb(0x01, IO_UART + 0x14); /* Enable UART */
}
#define arch_decomp_wdog()
p->u1.s.pages_in_bank[2] + \
p->u1.s.pages_in_bank[3]))
-#define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET)
#define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET)
#define FLUSH_BASE_PHYS 0x00000000 /* ROM */
--- /dev/null
+#ifndef _INCLUDE_CERF_H_
+#define _INCLUDE_CERF_H_
+
+/* GPIOs for CF+ slot lines */
+#define GPIO_CF_IRQ GPIO_GPIO (22) /* 1111 MBGNT _OR_ CF IRQ */
+#define GPIO_CF_CD GPIO_GPIO (23) /* 1111 MBREQ _OR_ CF CD */
+#define GPIO_CF_BVD2 GPIO_GPIO (19) /* Graphics IRQ _OR_ CF BVD */
+#define GPIO_CF_BVD1 GPIO_GPIO (20) /* 1111 IRQ _OR_ CF BVD */
+
+#define IRQ_GPIO_CF_IRQ IRQ_GPIO22
+#define IRQ_GPIO_CF_CD IRQ_GPIO23
+#define IRQ_GPIO_CF_BVD2 IRQ_GPIO19
+#define IRQ_GPIO_CF_BVD1 IRQ_GPIO20
+
+#endif
+
#define machine_has_neponset() (0)
#endif
+#ifdef CONFIG_SA1100_CERF
+#include "cerf.h"
+#endif
+
#ifdef CONFIG_SA1100_EMPEG
#include "empeg.h"
#endif
#include <linux/config.h>
-#ifdef CONFIG_BLK_DEV_IDE
-
#include <asm/irq.h>
-#include <asm/arch/hardware.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
/*
* Set up a hw structure for a specified data port, control port and IRQ.
ide_init_hwif_ports(&hw, 0xe00001f0, 0xe00003f6, NULL);
hw.irq = IRQ_GPIO7;
ide_register_hw(&hw, NULL);
+#endif
+ }
+ else if (machine_is_lart()) {
+#ifdef CONFIG_SA1100_LART
+ hw_regs_t hw;
+
+ /* Enable GPIO as interrupt line */
+ GPDR &= ~GPIO_GPIO1;
+ set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE);
+
+ /* set PCMCIA interface timing */
+ MECR = 0x00060006;
+
+ /* init the interface */
+/* ide_init_hwif_ports(&hw, 0xe00000000, 0xe00001000, NULL); */
+ ide_init_hwif_ports(&hw, 0xe00001000, 0xe00000000, NULL);
+ hw.irq = IRQ_GPIO1;
+ ide_register_hw(&hw, NULL);
#endif
}
}
-#endif
*/
#include <linux/config.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
#define fixup_irq(x) (x)
#include "hardware.h"
#include "serial_reg.h"
+#include <asm/mach-types.h>
+
/* Assabet's Status Control "Register" */
unsigned long SCR_value;
serial_port = (unsigned long *)_Ser3UTCR0;
else
serial_port = (unsigned long *)_Ser1UTCR0;
- } else if (machine_is_brutus())
+ } else if (machine_is_brutus()||machine_is_nanoengine())
serial_port = (unsigned long *)_Ser1UTCR0;
else if (machine_is_empeg() || machine_is_bitsy() ||
machine_is_victor() || machine_is_lart())
#include <asm/io.h>
#include <asm/system.h>
-extern int have_isa_bridge;
-
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int pckbd_getkeycode(unsigned int scancode);
extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
* Do not include any C declarations in this file - it is included by
* assembler source.
*/
+#ifndef __ASSEMBLY__
+#error "Only include this from assembly code"
+#endif
+
#include <asm/proc/ptrace.h>
#include <asm/proc/assembler.h>
typedef unsigned int dmach_t;
#include <linux/config.h>
-#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/memory.h>
#include <asm/arch/hardware.h>
+#ifdef PARAMS_OFFSET
+#define PARAMS_BASE ((PAGE_OFFSET) + (PARAMS_OFFSET))
+#else
+#define PARAMS_BASE 0
+#endif
+
#endif
led_amber_on,
led_amber_off,
led_red_on,
- led_red_off
+ led_red_off,
+ /*
+ * I want this between led_timer and led_start, but
+ * someone has decided to export this to user space
+ */
+ led_halted
} led_event_t;
/* Use this routine to handle LEDs */
#ifdef CONFIG_LEDS
extern void (*leds_event)(led_event_t);
-#define set_leds_event(r) leds_event = r
#else
#define leds_event(e)
-#define set_leds_event(r)
#endif
#endif
#ifndef _ASM_MC146818RTC_H
#define _ASM_MC146818RTC_H
+#include <asm/arch/irqs.h>
#include <asm/io.h>
#ifndef RTC_PORT
outb_p((val),RTC_PORT(1)); \
})
-#define RTC_IRQ 8
-
#endif /* _ASM_MC146818RTC_H */
#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
#ifndef CONFIG_DISCONTIGMEM
-#define MAP_NR(addr) ((__pa(addr) - PHYS_OFFSET) >> PAGE_SHIFT)
-#define virt_to_page(kaddr) (mem_map + ((__pa(kaddr) - PHYS_OFFSET) >> PAGE_SHIFT))
+#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT) - \
+ (PHYS_OFFSET >> PAGE_SHIFT))
#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
#endif
#define _ASMARM_PGALLOC_H
#include <linux/config.h>
-#include <linux/threads.h>
#include <asm/processor.h>
#include <linux/config.h>
#include <asm/arch/memory.h>
#include <asm/proc-fns.h>
-#include <asm/system.h>
/*
* PMD_SHIFT determines the size of the area a second-level page table can map
#define pte_clear(ptep) set_pte((ptep), __pte(0))
#ifndef CONFIG_DISCONTIGMEM
-#define pte_page(x) (mem_map + (unsigned long)(((pte_val(pte) - PHYS_OFFSET) >> PAGE_SHIFT)))
+#define pte_page(x) (mem_map + (pte_val((x)) >> PAGE_SHIFT) - \
+ (PHYS_OFFSET >> PAGE_SHIFT))
#else
/*
* I'm not happy with this - we needlessly convert a physical address
* which, if __va and __pa are expensive causes twice the expense for
* zero gain. --rmk
*/
-#define pte_page(x) (mem_map + MAP_NR(__va(pte_val(pte))))
+#define pte_page(x) (mem_map + MAP_NR(__va(pte_val((x)))))
#endif
#define pmd_none(pmd) (!pmd_val(pmd))
#define module_map vmalloc
#define module_unmap vfree
-/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
-#define PageSkip(page) (machine_is_riscpc() && test_bit(PG_skip, &(page)->flags))
-
#define io_remap_page_range remap_page_range
#endif /* !__ASSEMBLY__ */
* This file contains arm architecture specific defines
* for the different processors
*/
-#ifndef __ASSEMBLY__
-#error "Only include this from assembly code"
-#endif
-
#define MODE_USR USR26_MODE
#define MODE_FIQ FIQ26_MODE
#define MODE_IRQ IRQ26_MODE
#define SVCMODE(tmpreg)\
teqp pc, $0x00000003;\
mov r0, r0
+
+
+/*
+ * Save the current IRQ state and disable IRQs
+ * Note that this macro assumes FIQs are enabled, and
+ * that the processor is in SVC mode.
+ */
+ .macro save_and_disable_irqs, oldcpsr, temp
+ mov \oldcpsr, pc
+ orr \temp, \oldcpsr, #0x08000000
+ teqp \temp, #0
+ .endm
+
+/*
+ * Restore interrupt state previously stored in
+ * a register
+ * ** Actually do nothing on Arc - hope that the caller uses a MOVS PC soon
+ * after!
+ */
+ .macro restore_irqs, oldcpsr
+ @ This be restore_irqs
+ .endm
#define flush_icache_page(vma,page) do { } while (0)
#define flush_icache_range(start,end) do { } while (0)
+/* DAG: ARM3 will flush cache on MEMC updates anyway? so don't bother */
+#define clean_cache_area(_start,_size) do { } while (0)
+
/*
* TLB flushing:
*
--- /dev/null
+/*
+ * linux/include/asm-arm/proc-armo/locks.h
+ *
+ * Copyright (C) 2000 Russell King
+ * Fixes for 26 bit machines, (C) 2000 Dave Gilbert
+ *
+ * Interrupt safe locking assembler.
+ *
+ */
+#ifndef __ASM_PROC_LOCKS_H
+#define __ASM_PROC_LOCKS_H
+
+/* Decrements by 1, fails if value < 0 */
+#define __down_op(ptr,fail) \
+ ({ \
+ __asm__ __volatile__ ( \
+ "@ atomic down operation\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+" ldr lr, [%0]\n" \
+" and r0, r0, #0x0c000003\n" \
+" subs lr, lr, #1\n" \
+" str lr, [%0]\n" \
+" orrmi r0, r0, #0x80000000 @ set N\n" \
+" teqp r0, #0\n" \
+" movmi r0, %0\n" \
+" blmi " SYMBOL_NAME_STR(fail) \
+ : \
+ : "r" (ptr) \
+ : "r0", "lr", "cc"); \
+ })
+
+#define __down_op_ret(ptr,fail) \
+ ({ \
+ unsigned int result; \
+ __asm__ __volatile__ ( \
+" @ down_op_ret\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+" ldr lr, [%1]\n" \
+" and r0, r0, #0x0c000003\n" \
+" subs lr, lr, #1\n" \
+" str lr, [%1]\n" \
+" orrmi r0, r0, #0x80000000 @ set N\n" \
+" teqp r0, #0\n" \
+" movmi r0, %1\n" \
+" movpl r0, #0\n" \
+" blmi " SYMBOL_NAME_STR(fail) "\n" \
+" mov %0, r0" \
+ : "=&r" (result) \
+ : "r" (ptr) \
+ : "r0", "lr", "cc"); \
+ result; \
+ })
+
+#define __up_op(ptr,wake) \
+ ({ \
+ __asm__ __volatile__ ( \
+ "@ up_op\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+" ldr lr, [%0]\n" \
+" and r0, r0, #0x0c000003\n" \
+" adds lr, lr, #1\n" \
+" str lr, [%0]\n" \
+" orrle r0, r0, #0x80000000 @ set N - should this be mi ??? DAG ! \n" \
+" teqp r0, #0\n" \
+" movmi r0, %0\n" \
+" blmi " SYMBOL_NAME_STR(wake) \
+ : \
+ : "r" (ptr) \
+ : "r0", "lr", "cc"); \
+ })
+
+/*
+ * The value 0x01000000 supports up to 128 processors and
+ * lots of processes. BIAS must be chosen such that sub'ing
+ * BIAS once per CPU will result in the long remaining
+ * negative.
+ */
+#define RW_LOCK_BIAS 0x01000000
+#define RW_LOCK_BIAS_STR "0x01000000"
+
+/* Decrements by RW_LOCK_BIAS rather than 1, fails if value != 0 */
+#define __down_op_write(ptr,fail) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ down_op_write\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+" and r0, r0, #0x0c000003\n" \
+\
+" ldr lr, [%0]\n" \
+" subs lr, lr, %1\n" \
+" str lr, [%0]\n" \
+\
+" orreq r0, r0, #0x40000000 @ set Z \n"\
+" teqp r0, #0\n" \
+" movne r0, %0\n" \
+" blne " SYMBOL_NAME_STR(fail) \
+ : \
+ : "r" (ptr), "I" (RW_LOCK_BIAS) \
+ : "r0", "lr", "cc"); \
+ })
+
+/* Increments by RW_LOCK_BIAS, wakes if value >= 0 */
+#define __up_op_write(ptr,wake) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ up_op_read\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+\
+" ldr lr, [%0]\n" \
+" and r0, r0, #0x0c000003\n" \
+" adds lr, lr, %1\n" \
+" str lr, [%0]\n" \
+\
+" orrcs r0, r0, #0x20000000 @ set C\n" \
+" teqp r0, #0\n" \
+" movcs r0, %0\n" \
+" blcs " SYMBOL_NAME_STR(wake) \
+ : \
+ : "r" (ptr), "I" (RW_LOCK_BIAS) \
+ : "r0", "lr", "cc"); \
+ })
+
+#define __down_op_read(ptr,fail) \
+ __down_op(ptr, fail)
+
+#define __up_op_read(ptr,wake) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ up_op_read\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+\
+" ldr lr, [%0]\n" \
+" and r0, r0, #0x0c000003\n" \
+" adds lr, lr, %1\n" \
+" str lr, [%0]\n" \
+\
+" orreq r0, r0, #0x40000000 @ Set Z \n" \
+" teqp r0, #0\n" \
+" moveq r0, %0\n" \
+" bleq " SYMBOL_NAME_STR(wake) \
+ : \
+ : "r" (ptr), "I" (1) \
+ : "r0", "lr", "cc"); \
+ })
+
+#endif
: "memory"); \
} while(0)
+#define __clf() do { \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+" mov %0, pc @ clf\n" \
+" orr %0, %0, #0x04000000\n" \
+" teqp %0, #0\n" \
+ : "=r" (temp)); \
+ } while(0)
+
+#define __stf() do { \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+" mov %0, pc @ stf\n" \
+" bic %0, %0, #0x04000000\n" \
+" teqp %0, #0\n" \
+ : "=r" (temp)); \
+ } while(0)
+
/*
* save current IRQ & FIQ state
*/
* This file contains ARM processor specifics for
* the ARM6 and better processors.
*/
-#ifndef __ASSEMBLY__
-#error "Only include this from assembly code"
-#endif
-
#define MODE_USR USR_MODE
#define MODE_FIQ FIQ_MODE
#define MODE_IRQ IRQ_MODE
instr regs
/*
- * Save the current IRQ state and disable IRQs
- * Note that this macro assumes FIQs are enabled, and
- * that the processor is in SVC mode.
+ * Save the current IRQ state and disable IRQs. Note that this macro
+ * assumes FIQs are enabled, and that the processor is in SVC mode.
*/
.macro save_and_disable_irqs, oldcpsr, temp
mrs \oldcpsr, cpsr
.endm
/*
- * Restore interrupt state previously stored in
- * a register
+ * Restore interrupt state previously stored in a register. We don't
+ * guarantee that this will preserve the flags.
*/
.macro restore_irqs, oldcpsr
msr cpsr_c, \oldcpsr
there is no other ELF system currently supported by iBCS.
@@ Could print a warning message to encourage users to upgrade. */
#define SET_PERSONALITY(ex,ibcs2) \
- set_personality((ex).e_flags&EF_ARM_APCS26 ?PER_LINUX :PER_LINUX_32BIT)
+ set_personality(((ex).e_flags&EF_ARM_APCS26 ?PER_LINUX :PER_LINUX_32BIT))
#endif
: "memory"); \
})
+/*
+ * Enable FIQs
+ */
+#define __stf() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ stf\n" \
+" bic %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory"); \
+ })
+
+/*
+ * Disable FIQs
+ */
+#define __clf() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ clf\n" \
+" orr %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory"); \
+ })
+
/*
* save current IRQ & FIQ state
*/
"2:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
- "3: mvn %0, %3\n" \
+ "3: mov %0, %3\n" \
" b 2b\n" \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err) \
- : "r" (x), "r" (addr), "i" (EFAULT), "0" (err))
+ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err))
#define __put_user_asm_half(x,addr,err) \
({ \
"3:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
- "4: mvn %0, %5\n" \
+ "4: mov %0, %5\n" \
" b 3b\n" \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
: "=r" (err) \
: "r" (__temp), "r" (__temp >> 8), \
"r" (addr), "r" ((int)(addr) + 1), \
- "i" (EFAULT), "0" (err)); \
+ "i" (-EFAULT), "0" (err)); \
})
#define __put_user_asm_word(x,addr,err) \
"2:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
- "3: mvn %0, %3\n" \
+ "3: mov %0, %3\n" \
" b 2b\n" \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err) \
- : "r" (x), "r" (addr), "i" (EFAULT), "0" (err))
+ : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err))
#define __get_user_asm_byte(x,addr,err) \
__asm__ __volatile__( \
"2:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
- "3: mvn %0, %3\n" \
+ "3: mov %0, %3\n" \
" mov %1, #0\n" \
" b 2b\n" \
" .previous\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err), "=r" (x) \
- : "r" (addr), "i" (EFAULT), "0" (err))
+ : "r" (addr), "i" (-EFAULT), "0" (err))
#define __get_user_asm_half(x,addr,err) \
({ \
"3:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
- "4: mvn %0, %5\n" \
+ "4: mov %0, %5\n" \
" mov %1, #0\n" \
" b 3b\n" \
" .previous\n" \
" .previous" \
: "=r" (err), "=r" (x), "=&r" (__temp) \
: "r" (addr), "r" ((int)(addr) + 1), \
- "i" (EFAULT), "0" (err)); \
+ "i" (-EFAULT), "0" (err)); \
})
"2:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
- "3: mvn %0, %3\n" \
+ "3: mov %0, %3\n" \
" mov %1, #0\n" \
" b 2b\n" \
" .previous\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err), "=r" (x) \
- : "r" (addr), "i" (EFAULT), "0" (err))
+ : "r" (addr), "i" (-EFAULT), "0" (err))
extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n);
#define __do_copy_from_user(to,from,n) \
#define RLIM_NLIMITS 10
+#ifdef __KERNEL__
+
/*
* SuS says limits have to be unsigned.
* Which makes a ton more sense anyway.
*/
#define RLIM_INFINITY (~0UL)
-#ifdef __KERNEL__
-
-#define INIT_RLIMITS \
-{ \
- { LONG_MAX, LONG_MAX }, \
- { LONG_MAX, LONG_MAX }, \
- { LONG_MAX, LONG_MAX }, \
- { _STK_LIM, _STK_LIM }, \
- { 0, LONG_MAX }, \
- { LONG_MAX, LONG_MAX }, \
- { 0, 0 }, \
- { INR_OPEN, INR_OPEN }, \
- { LONG_MAX, LONG_MAX }, \
- { LONG_MAX, LONG_MAX }, \
+#define INIT_RLIMITS \
+{ \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { _STK_LIM, RLIM_INFINITY }, \
+ { 0, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { 0, 0 }, \
+ { INR_OPEN, INR_OPEN }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
}
#endif /* __KERNEL__ */
#ifndef __ASM_ARM_SYSTEM_H
#define __ASM_ARM_SYSTEM_H
-#include <linux/kernel.h>
-
#ifdef __KERNEL__
#include <linux/config.h>
+#include <linux/linkage.h>
/* information about the system we're running on */
extern unsigned int system_rev;
extern unsigned int system_serial_high;
extern unsigned int mem_fclk_21285;
-/* The type of machine we're running on */
-extern unsigned int __machine_arch_type;
-
-/* see arch/arm/kernel/arch.c for a description of these */
-#define MACH_TYPE_EBSA110 0
-#define MACH_TYPE_RISCPC 1
-#define MACH_TYPE_NEXUSPCI 3
-#define MACH_TYPE_EBSA285 4
-#define MACH_TYPE_NETWINDER 5
-#define MACH_TYPE_CATS 6
-#define MACH_TYPE_TBOX 7
-#define MACH_TYPE_CO285 8
-#define MACH_TYPE_CLPS7110 9
-#define MACH_TYPE_ARCHIMEDES 10
-#define MACH_TYPE_A5K 11
-#define MACH_TYPE_ETOILE 12
-#define MACH_TYPE_LACIE_NAS 13
-#define MACH_TYPE_CLPS7500 14
-#define MACH_TYPE_SHARK 15
-#define MACH_TYPE_BRUTUS 16
-#define MACH_TYPE_PERSONAL_SERVER 17
-#define MACH_TYPE_ITSY 18
-#define MACH_TYPE_L7200 19
-/* 20 is free - contact rmk@arm.linux.org.uk directly if you wish to use this number */
-#define MACH_TYPE_INTEGRATOR 21
-#define MACH_TYPE_BITSY 22
-#define MACH_TYPE_IXP1200 23
-#define MACH_TYPE_THINCLIENT 24
-#define MACH_TYPE_ASSABET 25
-#define MACH_TYPE_VICTOR 26
-#define MACH_TYPE_LART 27
-#define MACH_TYPE_RANGER 28
-#define MACH_TYPE_GRAPHICSCLIENT 29
-#define MACH_TYPE_XP860 30
-
/*
- * Sort out a definition for machine_arch_type
- * The rules are:
- * 1. If one architecture is selected, then all machine_is_xxx()
- * are constant.
- * 2. If two or more architectures are selected, then the selected
- * machine_is_xxx() are variable, and the unselected machine_is_xxx()
- * are constant zero.
- *
- * In general, you should use machine_is_xxxx() in your code, not:
- * - switch (machine_arch_type) { }
- * - if (machine_arch_type = xxxx)
- * - __machine_arch_type
- *
- * Please note that these are kept in numeric order (ie, the same
- * order as the list above).
+ * This tells us if we have an ISA bridge
+ * present in a PCI system.
*/
-#ifdef CONFIG_ARCH_EBSA110
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_EBSA110
-# endif
-# define machine_is_ebsa110() (machine_arch_type == MACH_TYPE_EBSA110)
-#else
-# define machine_is_ebsa110() (0)
-#endif
-
-#ifdef CONFIG_ARCH_RPC
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_RISCPC
-# endif
-# define machine_is_riscpc() (machine_arch_type == MACH_TYPE_RISCPC)
-#else
-# define machine_is_riscpc() (0)
-#endif
-
-#ifdef CONFIG_ARCH_EBSA285
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_EBSA285
-# endif
-# define machine_is_ebsa285() (machine_arch_type == MACH_TYPE_EBSA285)
-#else
-# define machine_is_ebsa285() (0)
-#endif
-
-#ifdef CONFIG_ARCH_NETWINDER
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_NETWINDER
-# endif
-# define machine_is_netwinder() (machine_arch_type == MACH_TYPE_NETWINDER)
-#else
-# define machine_is_netwinder() (0)
-#endif
-
-#ifdef CONFIG_ARCH_CATS
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_CATS
-# endif
-# define machine_is_cats() (machine_arch_type == MACH_TYPE_CATS)
-#else
-# define machine_is_cats() (0)
-#endif
-
-#ifdef CONFIG_ARCH_CO285
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_CO285
-# endif
-# define machine_is_co285() (machine_arch_type == MACH_TYPE_CO285)
-#else
-# define machine_is_co285() (0)
-#endif
-
-#ifdef CONFIG_ARCH_ARC
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_ARCHIMEDES
-# endif
-# define machine_is_arc() (machine_arch_type == MACH_TYPE_ARCHIMEDES)
-#else
-# define machine_is_arc() (0)
-#endif
-
-#ifdef CONFIG_ARCH_A5K
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_A5K
-# endif
-# define machine_is_a5k() (machine_arch_type == MACH_TYPE_A5K)
-#else
-# define machine_is_a5k() (0)
-#endif
-
-#ifdef CONFIG_ARCH_CLPS7500
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_CLPS7500
-# endif
-# define machine_is_clps7500() (machine_arch_type == MACH_TYPE_CLPS7500)
-#else
-# define machine_is_clps7500() (0)
-#endif
-
-#ifdef CONFIG_ARCH_SHARK
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_SHARK
-# endif
-# define machine_is_shark() (machine_arch_type == MACH_TYPE_SHARK)
-#else
-# define machine_is_shark() (0)
-#endif
-
-#ifdef CONFIG_SA1100_BRUTUS
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_BRUTUS
-# endif
-# define machine_is_brutus() (machine_arch_type == MACH_TYPE_BRUTUS)
-#else
-# define machine_is_brutus() (0)
-#endif
-
-#ifdef CONFIG_ARCH_PERSONAL_SERVER
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_PERSONAL_SERVER
-# endif
-# define machine_is_personal_server() (machine_arch_type == MACH_TYPE_PERSONAL_SERVER)
-#else
-# define machine_is_personal_server() (0)
-#endif
-
-#ifdef CONFIG_SA1100_ITSY
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_ITSY
-# endif
-# define machine_is_itsy() (machine_arch_type == MACH_TYPE_ITSY)
-#else
-# define machine_is_itsy() (0)
-#endif
-
-#ifdef CONFIG_ARCH_L7200
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_L7200
-# endif
-# define machine_is_l7200() (machine_arch_type == MACH_TYPE_L7200)
+#ifdef CONFIG_PCI
+extern int have_isa_bridge;
#else
-# define machine_is_l7200() (0)
-#endif
-
-#ifdef CONFIG_SA1100_BITSY
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_BITSY
-# endif
-# define machine_is_bitsy() (machine_arch_type == MACH_TYPE_BITSY)
-#else
-# define machine_is_bitsy() (0)
-#endif
-
-#ifdef CONFIG_SA1100_THINCLIENT
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_THINCLIENT
-# endif
-# define machine_is_thinclient() (machine_arch_type == MACH_TYPE_THINCLIENT)
-#else
-# define machine_is_thinclient() (0)
-#endif
-
-#ifdef CONFIG_SA1100_ASSABET
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_ASSABET
-# endif
-# define machine_is_assabet() (machine_arch_type == MACH_TYPE_ASSABET)
-#else
-# define machine_is_assabet() (0)
-#endif
-
-#ifdef CONFIG_SA1100_VICTOR
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_VICTOR
-# endif
-# define machine_is_victor() (machine_arch_type == MACH_TYPE_VICTOR)
-#else
-# define machine_is_victor() (0)
-#endif
-
-#ifdef CONFIG_SA1100_LART
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_LART
-# endif
-# define machine_is_lart() (machine_arch_type == MACH_TYPE_LART)
-#else
-# define machine_is_lart() (0)
-#endif
-
-#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_GRAPHICSCLIENT
-# endif
-# define machine_is_grpahicsclient() \
- (machine_arch_type == MACH_TYPE_GRAPHICSCLIENT)
-#else
-# define machine_is_graphicsclient() \
- (0)
-#endif
-
-#ifdef CONFIG_SA1100_XP860
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_XP860
-# endif
-# define machine_is_xp860() (machine_arch_type == MACH_TYPE_XP860)
-#else
-# define machine_is_xp860() (0)
-#endif
-
-/*
- * The following are currently unregistered
- */
-#ifdef CONFIG_SA1100_EMPEG
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_EMPEG
-# endif
-# define machine_is_empeg() (machine_arch_type == MACH_TYPE_EMPEG)
-#else
-# define machine_is_empeg() (0)
-#endif
-
-#ifdef CONFIG_SA1100_TIFON
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_TIFON
-# endif
-# define machine_is_tifon() (machine_arch_type == MACH_TYPE_TIFON)
-#else
-# define machine_is_tifon() (0)
-#endif
-
-#ifdef CONFIG_SA1100_PLEB
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_PLEB
-# endif
-# define machine_is_pleb() (machine_arch_type == MACH_TYPE_PLEB)
-#else
-# define machine_is_pleb() (0)
-#endif
-
-#ifdef CONFIG_SA1100_PENNY
-# ifdef machine_arch_type
-# undef machine_arch_type
-# define machine_arch_type __machine_arch_type
-# else
-# define machine_arch_type MACH_TYPE_PENNY
-# endif
-# define machine_is_penny() (machine_arch_type == MACH_TYPE_PENNY)
-#else
-# define machine_is_penny() (0)
-#endif
-
-#ifndef machine_arch_type
-#define machine_arch_type __machine_arch_type
+#define have_isa_bridge (0)
#endif
#include <asm/proc-fns.h>
mb(); \
} while (0)
-#endif
-
/* For spinlocks etc */
#define local_irq_save(x) __save_flags_cli(x)
#define local_irq_restore(x) __restore_flags(x)
#define cli() __cli()
#define sti() __sti()
+#define clf() __clf()
+#define stf() __stf()
#define save_flags(x) __save_flags(x)
#define restore_flags(x) __restore_flags(x)
#define save_flags_cli(x) __save_flags_cli(x)
-#endif
+#endif /* CONFIG_SMP */
+
+#endif /* __KERNEL__ */
#endif
#ifndef __ASM_ARM_TERMBITS_H
#define __ASM_ARM_TERMBITS_H
-#include <linux/posix_types.h>
-
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
#ifdef __KERNEL__
-#include <linux/string.h>
-
/*
* Translate a "termio" structure into a "termios". Ugh.
*/
/*
* Single-value transfer routines. They automatically use the right
- * size if we just have the right pointer type.
+ * size if we just have the right pointer type. Note that the functions
+ * which read from user space (*get_*) need to take care not to leak
+ * kernel data even if the calling code is buggy and fails to check
+ * the return value. This means zeroing out the destination variable
+ * or buffer on error. Normally this is done out of line by the
+ * fixup code, but there are a few places where it intrudes on the
+ * main code path. When we only write to user space, there is no
+ * problem.
*
* The "__xxx" versions of the user access functions do not verify the
* address space - it must have been done previously with a separate
*
* The "xxx_ret" versions return constant specified in the third
* argument if something bad happens.
+ *
+ * The "xxx_error" versions set the third argument to EFAULT if an
+ * error occurs, and leave it unchanged on success. Note that these
+ * versions are void (ie, don't return a value as such).
*/
#define get_user(x,p) __get_user_check((x),(p),sizeof(*(p)))
#define __get_user(x,p) __get_user_nocheck((x),(p),sizeof(*(p)))
+#define __get_user_error(x,p,e) __get_user_nocheck_error((x),(p),sizeof(*(p)),(e))
#define get_user_ret(x,p,r) ({ if (get_user(x,p)) return r; })
#define __get_user_ret(x,p,r) ({ if (__get_user(x,p)) return r; })
#define put_user(x,p) __put_user_check((__typeof(*(p)))(x),(p),sizeof(*(p)))
#define __put_user(x,p) __put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p)))
+#define __put_user_error(x,p,e) __put_user_nocheck_error((x),(p),sizeof(*(p)),(e))
#define put_user_ret(x,p,r) ({ if (put_user(x,p)) return r; })
#define __put_user_ret(x,p,r) ({ if (__put_user(x,p)) return r; })
static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n)
{
- char *end = (char *)to + n;
- if (access_ok(VERIFY_READ, from, n)) {
+ if (access_ok(VERIFY_READ, from, n))
__do_copy_from_user(to, from, n);
- if (n) memset(end - n, 0, n);
- }
return n;
}
({ \
long __gu_err = -EFAULT, __gu_val = 0; \
const __typeof__(*(ptr)) *__gu_addr = (ptr); \
- if (access_ok(VERIFY_READ,__gu_addr,size)) \
+ if (access_ok(VERIFY_READ,__gu_addr,size)) { \
+ __gu_err = 0; \
__get_user_size(__gu_val,__gu_addr,(size),__gu_err); \
+ } \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
#define __get_user_nocheck(x,ptr,size) \
({ \
- long __gu_err = 0, __gu_val = 0; \
+ long __gu_err = 0, __gu_val; \
__get_user_size(__gu_val,(ptr),(size),__gu_err); \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
+#define __get_user_nocheck_error(x,ptr,size,err) \
+({ \
+ long __gu_val; \
+ __get_user_size(__gu_val,(ptr),(size),(err)); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ (void) 0; \
+})
+
#define __put_user_check(x,ptr,size) \
({ \
long __pu_err = -EFAULT; \
__typeof__(*(ptr)) *__pu_addr = (ptr); \
- if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
+ if (access_ok(VERIFY_WRITE,__pu_addr,size)) { \
+ __pu_err = 0; \
__put_user_size((x),__pu_addr,(size),__pu_err); \
+ } \
__pu_err; \
})
__pu_err; \
})
+#define __put_user_nocheck_error(x,ptr,size,err) \
+({ \
+ __put_user_size((x),(ptr),(size),err); \
+ (void) 0; \
+})
+
extern long __get_user_bad(void);
#define __get_user_size(x,ptr,size,retval) \
do { \
- retval = 0; \
switch (size) { \
case 1: __get_user_asm_byte(x,ptr,retval); break; \
case 2: __get_user_asm_half(x,ptr,retval); break; \
#define __put_user_size(x,ptr,size,retval) \
do { \
- retval = 0; \
switch (size) { \
case 1: __put_user_asm_byte(x,ptr,retval); break; \
case 2: __put_user_asm_half(x,ptr,retval); break; \
#ifndef __ASM_ARM_UNALIGNED_H
#define __ASM_ARM_UNALIGNED_H
-#include <linux/types.h>
+#include <asm/types.h>
extern int __bug_unaligned_x(void *ptr);
#define _ARM_USER_H
#include <asm/page.h>
-#include <linux/ptrace.h>
+#include <asm/ptrace.h>
/* Core file format: The core file is written in such a way that gdb
can understand it and provide useful information to the user (under
linux we use the 'trad-core' bfd). There are quite a number of
#ifndef _ASM_IA64_PCI_H
#define _ASM_IA64_PCI_H
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/bitops.h>
#include <asm/mmu_context.h>
-#include <asm/processor.h>
#include <asm/system.h>
/*
-/* $Id: fcntl.h,v 1.13 2000/07/06 01:41:45 davem Exp $ */
+/* $Id: fcntl.h,v 1.14 2000/08/12 20:49:49 jj Exp $ */
#ifndef _SPARC_FCNTL_H
#define _SPARC_FCNTL_H
#define F_SETSIG 10 /* for sockets. */
#define F_GETSIG 11 /* for sockets. */
+#define F_GETLK64 12 /* using 'struct flock64' */
+#define F_SETLK64 13
+#define F_SETLKW64 14
+
/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
short __unused;
};
+struct flock64 {
+ short l_type;
+ short l_whence;
+ loff_t l_start;
+ loff_t l_len;
+ pid_t l_pid;
+ short __unused;
+};
+
#endif
-/* $Id: unistd.h,v 1.67 2000/08/12 13:25:51 davem Exp $ */
+/* $Id: unistd.h,v 1.68 2000/08/12 20:49:49 jj Exp $ */
#ifndef _SPARC_UNISTD_H
#define _SPARC_UNISTD_H
/* #define __NR_putmsg 152 SunOS Specific */
#define __NR_poll 153 /* Common */
#define __NR_getdents64 154 /* Linux specific */
-/* #define __NR_nfssvc 155 SunOS Specific */
+#define __NR_fstat64 155 /* Linux sparc32 Specific */
/* #define __NR_getdirentries 156 SunOS Specific */
#define __NR_statfs 157 /* Common */
#define __NR_fstatfs 158 /* Common */
-/* $Id: fcntl.h,v 1.9 2000/08/12 13:25:53 davem Exp $ */
+/* $Id: fcntl.h,v 1.10 2000/08/12 20:49:49 jj Exp $ */
#ifndef _SPARC64_FCNTL_H
#define _SPARC64_FCNTL_H
#define F_SETSIG 10 /* for sockets. */
#define F_GETSIG 11 /* for sockets. */
+#ifdef __KERNEL__
+#define F_GETLK64 12
+#define F_SETLK64 13
+#define F_SETLKW64 14
+#endif
+
/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
-/* $Id: openprom.h,v 1.7 1998/03/15 10:14:47 ecd Exp $ */
+/* $Id: openprom.h,v 1.8 2000/08/12 19:55:25 anton Exp $ */
#ifndef __SPARC64_OPENPROM_H
#define __SPARC64_OPENPROM_H
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
-/* Empirical constants... */
-#define KADB_DEBUGGER_BEGVM 0xffc00000 /* Where kern debugger is in virt-mem */
-#define LINUX_OPPROM_BEGVM 0xffd00000
-#define LINUX_OPPROM_ENDVM 0xfff00000
-#define LINUX_OPPROM_MAGIC 0x10010407
-
#ifndef __ASSEMBLY__
/* V0 prom device operations. */
struct linux_dev_v0_funcs {
-/* $Id: unistd.h,v 1.45 2000/08/12 13:25:52 davem Exp $ */
+/* $Id: unistd.h,v 1.46 2000/08/12 20:49:49 jj Exp $ */
#ifndef _SPARC64_UNISTD_H
#define _SPARC64_UNISTD_H
/* #define __NR_putmsg 152 SunOS Specific */
#define __NR_poll 153 /* Common */
#define __NR_getdents64 154 /* Linux specific */
-/* #define __NR_nfssvc 155 SunOS Specific */
+/* #define __NR_fstat64 155 Linux sparc32 Specific */
/* #define __NR_getdirentries 156 SunOS Specific */
#define __NR_statfs 157 /* Common */
#define __NR_fstatfs 158 /* Common */
VIA_VP3,
VIA_MVP3,
VIA_MVP4,
- VIA_APOLLO_SUPER,
VIA_APOLLO_PRO,
+ VIA_APOLLO_KX133,
+ VIA_APOLLO_KT133,
SIS_GENERIC,
AMD_GENERIC,
AMD_IRONGATE,
#define READA 2 /* read-ahead - don't block if no resources */
#define SPECIAL 4 /* For non-blockdevice requests in request queue */
-#define WRITERAW 5 /* raw write - don't play with buffer lists */
-
#define SEL_IN 1
#define SEL_OUT 2
#define SEL_EX 4
extern void signals_init(void);
extern void bdev_init(void);
extern int init_pcmcia_ds(void);
-extern int usb_init(void);
extern void free_initmem(void);
extern void filesystem_setup(void);
#ifdef CONFIG_ISAPNP
isapnp_init();
#endif
-#ifdef CONFIG_USB
- usb_init(); /* Do this before doing initcalls, so that we can make
- usbcore initialize here, and all drivers initialize later */
-#endif
#ifdef CONFIG_TC
tc_init();
#endif
read_lock(&tasklist_lock);
for_each_task(p) {
- struct file *files;
+ struct files_struct *files;
if (p->session != sid)
continue;
fi
if [ "$CONFIG_IRDA" != "n" ]; then
- source net/irda/compressors/Config.in
source drivers/net/irda/Config.in
fi
endmenu
struct socket * sock;
inode = get_empty_inode();
- inode->i_sb = sock_mnt->mnt_sb;
if (!inode)
return NULL;
+ inode->i_sb = sock_mnt->mnt_sb;
sock = socki_lookup(inode);
inode->i_mode = S_IFSOCK|S_IRWXUGO;
proto_init();
+ register_filesystem(&sock_fs_type);
+ sock_mnt = kern_mount(&sock_fs_type);
+
/*
* The netlink device handler may be needed early.
*/
#ifdef CONFIG_NETFILTER
netfilter_init();
#endif
- register_filesystem(&sock_fs_type);
- sock_mnt = kern_mount(&sock_fs_type);
}
int socket_get_info(char *buffer, char **start, off_t offset, int length)