boards supported by this driver, and for further information
on the use of this driver.
+QuickNet Internet LineJack/PhoneJack support
+CONFIG_PHONE_IXJ
+ Say M if you have a telephony card manufactured by Quicknet
+ Technologies, Inc. These include the Internet PhoneJACK and
+ Internet LineJACK Telephony Cards.
+
+ For the ISA versions of these products, you can configure the
+ cards using the isapnp tools (pnpdump/isapnp) or you can use the
+ isapnp support. Please read:
+
+ /usr/src/linux/Documentation/telephony/ixj.txt.
+
+ For more information on these cards, see Quicknet's website at:
+ http://www.quicknet.net/
+
+ If you do not have any Quicknet telephony cards, you can safely
+ ignore this option.
+
+
#
# ARM options
#
The i2c_probe or sensors_detect function will call the foo_detect_client
function only for those i2c addresses that actually have a device on
-them (unless a `force' parameter was used).
+them (unless a `force' parameter was used). In addition, addresses that
+are already in use (by some other registered client) are skipped.
The detect client function
return 0;
}
-You should never directly call this function, but instead use the
-general function below:
-
- extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
-
-
Sending and receiving
=====================
--- /dev/null
+Linux Quicknet-Drivers-Howto
+Quicknet Technologies, Inc. (www.quicknet.net)
+Version 0.3.4 December 18, 1999
+
+1.0 Introduction
+
+This document describes the first GPL release version of the Linux
+driver for the Quicknet Internet PhoneJACK and Internet LineJACK
+cards. More information about these cards is available at
+www.quicknet.net. The driver version discussed in this document is
+0.3.4.
+
+These cards offer nice telco style interfaces to use your standard
+telephone/key system/PBX as the user interface for VoIP applications.
+The Internet LineJACK also offers PSTN connectivity for a single line
+Internet to PSTN gateway. Of course, you can add more than one card
+to a system to obtain multi-line functionality. At this time, the
+driver supports the POTS port on both the Internet PhoneJACK and the
+Internet LineJACK, but the PSTN port on the latter card is not yet
+supported.
+
+This document, and the drivers for the cards, are intended for a
+limited audience that includes technically capable programmers who
+would like to experiment with Quicknet cards. The drivers are
+considered in ALPHA status and are not yet considered stable enough
+for general, widespread use in an unlimited audience.
+
+That's worth saying again:
+
+THE LINUX DRIVERS FOR QUICKNET CARDS ARE PRESENTLY IN A ALPHA STATE
+AND SHOULD NOT BE CONSIDERED AS READY FOR NORMAL WIDESPREAD USE.
+
+They are released early in the spirit of Internet development and to
+make this technology available to innovators who would benefit from
+early exposure.
+
+When we promote the device driver to "beta" level it will be
+considered ready for non-programmer, non-technical users. Until then,
+please be aware that these drivers may not be stable and may affect
+the performance of your system.
+
+
+1.1 Latest Additions/Improvements
+
+The 0.3.4 version of the driver is the first GPL release. Several
+features had to be removed from the prior binary only module, mostly
+for reasons of Intellectual Property rights. We can't release
+information that is not ours - so certain aspects of the driver had to
+be removed to protect the rights of others.
+
+Specifically, very old Internet PhoneJACK cards have non-standard
+G.723.1 codecs (due to the early nature of the DSPs in those days).
+The auto-conversion code to bring those cards into compliance with
+todays standards is available as a binary only module to those people
+needing it. If you bought your card after 1997 or so, you are OK -
+it's only the very old cards that are affected.
+
+Also, the code to download G.728/G.729/G.729a codecs to the DSP is
+available as a binary only module as well. This IP is not ours to
+release.
+
+Hooks are built into the GPL driver to allow it to work with other
+companion modules that are completely separate from this module.
+
+1.2 Copyright, Trademarks, Disclaimer, & Credits
+
+Copyright
+
+Copyright (c) 1999 Quicknet Technologies, Inc. Permission is granted
+to freely copy and distribute this document provided you preserve it
+in its original form. For corrections and minor changes contact the
+maintainer at linux@quicknet.net.
+
+Trademarks
+
+Internet PhoneJACK and Internet LineJACK are registered trademarks of
+Quicknet Technologies, Inc.
+
+Disclaimer
+
+Much of the info in this HOWTO is early information released by
+Quicknet Technologies, Inc. for the express purpose of allowing early
+testing and use of the Linux drivers developed for their products.
+While every attempt has been made to be thorough, complete and
+accurate, the information contained here may be unreliable and there
+are likely a number of errors in this document. Please let the
+maintainer know about them. Since this is free documentation, it
+should be obvious that neither I nor previous authors can be held
+legally responsible for any errors.
+
+Credits
+
+This HOWTO was written by:
+
+ Greg Herlein <gherlein@quicknet.net>
+ Ed Okerson <eokerson@quicknet.net>
+
+1.3 Future Plans: You Can Help
+
+Please let the maintainer know of any errors in facts, opinions,
+logic, spelling, grammar, clarity, links, etc. But first, if the date
+is over a month old, check to see that you have the latest
+version. Please send any info that you think belongs in this document.
+
+You can also contribute code and/or bug-fixes for the sample
+applications.
+
+
+1.4 Where to get things
+
+You can download the latest versions of the driver from:
+
+http://www.quicknet.net/develop.htm
+
+You can download the latest version of this document from:
+
+http://www.quicknet.net/develop.htm
+
+
+1.5 Mailing List
+
+Quicknet operates a mailing list to provide a public forum on using
+these drivers.
+
+To subscribe to the linux-sdk mailing list, send an email to:
+
+ majordomo@linux.quicknet.net
+
+In the body of the email, type:
+
+ subscribe linux-sdk <your-email-address>
+
+Please delete any signature block that you would normally add to the
+bottom of your email - it tends to confuse majordomo.
+
+To send mail to the list, address your mail to
+
+ linux-sdk@linux.quicknet.net
+
+Your message will go out to everyone on the list.
+
+To unsubscribe to the linux-sdk mailing list, send an email to:
+
+ majordomo@linux.quicknet.net
+
+In the body of the email, type:
+
+ unsubscribe linux-sdk <your-email-address>
+
+
+
+2.0 Requirements
+
+2.1 Quicknet Card(s)
+
+You will need at least one Internet PhoneJACK or Internet LineJACK
+cards. These are ISA or PCI bus devices that use Plug-n-Play for
+configuration, and use no IRQs. The driver will support up to 16
+cards in any one system, of any mix between the two types.
+
+Note that you will need two cards to do any useful testing alone, since
+you will need a card on both ends of the connection. Of course, if
+you are doing collaborative work, perhaps your friends or coworkers
+have cards too. If not, we'll gladly sell them some!
+
+
+2.2 ISAPNP
+
+Since the Quicknet cards are Plug-n-Play devices, you will need the
+isapnp tools package to configure the cards, or you can use the isapnp
+module to autoconfigure them. The former package probably came with
+your Linux distribution. Documentation on this package is available
+online at:
+
+http://mailer.wiwi.uni-marburg.de/linux/LDP/HOWTO/Plug-and-Play-HOWTO.html
+
+The isapnp autoconfiguration is available on the Quicknet website at:
+
+ http://www.quicknet.net/develop.htm
+
+though it may be in the kernel by the time you read this.
+
+
+3.0 Card Configuration
+
+If you did not get your drivers as part of the linux kernel, do the
+following to install them:
+
+ a. untar the distribution file. We use the following command:
+ tar -xvzf ixj-0.x.x.tgz
+
+This creates a subdirectory holding all the necessary files. Go to that
+subdirectory.
+
+ b. run the "ixj_dev_create" script to remove any stray device
+files left in the /dev directory, and to create the new officially
+designated device files. Note that the old devices were called
+/dev/ixj, and the new method uses /dev/phone.
+
+ c. type "make;make install" - this will compile and install the
+module.
+
+ d. type "depmod -av" to rebuild all your kernel version dependencies.
+
+ e. if you are using the isapnp module to configure the cards
+ automatically, then skip to step f. Otherwise, ensure that you
+ have run the isapnp configuration utility to properly configure
+ the cards.
+
+ e1. The Internet PhoneJACK has one configuration register that
+ requires 16 IO ports. The Internet LineJACK card has two
+ configuration registers and isapnp reports that IO 0
+ requires 16 IO ports and IO 1 requires 8. The Quicknet
+ driver assumes that these registers are configured to be
+ contiguous, i.e. if IO 0 is set to 0x340 then IO 1 should
+ be set to 0x350.
+
+ Make sure that none of the cards overlap if you have
+ multiple cards in the system.
+
+ If you are new to the isapnp tools, you can jumpstart
+ yourself by doing the following:
+
+ e2. go to the /etc directory and run pnpdump to get a blank
+ isapnp.conf file.
+
+ pnpdump > /etc/isapnp.conf
+
+ e3. edit the /etc/isapnp.conf file to set the IO warnings and
+ the register IO addresses. The IO warnings means that you
+ should find the line in the file that looks like this:
+
+ (CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
+
+ and you should edit the line to look like this:
+
+ (CONFLICT (IO WARNING)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) #
+ or WARNING
+
+ The next step is to set the IO port addresses. The issue
+ here is that isapnp does not identify all of the ports out
+ there. Specifically any device that does not have a driver
+ or module loaded by Linux will not be registered. This
+ includes older sound cards and network cards. We have
+ found that the IO port 0x300 is often used even though
+ isapnp claims that no-one is using those ports. We
+ recommend that for a single card installation that port
+ 0x340 (and 0x350) be used. The IO port line should change
+ from this:
+
+ (IO 0 (SIZE 16) (BASE 0x0300) (CHECK))
+
+ to this:
+
+ (IO 0 (SIZE 16) (BASE 0x0340) )
+
+ e4. if you have multiple Quicknet cards, make sure that you do
+ not have any overlaps. Be especially careful if you are
+ mixing Internet PhoneJACK and Internet LineJACK cards in
+ the same system. In these cases we recommend moving the
+ IO port addresses to the 0x400 block. Please note that on
+ a few machines the 0x400 series are used. Feel free to
+ experiment with other addresses. Our cards have been
+ proven to work using IO addresses of up to 0xFF0.
+
+ e5. the last step is to uncomment the activation line so the
+ drivers will be associated with the port. This means the
+ line (immediately below) the IO line should go from this:
+
+ # (ACT Y)
+
+ to this:
+
+ (ACT Y)
+
+ Once you have finished editing the isapnp.conf file you
+ must submit it into the pnp driverconfigure the cards.
+ This is done using the following command:
+
+ isapnp isapnp.conf
+
+ If this works you should see a line that identifies the
+ Quicknet device, the IO port(s) chosen, and a message
+ "Enabled OK".
+
+ f. if you are loading the module by hand, use insmod. An example
+of this would look like this:
+
+ insmod phonedev
+ insmod ixj dspio=0x320,0x310 xio=0,0x330
+
+Then verify the module loaded by running lsmod. If you are not using a
+module that matches your kernel version, you may need to "force" the
+load using the -f option in the insmod command.
+
+ insmod phonedev
+ insmod -f ixj dspio=0x320,0x310 xio=0,0x330
+
+
+If you are using isapnp to autoconfigure your card, then you do NOT
+need any of the above, though you need to use depmod to load the
+driver, like this:
+
+ depmod ixj
+
+which will result in the needed drivers getting loaded automatically.
+
+ g. if you are planning on using kerneld to automatically load the
+module for you, then you need to edit /etc/conf.modules and add the
+following lines:
+
+ options ixj dspio=0x340 xio=0x330 ixjdebug=0
+
+If you do this, then when you execute an application that uses the
+module kerneld will load the module for you. Note that to do this,
+you need to have your kernel set to support kerneld. You can check
+for this by looking at /usr/src/linux/.config and you should see this:
+
+ # Loadable module support
+ #
+ <snip>
+ CONFIG_KMOD=y
+
+ h. if you want non-root users to be able to read and write to the
+ixj devices (this is a good idea!) you should do the following:
+
+ - decide upon a group name to use and create that group if
+ needed. Add the user names to that group that you wish to
+ have access to the device. For example, we typically will
+ create a group named "ixj" in /etc/group and add all users
+ to that group that we want to run software that can use the
+ ixjX devices.
+
+ - change the permissions on the device files, like this:
+
+ chgrp ixj /dev/ixj*
+ chmod 660 /dev/ixj*
+
+Once this is done, then non-root users should be able to use the
+devices. If you have enabled autoloading of modules, then the user
+should be able to open the device and have the module loaded
+automatically for them.
+
+
+4.0 Driver Installation problems.
+
+We have tested these drivers on the 2.2.9, 2.2.10, 2.2.12, and 2.2.13 kernels
+and in all cases have eventually been able to get the drivers to load and
+run. We have found four types of problems that prevent this from happening.
+The problems and solutions are:
+
+ a. A step was missed in the installation. Go back and use section 3
+as a checklist. Many people miss running the ixj_dev_create script and thus
+never load the device names into the filesystem.
+
+ b. The kernel is inconsistently linked. We have found this problem in
+the Out Of the Box installation of several distributions. The symptoms
+are that neither driver will load, and that the unknown symbols include "jiffy"
+and "kmalloc". The solution is to recompile both the kernel and the
+modules. The command string for the final compile looks like this:
+
+ In the kernel directory:
+ 1. cp .config /tmp
+ 2. make mrproper
+ 3. cp /tmp/.config .
+ 4. make dep;make clean;make bzImage;make modules;make modules_install
+
+This rebuilds both the kernel and all the modules and makes sure they all
+have the same linkages. This generally solves the problem once the new
+kernel is installed and the system rebooted.
+
+ c. The kernel has been patched, then unpatched. This happens when
+someone decides to use an earlier kernel after they load a later kernel.
+The symptoms are proceeding through all three above steps and still not
+being able to load the driver. What has happened is that the generated
+header files are out of sync with the kernel itself. The solution is
+to recompile (again) using "make mrproper". This will remove and then
+regenerate all the necessary header files. Once this is done, then you
+need to install and reboot the kernel. We have not seen any problem
+loading one of our drivers after this treatment.
+
+5.0 Known Limitations
+
+We cannot currently play "dial-tone" and listen for DTMF digits at the
+same time using the ISA PhoneJACK. This is a bug in the 8020 DSP chip
+used on that product. All other Quicknet products function normally
+in this regard. We have a work-around, but it's not done yet. Until
+then, if you want dial-tone, you can always play a recorded dial-tone
+sound into the audio until you have gathered the DTMF digits.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-make[1]: Entering directory `/home/kraxel/2/src/bttv-0.7.10/driver'
bttv.o
card=0 - unknown
card=1 - MIRO PCTV
card=31 - iProTV
card=32 - Intel Create and Share PCI
card=33 - Askey/Typhoon/Anubis Magic TView
+ card=34 - Terratec TerraTValue
tuner.o
type=0 - Temic PAL
type=11 - Alps TSBB5
type=12 - Alps TSBE5
type=13 - Alps TSBC5
-make[1]: Leaving directory `/home/kraxel/2/src/bttv-0.7.10/driver'
fieldnr=1 Count fields. Some TV descrambling software
needs this, for others it only generates
50 useless IRQs/sec.
+ autoload=0/1 autoload helper modules (tuner, audio).
+ default is 1 (on).
remap, card, radio and pll accept up to four comma-separted arguments
(for multiple boards).
from the kernel version, port to the new i2c stack, removed support
for 2.0.x, code cleanups, ...
-You'll need the new i2c stack, download it from
+To compile this bttv version, you'll the new i2c stack. Kernels
+newer than 2.3.34 have this already included. If you have a older
+kernel, download it from:
http://www2.lm-sensors.nu/~lm78/download.html
You'll find Ralphs original (mostly outdated) documentation in the
You should verify this is correct. If it is'nt, you have to pass the
correct board type as insmod argument, "insmod bttv card=2" for
-example. The file MODULES in the driver directory has a list of valid
-arguments. If your card is'nt listed there, you might check the
-source code for new entries which are not listed yet. If there is'nt
-one for your card, you can check if one of the existing entries does
-work for you (just trial and error...).
+example. The file CARDLIST has a list of valid arguments for card.
+If your card is'nt listed there, you might check the source code for
+new entries which are not listed yet. If there is'nt one for your
+card, you can check if one of the existing entries does work for you
+(just trial and error...).
Some boards have an extra processor for sound to do stereo decoding
and other nice features. The msp34xx chips are used by Hauppauge for
the audiomux array. If you have Windows and the drivers four your
card installed, you might to check out if you can read these registers
values used by the windows driver. A tool to do this is available
-from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil
-If you hav'nt Windows installed, this is a trial and error game...
+from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil. There is
+some #ifdef'ed code in bttv.c (search for "new card") which prints
+these values before board initialization, this might help too: boot
+win, start tv app, softboot (loadlin) into linux and load bttv with
+this enabled. If you hav'nt Windows installed, this is a trial and
+error game...
Good luck,
Gerd
-PS: If you have a new working entry, mail it to Ralph. So it can be
- included into next driver version...
+PS: If you have a new working entry, mail it to me.
+
+--
+Gerd Knorr <kraxel@goldbach.in-berlin.de>
W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
S: Maintained
+I2C DRIVERS
+P: Simon Vogl
+M: simon@tk.uni-linz.ac.at
+P: Frodo Looijaard
+M: frodol@dds.nl
+L: linux-i2c@pelican.tk.uni-linz.ac.at
+W: http://www.tk.uni-linz.ac.at/~simon/private/i2c
+S: Maintained
+
i386 BOOT CODE
P: Riley H. Williams
M: rhw@memalpha.cx
VERSION = 2
PATCHLEVEL = 3
-SUBLEVEL = 35
+SUBLEVEL = 36
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
DRIVERS := $(DRIVERS) drivers/i2c/i2c.a
endif
+ifeq ($(CONFIG_PHONE),y)
+DRIVERS := $(DRIVERS) drivers/telephony/telephony.a
+endif
+
include arch/$(ARCH)/Makefile
.S.s:
.quad osf_utsname
.quad sys_lchown
.quad osf_shmat
- .quad sys_shmctl /* 210 */
+ .quad sys_shmctlold /* 210 */
.quad sys_shmdt
.quad sys_shmget
.quad alpha_ni_syscall
.quad sys_setresgid
.quad sys_getresgid
.quad sys_ni_syscall /* sys_dipc */
+ .quad sys_shmctl
#include <linux/shm.h>
#include <linux/poll.h>
#include <linux/file.h>
+#include <linux/types.h>
+#include <linux/ipc.h>
+#include <linux/shm.h>
#include <asm/fpu.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/sysinfo.h>
#include <asm/hwrpb.h>
+#include <asm/processor.h>
extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
extern int do_pipe(int *);
return ret;
}
+
+struct shmid_ds_old {
+ struct ipc_perm shm_perm; /* operation perms */
+ int shm_segsz; /* size of segment (bytes) */
+ __kernel_time_t shm_atime; /* last attach time */
+ __kernel_time_t shm_dtime; /* last detach time */
+ __kernel_time_t shm_ctime; /* last change time */
+ __kernel_ipc_pid_t shm_cpid; /* pid of creator */
+ __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
+ unsigned short shm_nattch; /* no. of current attaches */
+ unsigned short shm_unused; /* compatibility */
+ void *shm_unused2; /* ditto - used by DIPC */
+ void *shm_unused3; /* unused */
+};
+
+struct shminfo_old {
+ int shmmax;
+ int shmmin;
+ int shmmni;
+ int shmseg;
+ int shmall;
+};
+
+asmlinkage long sys_shmctlold(int shmid, int cmd, struct shmid_ds_old *buf)
+{
+ struct shmid_ds arg;
+ long ret;
+ mm_segment_t old_fs;
+
+ if (cmd == IPC_SET) {
+ struct shmid_ds_old tbuf;
+
+ if(copy_from_user (&tbuf, buf, sizeof(*buf)))
+ return -EFAULT;
+ arg.shm_perm = tbuf.shm_perm;
+ arg.shm_segsz = tbuf.shm_segsz;
+ arg.shm_atime = tbuf.shm_atime;
+ arg.shm_dtime = tbuf.shm_dtime;
+ arg.shm_ctime = tbuf.shm_ctime;
+ arg.shm_cpid = tbuf.shm_cpid;
+ arg.shm_lpid = tbuf.shm_lpid;
+ arg.shm_nattch = tbuf.shm_nattch;
+ arg.shm_unused = tbuf.shm_unused;
+ arg.shm_unused2 = tbuf.shm_unused2;
+ arg.shm_unused3 = tbuf.shm_unused3;
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ ret = sys_shmctl(shmid, cmd, &arg);
+ set_fs (old_fs);
+ if (ret < 0)
+ return(ret);
+ switch(cmd) {
+ case IPC_INFO:
+ {
+ struct shminfo *tbuf = (struct shminfo *) &arg;
+ struct shminfo_old shminfo_oldst;
+
+ shminfo_oldst.shmmax = (tbuf->shmmax > INT_MAX ?
+ INT_MAX : tbuf->shmmax);
+ shminfo_oldst.shmmin = tbuf->shmmin;
+ shminfo_oldst.shmmni = tbuf->shmmni;
+ shminfo_oldst.shmseg = tbuf->shmseg;
+ shminfo_oldst.shmall = tbuf->shmall;
+ if (copy_to_user(buf, &shminfo_oldst,
+ sizeof(struct shminfo_old)))
+ return -EFAULT;
+ return(ret);
+ }
+ case SHM_INFO:
+ {
+ struct shm_info *tbuf = (struct shm_info *) &arg;
+
+ if (copy_to_user (buf, tbuf, sizeof(struct shm_info)))
+ return -EFAULT;
+ return(ret);
+ }
+ case SHM_STAT:
+ case IPC_STAT:
+ {
+ struct shmid_ds_old tbuf;
+
+ tbuf.shm_perm = arg.shm_perm;
+ tbuf.shm_segsz = arg.shm_segsz;
+ tbuf.shm_atime = arg.shm_atime;
+ tbuf.shm_dtime = arg.shm_dtime;
+ tbuf.shm_ctime = arg.shm_ctime;
+ tbuf.shm_cpid = arg.shm_cpid;
+ tbuf.shm_lpid = arg.shm_lpid;
+ tbuf.shm_nattch = arg.shm_nattch;
+ tbuf.shm_unused = arg.shm_unused;
+ tbuf.shm_unused2 = arg.shm_unused2;
+ tbuf.shm_unused3 = arg.shm_unused3;
+ if (copy_to_user (buf, &tbuf, sizeof(tbuf)))
+ return -EFAULT;
+ return(ret);
+ }
+ }
+ return(ret);
+}
source net/Config.in
fi
+source drivers/telephony/Config.in
+
mainmenu_option next_comment
comment 'SCSI support'
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
macintosh video dio zorro fc4 usb \
- nubus tc ap1000 atm pcmcia i2c
+ nubus tc ap1000 atm pcmcia i2c telephony
ifdef CONFIG_DIO
SUB_DIRS += dio
endif
endif
+ifeq ($(CONFIG_PHONE),y)
+SUB_DIRS += telephony
+MOD_SUB_DIRS += telephony
+else
+ ifeq ($(CONFIG_PHONE),m)
+ MOD_SUB_DIRS += telephony
+ endif
+endif
+
ifdef CONFIG_SGI
SUB_DIRS += sgi
MOD_SUB_DIRS += sgi
tristate 'Video For Linux' CONFIG_VIDEO_DEV
if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT
- comment 'Radio/Video Adapters'
+ comment 'Radio Adapters'
dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
fi
- if [ "$CONFIG_PCI" != "n" ]; then
- dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
- fi
dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
fi
- dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
- if [ "$CONFIG_PMAC" = "y" ]; then
- dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
- fi
- if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
- fi
- fi
- dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_SGI" = "y" ]; then
- dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
- fi
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV
- fi
dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
fi
- dep_tristate ' Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI
+ comment 'Video Adapters'
+ dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI
+ dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_PARPORT" != "n" ]; then
+ dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
+ fi
+ fi
+ dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_SGI" = "y" ]; then
+ dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI
+ 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 ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN
- dep_tristate ' Zoran ZR36120/36125 support' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI
+ dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI
fi
endmenu
MODULE_PARM(pll,"1-4i");
MODULE_PARM(bigendian,"i");
MODULE_PARM(fieldnr,"i");
+MODULE_PARM(autoload,"i");
#if defined(__sparc__) || defined(__powerpc__)
static unsigned int bigendian=1;
static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 };
static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0};
static unsigned int fieldnr = 0;
+static unsigned int autoload = 1;
#define I2C_TIMING (0x7<<4)
}
/* read I2C */
-static int I2CRead(struct bttv *btv, unsigned char addr)
+static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
{
unsigned char buffer = 0;
+ if (NULL != probe_for)
+ printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
+ btv->nr,probe_for,addr);
btv->i2c_client.addr = addr >> 1;
if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
- printk("bttv%d: i2c read 0x%x: error\n",btv->nr,addr);
+ if (NULL != probe_for)
+ printk("not found\n");
+ else
+ printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
+ btv->nr,addr);
return -1;
}
- printk("bttv%d: i2c read 0x%x: %d\n",btv->nr,addr,buffer);
+ if (NULL != probe_for)
+ printk("found\n");
return buffer;
}
printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
tmp=I2CWrite(btv,0x1E,0x08,0,1);
- printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x09,0,1);
- printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x0a,0,1);
- printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x0b,0,1);
- printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x0c,0,1);
- printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x0d,0,1);
- printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x01,0,1);
- printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x02,0,1);
- printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x03,0,1);
- printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x04,0,1);
- printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x05,0,1);
- printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x06,0,1);
- printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
tmp=I2CWrite(btv,0x1E,0x00,0,1);
- printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F));
+ printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
printk(KERN_INFO "PXC200 Initialised.\n");
}
3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
1,1,1,1,0 },
{ "AVerMedia TVCapture 98",
- 3, 1, 4, 0, 15, { 2, 3, 1, 0, 0}, { 13, 14, 11, 7, 0, 0},0,
+ 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
1,1,1,1,0 },
{ "Aimslab VHX",
3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
{ "Askey/Typhoon/Anubis Magic TView",
3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
1,1,1,1,0 },
+ { "Terratec TerraTValue",
+ 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
+ 1,1,1,1,0 },
};
#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
/* ----------------------------------------------------------------------- */
-static void audio(struct bttv *btv, int mode)
+static void audio(struct bttv *btv, int mode, int no_irq_context)
{
btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask,
BT848_GPIO_OUT_EN);
mode = AUDIO_RADIO;
btaor(tvcards[btv->type].audiomux[mode],
~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
- call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
+ if (no_irq_context)
+ call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
}
}
btaor((tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);
audio(btv, (input!=tvcards[btv->type].tuner) ?
- AUDIO_EXTERN : AUDIO_TUNER);
+ AUDIO_EXTERN : AUDIO_TUNER, 1);
btaor(tvcards[btv->type].muxsel[input]>>4,
~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
}
static void bt848_set_geo(struct bttv *btv, u16 width, u16 height,
- u16 fmt, int pllset)
+ u16 fmt, int no_irq_context)
{
u16 vscale, hscale;
u32 xsf, sr;
btwrite(1, BT848_VBI_PACK_DEL);
btv->pll.pll_ofreq = tvn->Fsc;
- if (pllset)
+ if (no_irq_context)
set_pll(btv);
btwrite(fmt, BT848_COLOR_FMT);
{
struct bttv *btv=(struct bttv *)dev;
int i;
-
+
switch (cmd) {
case VIDIOCGCAP:
{
return -EFAULT;
down(&btv->lock);
if(v.flags&VIDEO_AUDIO_MUTE)
- audio(btv, AUDIO_MUTE);
+ audio(btv, AUDIO_MUTE, 1);
/* One audio source per tuner -- huh? <GA> */
if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) {
up(&btv->lock);
}
/* bt848_muxsel(btv,v.audio); */
if(!(v.flags&VIDEO_AUDIO_MUTE))
- audio(btv, AUDIO_UNMUTE);
+ audio(btv, AUDIO_UNMUTE, 1);
+ up(&btv->lock);
call_i2c_clients(btv,cmd,&v);
+ down(&btv->lock);
if (btv->type == BTTV_TERRATV) {
unsigned int con = 0;
*/
if (btv->type == BTTV_UNKNOWN)
{
- if (I2CRead(btv, I2C_HAUPEE)>=0)
+ if (I2CRead(btv, I2C_HAUPEE, "eeprom")>=0)
{
if(btv->id>849)
btv->type=BTTV_HAUPPAUGE878;
else
btv->type=BTTV_HAUPPAUGE;
- } else if (I2CRead(btv, I2C_STBEE)>=0) {
+ } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) {
btv->type=BTTV_STB;
#if 0 /* bad idea: 0xc0 is used for the tuner on _many_ boards */
#endif
} else {
- if (I2CRead(btv, 0x80)>=0) /* check for msp34xx */
+ if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */
btv->type = BTTV_MIROPRO;
else
btv->type = BTTV_MIRO;
/* try to detect audio/fader chips */
if (tvcards[btv->type].msp34xx &&
- I2CRead(btv, I2C_MSP3400) >=0) {
- printk(KERN_INFO "bttv%d: audio chip: MSP34xx\n",i);
- request_module("msp3400");
+ I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
+ if (autoload)
+ request_module("msp3400");
}
if (tvcards[btv->type].tda8425 &&
- I2CRead(btv, I2C_TDA8425) >=0) {
- printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",i);
- request_module("tda8425");
+ I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) {
+ if (autoload)
+ request_module("tda8425");
}
if (tvcards[btv->type].tda9840 &&
- I2CRead(btv, I2C_TDA9840) >=0) {
+ I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) {
init_tda9840(btv);
- printk(KERN_INFO "bttv%d: audio chip: TDA9840\n", i);
btv->audio_chip = TDA9840;
/* move this to a module too? */
init_tda9840(btv);
}
if (tvcards[btv->type].tda985x &&
- I2CRead(btv, I2C_TDA9850) >=0) {
- printk(KERN_INFO "bttv%d: audio chip: TDA985x\n",i);
- request_module("tda9855");
+ I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) {
+ if (autoload)
+ request_module("tda9855");
}
if (tvcards[btv->type].tea63xx &&
- I2CRead(btv, I2C_TEA6300)) {
- printk(KERN_INFO "bttv%d: fader chip: TEA63xx\n",i);
- request_module("tea6300");
+ I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0) {
+ if (autoload)
+ request_module("tea6300");
}
if (tvcards[btv->type].tuner != -1) {
- request_module("tuner");
+ if (autoload)
+ request_module("tuner");
}
- audio(btv, AUDIO_MUTE);
+ audio(btv, AUDIO_MUTE, 1);
}
if (astat&BT848_INT_HLOCK)
{
if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
- audio(btv, AUDIO_ON);
+ audio(btv, AUDIO_ON,0);
else
- audio(btv, AUDIO_OFF);
+ audio(btv, AUDIO_OFF,0);
}
if (astat&BT848_INT_I2CDONE)
{
+ IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr));
}
count++;
#ifndef _BTTV_H_
#define _BTTV_H_
-#define BTTV_VERSION_CODE 0x00070a
+#define BTTV_VERSION_CODE 0x00070b
#include <linux/types.h>
#include <linux/wait.h>
mdelay(10);
zr36060_reset(zr);
mdelay(10);
- zr36060_sleep(zr, 1);
- mdelay(10);
/* display codec revision */
if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
udelay(3000);
zr36060_reset(zr);
udelay(3000);
- zr36060_sleep(zr, 1);
- udelay(3000);
/* display codec revision */
if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) {
zr->name, zr36060_read_8(zr, 0x023));
} else {
printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev);
-// kfree((void *) zr->stat_com);
-// return -1;
+ kfree((void *) zr->stat_com);
+ return -1;
}
break;
}
#ifdef CONFIG_USB
extern void usb_init(void);
#endif
+#ifdef CONFIG_PHONE
+extern void telephony_init(void);
+#endif
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
const char * buf, size_t count, loff_t *ppos)
#ifdef CONFIG_USB
usb_init();
#endif
+#ifdef CONFIG_I2C
+ i2c_init_all();
+#endif
#if defined (CONFIG_FB)
fbmem_init();
#endif
#ifdef CONFIG_FTAPE
ftape_init();
#endif
-#ifdef CONFIG_I2C
- i2c_init_all();
-#endif
-
#ifdef CONFIG_VIDEO_BT848
i2c_init();
#endif
#ifdef CONFIG_VIDEO_DEV
videodev_init();
#endif
+#ifdef CONFIG_PHONE
+ telephony_init();
+#endif
return 0;
}
#include <linux/videodev.h>
#include "linux/video_decoder.h"
-#define DEBUG(x...) x /* remove when no long debugging */
+#define DEBUG(x...) /* remove when no long debugging */
#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */
#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */
else {
saa7110_write(decoder,0x21,0x16);
saa7110_write(decoder,0x0D,0x04);
- printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder));
+ DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder)));
saa7110_write(decoder,0x0D,0x06);
}
static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data)
{
int ack;
- unsigned long flags;
LOCK_I2C_BUS(dev->bus);
i2c_start(dev->bus);
static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len)
{
- int ack;
+ int ack = 0;
unsigned subaddr;
- unsigned long flags;
while (len > 1) {
LOCK_I2C_BUS(dev->bus);
static int saa7111_read(struct saa7111 *dev, unsigned char subaddr)
{
int data;
- unsigned long flags;
LOCK_I2C_BUS(dev->bus);
i2c_start(dev->bus);
static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data)
{
int ack;
- unsigned long flags;
LOCK_I2C_BUS(dev->bus);
static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len)
{
- int ack;
+ int ack = 0;
unsigned subaddr;
- unsigned long flags;
while (len > 1) {
LOCK_I2C_BUS(dev->bus);
static struct i2c_driver driver = {
"i2c tda9855 driver",
- I2C_DRIVERID_TDA9855, /* FIXME */
+ I2C_DRIVERID_TDA9855,
I2C_DF_NOTIFY,
tda9855_probe,
tda9855_detach,
static int tea6300_write(struct i2c_client *client, int addr, int val)
{
unsigned char buffer[2];
-
+
buffer[0] = addr;
buffer[1] = val;
if (2 != i2c_master_send(client,buffer,2)) {
static struct i2c_driver driver = {
"i2c tea6300 driver",
- I2C_DRIVERID_TEA6300, /* FIXME */
+ I2C_DRIVERID_TEA6300,
I2C_DF_NOTIFY,
tea6300_probe,
tea6300_detach,
};
static int debug = 0; /* insmod parameter */
-static int type = -1; /* insmod parameter */
+static int type = -1; /* insmod parameter */
+
+static int addr = 0;
+static int this_adap;
#define dprintk if (debug) printk
MODULE_PARM(debug,"i");
MODULE_PARM(type,"i");
+MODULE_PARM(addr,"i");
struct tuner
{
else
config = tun->UHF;
-#if 0 // Fix colorstandard mode change
+#if 1 // Fix colorstandard mode change
if (t->type == TUNER_PHILIPS_SECAM
- && t->std == V4L2_STANDARD_DDD )
+ /*&& t->std == V4L2_STANDARD_DDD*/ )
config |= tun->mode;
else
config &= ~tun->mode;
struct tuner *t;
struct i2c_client *client;
+ if (this_adap > 0)
+ return -1;
+ this_adap++;
+
client_template.adapter = adap;
client_template.addr = addr;
static int tuner_probe(struct i2c_adapter *adap)
{
+ if (0 != addr) {
+ normal_i2c_range[0] = addr;
+ normal_i2c_range[1] = addr;
+ }
+ this_adap = 0;
if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
return i2c_probe(adap, &addr_data, tuner_attach);
return 0;
#ifdef CONFIG_VIDEO_ZORAN
extern int init_zoran_cards(struct video_init *);
#endif
-#ifdef CONFIG_VIDEO_ZR36120
-extern int init_zr36120_cards(struct video_init *);
-#endif
static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
#endif
#ifdef CONFIG_VIDEO_ZORAN
{"zoran", init_zoran_cards},
-#endif
-#ifdef CONFIG_VIDEO_ZR36120
- {"zr36120", init_zr36120_cards},
#endif
{"end", NULL}
};
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
+#include <linux/video_decoder.h>
#include <asm/segment.h>
#include <linux/version.h>
#include <asm/uaccess.h>
-#include "linux/video_decoder.h"
#include "tuner.h"
#include "zr36120.h"
#include "zr36120_mem.h"
+/* mark an required function argument unused - lintism */
+#define UNUSED(x) (void)(x)
+
/* sensible default */
#ifndef CARDTYPE
#define CARDTYPE 0
/* Anybody who uses more than four? */
#define ZORAN_MAX 4
-static ulong irq1 = 0;
-
- unsigned int triton1=0; /* triton1 chipset? */
+static unsigned int triton1=0; /* triton1 chipset? */
static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE };
MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>");
#undef F
#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0]))
-static struct { const char name[8]; int mode; int bpp; } palette2fmt[] = {
+#ifdef __sparc__
+#define ENDIANESS 0
+#else
+#define ENDIANESS ZORAN_VFEC_LE
+#endif
+
+static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = {
/* n/a */ { "n/a", 0, 0 },
/* GREY */ { "GRAY", 0, 0 },
/* HI240 */ { "HI240", 0, 0 },
-/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ZORAN_VFEC_LE, 2 },
-/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24, 3 },
-/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE, 4 },
-/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ZORAN_VFEC_LE, 2 },
-/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ZORAN_VFEC_LE, 3 },
+/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 },
+/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 },
+/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 },
+/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 },
+/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 },
/* YUYV */ { "YUYV", 0, 0 },
/* UYVY */ { "UYVY", 0, 0 },
/* YUV420 */ { "YUV420", 0, 0 },
/* YUV422P */ { "YUV422P", 0, 0 },
/* YUV411P */ { "YUV411P", 0, 0 }};
#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0]))
+#undef ENDIANESS
/* ----------------------------------------------------------------------- */
-/* ZORAN chipset detector */
-/* shamelessly stolen from bttv.c */
+/* ZORAN chipset detector */
+/* shamelessly stolen from bttv.c */
/* Reason for beeing here: we need to detect if we are running on a */
/* Triton based chipset, and if so, enable a certain bit */
/* ----------------------------------------------------------------------- */
-
-void handle_chipset(void)
+static
+void __init handle_chipset(void)
{
struct pci_dev *dev = NULL;
-
+
/* Just in case some nut set this to something dangerous */
if (triton1)
triton1 = ZORAN_VDC_TRICOM;
-
- while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev)))
+
+ while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev)))
{
printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n");
triton1 = ZORAN_VDC_TRICOM;
static
void zoran_dump(struct zoran *ztv)
{
- char str[1024];
+ char str[256];
char *p=str; /* shut up, gcc! */
int i;
for (i=0; i<0x60; i+=4) {
if ((i % 16) == 0) {
- if (i) printk(/*KERN_DEBUG*/ "%s\n",str);
+ if (i) printk("%s\n",str);
p = str;
- p+= sprintf(str, " %04x: ",i);
+ p+= sprintf(str, KERN_DEBUG " %04x: ",i);
}
p += sprintf(p, "%08x ",zrread(i));
}
static
void reap_states(struct zoran* ztv)
{
- irq1++; /* debugging... */
+ /* count frames */
+ ztv->fieldnr++;
/*
- * GRABBING?
+ * Are we busy at all?
+ * This depends on if there is a workqueue AND the
+ * videotransfer is enabled on the chip...
*/
- if ( test_bit(STATE_GRAB, &ztv->state) ) {
- int i;
+ if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
+ {
+ struct vidinfo* newitem;
+
+ /* did we get a complete frame? */
+ if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
+ return;
- /* are we already grabbing? */
- if (test_bit(STATE_GRAB, &ztv->prevstate)) {
+DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
- /* did we get a complete grab? */
- if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
- goto out;
+ /* we are done with this buffer, tell everyone */
+ ztv->workqueue->status = FBUFFER_DONE;
+ ztv->workqueue->fieldnr = ztv->fieldnr;
+ /* not good, here for BTTV_FIELDNR reasons */
+ ztv->lastfieldnr = ztv->fieldnr;
- /* we are done with this buffer, tell everyone */
- ztv->grabinfo[ztv->lastframe].status = FBUFFER_DONE;
+ switch (ztv->workqueue->kindof) {
+ case FBUFFER_GRAB:
wake_up_interruptible(&ztv->grabq);
+ break;
+ case FBUFFER_VBI:
+ wake_up_interruptible(&ztv->vbiq);
+ break;
+ default:
+ printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof);
}
- /* locate a new frame to grab */
- for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
- if (ztv->grabinfo[i].status == FBUFFER_GRABBING) {
-
- /* there is a buffer more to be grabbed... */
- ztv->lastframe = i;
-
-DEBUG(printk(KERN_DEBUG "irq(%ld): starting grab(%d)\n",irq1,i));
-
- /* loadup the frame settings */
- read_lock(&ztv->lock);
- zoran_set_geo(ztv,&ztv->grabinfo[i]);
- read_unlock(&ztv->lock);
-
- zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
- zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
- zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
- zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
-
- /* start single-shot grab */
- zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
- goto out;
- }
-
-DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to grab\n",irq1));
-
- /* turn grabbing off the next time around */
- clear_bit(STATE_GRAB, &ztv->state);
-
- /* force re-init of Read or Overlay settings */
- clear_bit(STATE_READ, &ztv->prevstate);
- clear_bit(STATE_OVERLAY, &ztv->prevstate);
+ /* item completed, skip to next item in queue */
+ write_lock(&ztv->lock);
+ newitem = ztv->workqueue->next;
+ ztv->workqueue->next = 0; /* mark completed */
+ ztv->workqueue = newitem;
+ write_unlock(&ztv->lock);
}
/*
- * READING?
+ * ok, so it seems we have nothing in progress right now.
+ * Lets see if we can find some work.
*/
- if ( test_bit(STATE_READ, &ztv->state) ) {
- /* are we already reading? */
- if (!test_bit(STATE_READ, &ztv->prevstate)) {
+ if (ztv->workqueue)
+ {
+ struct vidinfo* newitem;
+again:
-DEBUG(printk(KERN_DEBUG "irq(%ld): starting read\n",irq1));
+DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue));
- read_lock(&ztv->lock);
- zoran_set_geo(ztv,&ztv->readinfo);
- read_unlock(&ztv->lock);
+ /* loadup the frame settings */
+ read_lock(&ztv->lock);
+ zoran_set_geo(ztv,ztv->workqueue);
+ read_unlock(&ztv->lock);
- zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
+ switch (ztv->workqueue->kindof) {
+ case FBUFFER_GRAB:
+ case FBUFFER_VBI:
zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
/* start single-shot grab */
zror(ZORAN_VSTR_GRAB, ZORAN_VSTR);
- goto out;
+ break;
+ default:
+ printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof);
+ write_lock(&ztv->lock);
+ newitem = ztv->workqueue->next;
+ ztv->workqueue->next = 0;
+ ztv->workqueue = newitem;
+ write_unlock(&ztv->lock);
+ if (newitem)
+ goto again; /* yeah, sure.. */
}
-
- /* did we get a complete grab? */
- if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB)
- goto out;
-
-DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to read\n",irq1));
-
- /* turn reading off the next time around */
- clear_bit(STATE_READ, &ztv->state);
- /* force re-init of Overlay settings */
- clear_bit(STATE_OVERLAY, &ztv->prevstate);
-
- /* we are done, tell everyone */
- wake_up_interruptible(&ztv->readq);
+ /* bye for now */
+ return;
}
+DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD));
/*
- * OVERLAYING?
+ * What? Even the workqueue is empty? Am i really here
+ * for nothing? Did i come all that way to... do nothing?
*/
- if ( test_bit(STATE_OVERLAY, &ztv->state) ) {
- /* are we already overlaying? */
- if (!test_bit(STATE_OVERLAY, &ztv->prevstate)) {
-DEBUG(printk(KERN_DEBUG "irq(%ld): starting overlay\n",irq1));
+ /* do we need to overlay? */
+ if (test_bit(STATE_OVERLAY, &ztv->state))
+ {
+ /* are we already overlaying? */
+ if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) ||
+ !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN))
+ {
+DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD));
read_lock(&ztv->lock);
zoran_set_geo(ztv,&ztv->overinfo);
read_unlock(&ztv->lock);
- zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
- zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
zror(ZORAN_OCR_OVLEN, ZORAN_OCR);
+ zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR);
zror(ZORAN_VDC_VIDEN,ZORAN_VDC);
}
* leave overlaying on, but turn interrupts off.
*/
zrand(~ZORAN_ICR_EN,ZORAN_ICR);
- goto out;
+ return;
+ }
+
+ /* do we have any VBI idle time processing? */
+ if (test_bit(STATE_VBI, &ztv->state))
+ {
+ struct vidinfo* item;
+ struct vidinfo* lastitem;
+
+ /* protect the workqueue */
+ write_lock(&ztv->lock);
+ lastitem = ztv->workqueue;
+ if (lastitem)
+ while (lastitem->next) lastitem = lastitem->next;
+ for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+ if (item->next == 0 && item->status == FBUFFER_FREE)
+ {
+DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item));
+ item->status = FBUFFER_BUSY;
+ if (!lastitem)
+ ztv->workqueue = item;
+ else
+ lastitem->next = item;
+ lastitem = item;
+ }
+ write_unlock(&ztv->lock);
+ if (ztv->workqueue)
+ goto again; /* hey, _i_ graduated :) */
}
/*
- * THEN WE MUST BE IDLING
+ * Then we must be realy IDLE
*/
-DEBUG(printk(KERN_DEBUG "irq(%ld): turning off\n",irq1));
+DEBUG(printk(CARD_DEBUG "turning off\n",CARD));
/* nothing further to do, disable DMA and further IRQs */
zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
zrand(~ZORAN_ICR_EN,ZORAN_ICR);
-out:
- ztv->prevstate = ztv->state;
}
static
int count = 0;
struct zoran *ztv = (struct zoran *)dev_id;
+ UNUSED(irq); UNUSED(regs);
for (;;) {
/* get/clear interrupt status bits */
stat=zrread(ZORAN_ISR);
if (!estat)
return;
zrwrite(estat,ZORAN_ISR);
- IDEBUG(printk(KERN_DEBUG "%s: estat %08x\n",CARD,estat));
- IDEBUG(printk(KERN_DEBUG "%s: stat %08x\n",CARD,stat));
+ IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat));
+ IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat));
if (estat & ZORAN_ISR_CODE)
{
- IDEBUG(printk(KERN_DEBUG "%s: CodReplIRQ\n",CARD));
+ IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD));
}
if (estat & ZORAN_ISR_GIRQ0)
{
- IDEBUG(printk(KERN_DEBUG "%s: GIRQ0\n",CARD));
+ IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD));
if (!ztv->card->usegirq1)
reap_states(ztv);
}
if (estat & ZORAN_ISR_GIRQ1)
{
- IDEBUG(printk(KERN_DEBUG "%s: GIRQ1\n",CARD));
+ IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD));
if (ztv->card->usegirq1)
reap_states(ztv);
}
count++;
if (count > 10)
- printk(KERN_ERR "%s: irq loop %d (%x)\n",CARD,count,estat);
+ printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat);
if (count > 20)
{
zrwrite(0, ZORAN_ICR);
- printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n",CARD);
- }
- }
-}
-
-/*
- * Scan for a Zoran chip, request the irq and map the io memory
- */
-static int find_zoran(void)
-{
- unsigned char command, latency;
- int result;
- struct zoran *ztv;
- struct pci_dev *dev;
- int zoran_num=0;
-
- if (!pcibios_present())
- {
- DEBUG(printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n"));
- return 0;
- }
-
- for (dev = pci_devices; dev != NULL; dev = dev->next)
- {
- if (dev->vendor != PCI_VENDOR_ID_ZORAN)
- continue;
- if (dev->device != PCI_DEVICE_ID_ZORAN_36120)
- continue;
-
- /* Ok, ZR36120 found! */
- ztv=&zorans[zoran_num];
- ztv->dev=dev;
- ztv->id=dev->device;
- ztv->zoran_mem=NULL;
-
- ztv->zoran_adr = ztv->dev->resource[0].start;
- pci_read_config_byte(ztv->dev, PCI_CLASS_REVISION,
- &ztv->revision);
- printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
- ztv->id, ztv->revision);
- printk("bus: %d, devfn: %d, ",
- ztv->dev->bus->number, ztv->dev->devfn);
- printk("irq: %d, ",ztv->dev->irq);
- printk("memory: 0x%08x.\n", ztv->zoran_adr);
-
- ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000);
- DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
-
- result = request_irq(ztv->dev->irq, zoran_irq,
- SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv);
- if (result==-EINVAL)
- {
- printk(KERN_ERR "zoran: Bad irq number or handler\n");
- return -EINVAL;
- }
- if (result==-EBUSY)
- {
- printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",ztv->dev->irq);
- return result;
+ printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD);
}
- if (result < 0)
- return result;
-
- /* Enable bus-mastering */
- pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
- command|=PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY;
- pci_write_config_byte(ztv->dev, PCI_COMMAND, command);
- pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
- if (!(command&PCI_COMMAND_MASTER))
- {
- printk(KERN_ERR "zoran: PCI bus-mastering could not be enabled\n");
- return -1;
- }
- pci_read_config_byte(ztv->dev, PCI_LATENCY_TIMER, &latency);
- if (!latency)
- {
- latency=32;
- pci_write_config_byte(ztv->dev, PCI_LATENCY_TIMER, latency);
- DEBUG(printk(KERN_INFO "zoran: latency set to %d\n",latency));
- }
- zoran_num++;
}
- if(zoran_num)
- printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num);
- return zoran_num;
}
static
static
void zoran_cap(struct zoran* ztv, int on)
{
- DEBUG(printk(KERN_DEBUG " zoran_cap(%d) at %ld, state=%x\n",on,irq1,ztv->state));
+DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state));
if (on) {
ztv->running = 1;
- /*
- * Clear the previous state flag. This way the irq
- * handler will be forced to re-examine its current
- * state from scratch, setting up the registers along
- * the way.
- */
- clear_bit(STATE_OVERLAY, &ztv->prevstate);
+
/*
- * turn interrupts back on. The DMA will be enabled
+ * turn interrupts (back) on. The DMA will be enabled
* inside the irq handler when it detects a restart.
*/
- zror(ZORAN_ICR_CODE|ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1,ZORAN_ICR);
zror(ZORAN_ICR_EN,ZORAN_ICR);
}
else {
- ztv->running = 0;
/*
- * turn interrupts and DMA both off
+ * turn both interrupts and DMA off
*/
zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
zrand(~ZORAN_ICR_EN,ZORAN_ICR);
+
+ ztv->running = 0;
}
}
{
ulong* mtop;
int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */
- int mult = ztv->interlace; /* double height? */
int i;
- DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count));
- if (ztv->overinfo.overlay == 0) {
- zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR);
- return;
- }
-
-for (i=0; i<count; i++) {
- struct video_clip *vp = vcp+i;
- DEBUG(printk(KERN_DEBUG " %d: clip(%d,%d,%d,%d)\n",
- i,vp->x,vp->y,vp->width,vp->height));
-}
+DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count));
- /* clear entire blob */
-/* memset(ztv->overinfo.overlay, 0, 1024*1024/8); */
+ for (i=0; i<count; i++) {
+ struct video_clip *vp = vcp+i;
+ UNUSED(vp);
+DEBUG(printk(KERN_DEBUG " %d: clip(%d,%d,%d,%d)\n", i,vp->x,vp->y,vp->width,vp->height));
+ }
/*
* activate the visible portion of the screen
/* process clipping regions */
for (i=0; i<count; i++) {
int h;
- if (vcp->x < 0 || vcp->x > ztv->overinfo.w ||
+ if (vcp->x < 0 || (uint)vcp->x > ztv->overinfo.w ||
vcp->y < 0 || vcp->y > ztv->overinfo.h ||
- vcp->width < 0 || (vcp->x+vcp->width) > ztv->overinfo.w ||
+ vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w ||
vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h)
{
- DEBUG(printk(KERN_DEBUG "%s: illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h));
+ DEBUG(printk(CARD_DEBUG "illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h));
if (vcp->x < 0) vcp->x = 0;
- if (vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w;
+ if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w;
if (vcp->y < 0) vcp->y = 0;
if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h;
if (vcp->width < 0) vcp->width = 0;
- if (vcp->x+vcp->width > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x;
+ if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x;
if (vcp->height < 0) vcp->height = 0;
if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y;
// continue;
mtop = ztv->overinfo.overlay;
zrwrite(virt_to_bus(mtop), ZORAN_MTOP);
zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT);
- zraor((mult*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
+ zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR);
}
struct tvnorm
};
#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
+/*
+ * Program the chip for a setup as described in the vidinfo struct.
+ *
+ * Side-effects: calculates vidXshift, vidInterlace,
+ * vidHeight, vidWidth which are used in a later stage
+ * to calculate the overlay mask
+ *
+ * This is an internal function, as such it does not check the
+ * validity of the struct members... Spectaculair crashes will
+ * follow /very/ quick when you're wrong and the chip right :)
+ */
static
void zoran_set_geo(struct zoran* ztv, struct vidinfo* i)
{
int stride;
int winWidth, winHeight;
int maxWidth, maxHeight, maxXOffset, maxYOffset;
- int filter;
+ long vfec;
- DEBUG(printk(KERN_DEBUG " set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, vidadr=%lx, overlay=%p)\n", i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->vidadr,i->overlay));
+DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay));
/*
* make sure the DMA transfers are inhibited during our
zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC);
maxWidth = tvnorms[ztv->norm].Wa;
- maxHeight = tvnorms[ztv->norm].Ha;
+ maxHeight = tvnorms[ztv->norm].Ha/2;
maxXOffset = tvnorms[ztv->norm].HStart;
maxYOffset = tvnorms[ztv->norm].VStart;
+ /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */
+ vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) |
+ (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24));
+
/*
* Set top, bottom ptrs. Since these must be DWORD aligned,
* possible adjust the x and the width of the window.
*/
ztv->vidXshift = 0;
winWidth = i->w;
- top = i->vidadr + i->x*i->bpp + i->y*i->bpl;
+ if (winWidth < 0)
+ winWidth = -winWidth;
+ top = i->busadr + i->x*i->bpp + i->y*i->bpl;
if (top & 3) {
ztv->vidXshift = (top & 3) / i->bpp;
winWidth += ztv->vidXshift;
* next line is DWORD aligned too (as required by spec).
*/
if ((winWidth*i->bpp) & 3) {
- DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3));
+DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3));
winWidth += (winWidth*i->bpp) & 3;
}
/* determine the DispMode and stride */
- if (i->h <= maxHeight/2) {
- /* single frame suffices for this height */
- zror(ZORAN_VFEC_DISPMOD, ZORAN_VFEC);
- ztv->interlace = 0;
- winHeight = i->h;
- if (winHeight < 0) /* can happen for read's! */
- winHeight = -winHeight;
+ if (i->h >= 0 && i->h <= maxHeight) {
+ /* single frame grab suffices for this height. */
+ vfec |= ZORAN_VFEC_DISPMOD;
+ ztv->vidInterlace = 0;
stride = i->bpl - (winWidth*i->bpp);
+ winHeight = i->h;
}
else {
/* interleaving needed for this height */
- zrand(~ZORAN_VFEC_DISPMOD, ZORAN_VFEC);
- ztv->interlace = 1;
- winHeight = i->h/2;
+ ztv->vidInterlace = 1;
stride = i->bpl*2 - (winWidth*i->bpp);
+ winHeight = i->h/2;
}
+ if (winHeight < 0) /* can happen for VBI! */
+ winHeight = -winHeight;
+
/* safety net, sometimes bpl is too short??? */
if (stride<0) {
- DEBUG(printk(KERN_DEBUG "%s: WARNING stride = %d\n",CARD,stride));
+DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride));
stride = 0;
}
/* remember vidWidth, vidHeight for overlay calculations */
ztv->vidWidth = winWidth;
ztv->vidHeight = winHeight;
-DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx, winWidth=%d, winHeight=%d, maxWidth=%d, maxHeight=%d, stride=%d\n",top,bot,winWidth,winHeight,maxWidth,maxHeight,stride));
-
- /* determine scales and crops */
- if (1) {
- int Wa, X, We, HorDcm, hcrop1, hcrop2, Hstart, Hend;
-
-A: Wa = maxWidth;
- X = (winWidth*64+Wa-1)/Wa;
- We = winWidth*64/X;
- HorDcm = 64-X;
- hcrop1 = 2*(Wa-We)/4;
- hcrop2 = Wa-We-hcrop1;
- Hstart = maxXOffset + hcrop1;
- Hend = maxXOffset + Wa-1-hcrop2;
+DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot));
+DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight));
+DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight));
+DEBUG(printk(KERN_DEBUG " stride=%d\n",stride));
+ /*
+ * determine horizontal scales and crops
+ */
+ if (i->w < 0) {
+ int Hstart = 1;
+ int Hend = Hstart + winWidth;
+DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend));
+ zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
+ }
+ else {
+ int Wa = maxWidth;
+ int X = (winWidth*64+Wa-1)/Wa;
+ int We = winWidth*64/X;
+ int HorDcm = 64-X;
+ int hcrop1 = 2*(Wa-We)/4;
/*
* BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi>
* found the solution to the color phase shift.
* See ChangeLog for the full explanation)
*/
- if (!(Hstart & 1)) {
-DEBUG(printk(KERN_DEBUG " correcting horizontal start/end by one\n"));
- winWidth--;
- goto A;
- }
+ int Hstart = (maxXOffset + hcrop1) | 1;
+ int Hend = Hstart + We - 1;
DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend));
zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH);
- zraor((HorDcm<<14),~ZORAN_VFEC_HORDCM, ZORAN_VFEC);
-
- filter = ZORAN_VFEC_HFILTER_1;
- if (HorDcm >= 48)
- filter = ZORAN_VFEC_HFILTER_5; /* 5 tap filter */
- else if (HorDcm >= 32)
- filter = ZORAN_VFEC_HFILTER_4; /* 4 tap filter */
- else if (HorDcm >= 16)
- filter = ZORAN_VFEC_HFILTER_3; /* 3 tap filter */
- zraor(filter, ~ZORAN_VFEC_HFILTER, ZORAN_VFEC);
+ vfec |= HorDcm<<14;
+
+ if (HorDcm<16)
+ vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */
+ else if (HorDcm<32)
+ vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */
+ else if (HorDcm<48)
+ vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */
+ else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */
}
- /* when height is negative, we want to read from line 0 */
+
+ /*
+ * Determine vertical scales and crops
+ *
+ * when height is negative, we want to read starting at line 0
+ * One day someone might need access to these lines...
+ */
if (i->h < 0) {
int Vstart = 0;
int Vend = Vstart + winHeight;
- int VerDcm = 0;
-DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
+DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend));
zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
- zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC);
}
else {
- int Ha = maxHeight/2;
+ int Ha = maxHeight;
int Y = (winHeight*64+Ha-1)/Ha;
int He = winHeight*64/Y;
int VerDcm = 64-Y;
int vcrop1 = 2*(Ha-He)/4;
- int vcrop2 = Ha-He-vcrop1;
int Vstart = maxYOffset + vcrop1;
- int Vend = maxYOffset + Ha-1-vcrop2;
+ int Vend = Vstart + He - 1;
DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend));
zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV);
- zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC);
+ vfec |= VerDcm<<8;
}
DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name));
+
/* setup the requested format */
- zraor(palette2fmt[i->format].mode, ~(ZORAN_VFEC_RGB|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24), ZORAN_VFEC);
+ zrwrite(vfec, ZORAN_VFEC);
}
-#if LINUX_VERSION_CODE >= 0x020100
static
-unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait)
+void zoran_common_open(struct zoran* ztv, int flags)
{
- struct zoran *ztv = (struct zoran *)dev;
+ UNUSED(flags);
+
+ /* already opened? */
+ if (ztv->users++ != 0)
+ return;
- poll_wait(file, &ztv->readq, wait);
+ /* unmute audio */
+ /* /what/ audio? */
- return (POLLIN | POLLRDNORM);
+ ztv->state = 0;
+
+ /* setup the encoder to the initial values */
+ ztv->picture.colour=254<<7;
+ ztv->picture.brightness=128<<8;
+ ztv->picture.hue=128<<8;
+ ztv->picture.contrast=216<<7;
+ i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture);
+
+ /* default to the composite input since my camera is there */
+ zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);
+}
+
+static
+void zoran_common_close(struct zoran* ztv)
+{
+ if (--ztv->users != 0)
+ return;
+
+ /* mute audio */
+ /* /what/ audio? */
+
+ /* stop the chip */
+ zoran_cap(ztv, 0);
}
-#endif
/*
* Open a zoran card. Right now the flags are just a hack
static int zoran_open(struct video_device *dev, int flags)
{
struct zoran *ztv = (struct zoran*)dev;
- int i;
-
- DEBUG(printk(KERN_DEBUG "%s: open(dev,%d)\n",CARD,flags));
-
- switch (flags) {
- case 0:
- /* already active? */
- if (ztv->user)
- return -EBUSY;
- ztv->user++;
-
- /* unmute audio */
- /* /what/ audio? */
-
-/******************************************
- We really should be doing lazy allocing...
- ******************************************/
- /* allocate a frame buffer */
- if (!ztv->fbuffer)
- ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE);
- if (!ztv->fbuffer) {
- /* could not get a buffer, bail out */
- ztv->user--;
- return -ENOBUFS;
- }
- /* at this time we _always_ have a framebuffer */
- memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE);
-
- if (!ztv->overinfo.overlay)
- ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL);
- if (!ztv->overinfo.overlay) {
- /* could not get an overlay buffer, bail out */
- ztv->user--;
- bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
- return -ENOBUFS;
- }
- /* at this time we _always_ have a overlay */
+ struct vidinfo* item;
+ char* pos;
+
+ DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags));
+
+ /*********************************************
+ * We really should be doing lazy allocing...
+ *********************************************/
+ /* allocate a frame buffer */
+ if (!ztv->fbuffer)
+ ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE);
+ if (!ztv->fbuffer) {
+ /* could not get a buffer, bail out */
+ return -ENOBUFS;
+ }
+ /* at this time we _always_ have a framebuffer */
+ memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE);
+
+ if (!ztv->overinfo.overlay)
+ ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL);
+ if (!ztv->overinfo.overlay) {
+ /* could not get an overlay buffer, bail out */
+ bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE);
+ return -ENOBUFS;
+ }
+ /* at this time we _always_ have a overlay */
- /* clear buffer status */
- for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
- ztv->grabinfo[i].status = FBUFFER_UNUSED;
- ztv->state = 0;
- ztv->prevstate = 0;
- ztv->lastframe = -1;
+ /* clear buffer status, and give them a DMAable address */
+ pos = ztv->fbuffer;
+ for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
+ {
+ item->status = FBUFFER_FREE;
+ item->memadr = pos;
+ item->busadr = virt_to_bus(pos);
+ pos += ZORAN_MAX_FBUFFER;
+ }
- /* setup the encoder to the initial values */
- i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture);
+ /* do the common part of all open's */
+ zoran_common_open(ztv, flags);
- /* default to the compisite input since my camera is there */
- zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);
- break;
- case 1:
- break;
- }
MOD_INC_USE_COUNT;
return 0;
}
{
struct zoran *ztv = (struct zoran*)dev;
- DEBUG(printk(KERN_DEBUG "%s: close(dev)\n",CARD));
+ DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD));
- /* we are no longer active, goodbye */
- ztv->user--;
+ /* driver specific closure */
+ clear_bit(STATE_OVERLAY, &ztv->state);
- /* mute audio */
- /* stop the chip */
- zoran_cap(ztv, 0);
+ zoran_common_close(ztv);
+
+ /*
+ * This is sucky but right now I can't find a good way to
+ * be sure its safe to free the buffer. We wait 5-6 fields
+ * which is more than sufficient to be sure.
+ */
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/10); /* Wait 1/10th of a second */
/* free the allocated framebuffer */
if (ztv->fbuffer)
MOD_DEC_USE_COUNT;
}
-static
-long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock)
-{
- DEBUG(printk(KERN_DEBUG "zoran_write\n"));
- return -EINVAL;
-}
-
+/*
+ * This read function could be used reentrant in a SMP situation.
+ *
+ * This is made possible by the spinlock which is kept till we
+ * found and marked a buffer for our own use. The lock must
+ * be released as soon as possible to prevent lock contention.
+ */
static
long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
{
struct zoran *ztv = (struct zoran*)dev;
- int max;
+ unsigned long max;
+ struct vidinfo* unused = 0;
+ struct vidinfo* done = 0;
- DEBUG(printk(KERN_DEBUG "zoran_read(%p,%ld,%d)\n",buf,count,nonblock));
+ DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock));
- /* tell the state machine we want in too */
- write_lock_irq(&ztv->lock);
- ztv->readinfo.vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer));
- set_bit(STATE_READ, &ztv->state);
- write_unlock_irq(&ztv->lock);
- zoran_cap(ztv, 1);
+ /* find ourself a free or completed buffer */
+ for (;;) {
+ struct vidinfo* item;
+
+ write_lock_irq(&ztv->lock);
+ for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
+ {
+ if (!unused && item->status == FBUFFER_FREE)
+ unused = item;
+ if (!done && item->status == FBUFFER_DONE)
+ done = item;
+ }
+ if (done || unused)
+ break;
+
+ /* no more free buffers, wait for them. */
+ write_unlock_irq(&ztv->lock);
+ if (nonblock)
+ return -EWOULDBLOCK;
+ interruptible_sleep_on(&ztv->grabq);
+ if (signal_pending(current))
+ return -EINTR;
+ }
- /* wait for data to arrive */
- interruptible_sleep_on(&ztv->readq);
+ /* Do we have 'ready' data? */
+ if (!done) {
+ /* no? than this will take a while... */
+ if (nonblock) {
+ write_unlock_irq(&ztv->lock);
+ return -EWOULDBLOCK;
+ }
+
+ /* mark the unused buffer as wanted */
+ unused->status = FBUFFER_BUSY;
+ unused->w = 320;
+ unused->h = 240;
+ unused->format = VIDEO_PALETTE_RGB24;
+ unused->bpp = palette2fmt[unused->format].bpp;
+ unused->bpl = unused->w * unused->bpp;
+ unused->next = 0;
+ { /* add to tail of queue */
+ struct vidinfo* oldframe = ztv->workqueue;
+ if (!oldframe) ztv->workqueue = unused;
+ else {
+ while (oldframe->next) oldframe = oldframe->next;
+ oldframe->next = unused;
+ }
+ }
+ write_unlock_irq(&ztv->lock);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
+ /* tell the state machine we want it filled /NOW/ */
+ zoran_cap(ztv, 1);
+
+ /* wait till this buffer gets grabbed */
+ while (unused->status == FBUFFER_BUSY) {
+ interruptible_sleep_on(&ztv->grabq);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ done = unused;
+ }
+ else
+ write_unlock_irq(&ztv->lock);
- /* give the user what he requested */
- max = ztv->readinfo.w*ztv->readinfo.bpp - ztv->readinfo.h*ztv->readinfo.bpl;
+ /* Yes! we got data! */
+ max = done->bpl * done->h;
if (count > max)
count = max;
- if (copy_to_user((void*)buf, (void*)ztv->fbuffer, count))
- return -EFAULT;
+ if (copy_to_user((void*)buf, done->memadr, count))
+ count = -EFAULT;
+
+ /* keep the engine running */
+ done->status = FBUFFER_FREE;
+// zoran_cap(ztv,1);
+
+ /* tell listeners this buffer became free */
+ wake_up_interruptible(&ztv->grabq);
/* goodbye */
+ DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count));
return count;
}
+static
+long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock)
+{
+ struct zoran *ztv = (struct zoran *)dev;
+ UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock);
+ DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD));
+ return -EINVAL;
+}
+
+#if LINUX_VERSION_CODE >= 0x020100
+static
+unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait)
+{
+ struct zoran *ztv = (struct zoran *)dev;
+ struct vidinfo* item;
+ unsigned int mask = 0;
+
+ poll_wait(file, &ztv->grabq, wait);
+
+ for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++)
+ if (item->status == FBUFFER_DONE)
+ {
+ mask |= (POLLIN | POLLRDNORM);
+ break;
+ }
+
+ DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask));
+
+ return mask;
+}
+#endif
+
/* append a new clipregion to the vector of video_clips */
static
void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h)
switch (cmd) {
case VIDIOCGCAP:
- { /* get video capabilities */
+ {
struct video_capability c;
- struct video_decoder_capability dc;
- int rv;
- DEBUG(printk(KERN_DEBUG "%s: GetCapabilities\n",CARD));
-
- /* fetch the capabilites of the decoder */
- dc.flags = 0;
- dc.inputs = -1;
- dc.outputs = -1;
- rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc);
- if (rv)
- return rv;
- DEBUG(printk(KERN_DEBUG "%s: capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs));
+ DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD));
strcpy(c.name,ztv->video_dev.name);
c.type = VID_TYPE_CAPTURE|
VID_TYPE_CLIPPING|
VID_TYPE_FRAMERAM|
VID_TYPE_SCALES;
- c.channels = ztv->card->video_inputs;
- c.audios = ztv->card->audio_inputs;
+ if (ztv->have_tuner)
+ c.type |= VID_TYPE_TUNER;
+ if (ztv->have_decoder) {
+ c.channels = ztv->card->video_inputs;
+ c.audios = ztv->card->audio_inputs;
+ } else
+ /* no decoder -> no channels */
+ c.channels = c.audios = 0;
c.maxwidth = 768;
c.maxheight = 576;
c.minwidth = 32;
c.minheight = 32;
if (copy_to_user(arg,&c,sizeof(c)))
return -EFAULT;
- return 0;
+ break;
}
case VIDIOCGCHAN:
{
struct video_channel v;
int mux;
-
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- DEBUG(printk(KERN_DEBUG "%s: GetChannel(%d)\n",CARD,v.channel));
+ DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel));
v.flags=VIDEO_VC_AUDIO
#ifdef VIDEO_VC_NORM
|VIDEO_VC_NORM
#else
v.norm=VIDEO_MODE_PAL;
#endif
- /* too many inputs? */
- if (v.channel >= ztv->card->video_inputs)
+ /* too many inputs? no decoder -> no channels */
+ if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
return -EINVAL;
/* now determine the name of the channel */
if (copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
- return 0;
+ break;
}
case VIDIOCSCHAN:
{ /* set video channel */
struct video_channel v;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- DEBUG(printk(KERN_DEBUG "%s: SetChannel(%d,%d)\n",CARD,v.channel,v.norm));
- if (v.channel >= ztv->card->video_inputs)
+ DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm));
+
+ /* too many inputs? no decoder -> no channels */
+ if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
return -EINVAL;
if (v.norm != VIDEO_MODE_PAL &&
struct video_tuner v;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner));
- /* Only one tuner for now */
- if (!ztv->have_tuner && v.tuner)
+ /* Only no or one tuner for now */
+ if (!ztv->have_tuner || v.tuner)
return -EINVAL;
strcpy(v.name,"Television");
if (copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
- return 0;
+ break;
}
-
case VIDIOCSTUNER:
{
struct video_tuner v;
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode));
- /* Only one tuner for now */
- if (!ztv->have_tuner && v.tuner)
+ /* Only no or one tuner for now */
+ if (!ztv->have_tuner || v.tuner)
return -EINVAL;
/* and it only has certain valid modes */
case VIDIOCGPICT:
{
struct video_picture p = ztv->picture;
- DEBUG(printk(KERN_DEBUG "%s: GetPicture\n",CARD));
+ DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD));
p.depth = ztv->depth;
switch (p.depth) {
case 8: p.palette=VIDEO_PALETTE_YUV422;
}
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
- return 0;
+ break;
}
case VIDIOCSPICT:
{
struct video_picture p;
- DEBUG(printk(KERN_DEBUG "%s: SetPicture\n",CARD));
if (copy_from_user(&p, arg,sizeof(p)))
return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette));
/* depth must match with framebuffer */
if (p.depth != ztv->depth)
return -EINVAL;
/* check if palette matches this bpp */
- if (p.palette<1 || p.palette>NRPALETTES ||
+ if (p.palette>NRPALETTES ||
palette2fmt[p.palette].bpp != ztv->overinfo.bpp)
return -EINVAL;
/* tell the decoder */
i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
- return 0;
+ break;
}
case VIDIOCGWIN:
{
struct video_window vw;
- DEBUG(printk(KERN_DEBUG "%s: GetWindow\n",CARD));
+ DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD));
read_lock(&ztv->lock);
vw.x = ztv->overinfo.x;
vw.y = ztv->overinfo.y;
vw.height = ztv->overinfo.h;
vw.chromakey= 0;
vw.flags = 0;
- if (ztv->interlace)
+ if (ztv->vidInterlace)
vw.flags|=VIDEO_WINDOW_INTERLACE;
read_unlock(&ztv->lock);
if (copy_to_user(arg,&vw,sizeof(vw)))
return -EFAULT;
- return 0;
+ break;
}
case VIDIOCSWIN:
{
struct video_window vw;
struct video_clip *vcp;
int on;
-
if (copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
-
- DEBUG(printk(KERN_DEBUG "%s: SetWindow(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
+ DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
if (vw.flags)
return -EINVAL;
if (on)
zoran_cap(ztv, 0);
+ /*
+ * strange, it seems xawtv sometimes calls us with 0
+ * width and/or height. Ignore these values
+ */
+ if (vw.x == 0)
+ vw.x = ztv->overinfo.x;
+ if (vw.y == 0)
+ vw.y = ztv->overinfo.y;
+
/* by now we are committed to the new data... */
write_lock_irq(&ztv->lock);
ztv->overinfo.x = vw.x;
/*
* Impose display clips
*/
- if (vw.x<0)
- new_clip(&vw, vcp, 0, 0, -vw.x, vw.height-1);
- if (vw.y<0)
- new_clip(&vw, vcp, 0, 0, vw.width-1,-vw.y);
if (vw.x+vw.width > ztv->swidth)
new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1);
if (vw.y+vw.height > ztv->sheight)
vfree(vcp);
/* if we were on, restart the video engine */
- if (on) zoran_cap(ztv, on);
- return 0;
+ if (on)
+ zoran_cap(ztv, 1);
+ break;
}
+
case VIDIOCCAPTURE:
{
int v;
get_user_ret(v,(int*)arg, -EFAULT);
- DEBUG(printk(KERN_DEBUG "%s: Capture(%d)\n",CARD,v));
+ DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v));
if (v==0) {
- zoran_cap(ztv, 0);
clear_bit(STATE_OVERLAY, &ztv->state);
+ zoran_cap(ztv, 1);
}
else {
/* is VIDIOCSFBUF, VIDIOCSWIN done? */
- if (ztv->overinfo.vidadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
+ if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
return -EINVAL;
set_bit(STATE_OVERLAY, &ztv->state);
zoran_cap(ztv, 1);
}
- return 0;
+ break;
}
case VIDIOCGFBUF:
{
struct video_buffer v;
- DEBUG(printk(KERN_DEBUG "%s: GetFramebuffer\n",CARD));
+ DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD));
read_lock(&ztv->lock);
- v.base = (void *)ztv->overinfo.vidadr;
+ v.base = (void *)ztv->overinfo.busadr;
v.height = ztv->sheight;
v.width = ztv->swidth;
v.depth = ztv->depth;
read_unlock(&ztv->lock);
if(copy_to_user(arg, &v,sizeof(v)))
return -EFAULT;
- return 0;
+ break;
}
case VIDIOCSFBUF:
{
struct video_buffer v;
#if LINUX_VERSION_CODE >= 0x020100
- if(!capable(CAP_SYS_ADMIN))
+ if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN))
#else
if(!suser())
#endif
return -EPERM;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline));
+
if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
return -EINVAL;
if (v.bytesperline<1)
if (ztv->running)
return -EBUSY;
write_lock_irq(&ztv->lock);
- ztv->overinfo.vidadr = (unsigned long)v.base;
+ ztv->overinfo.busadr = (ulong)v.base;
ztv->sheight = v.height;
ztv->swidth = v.width;
- ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
ztv->depth = v.depth; /* bits per pixel */
- ztv->overinfo.bpl = v.bytesperline;
+ ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
+ ztv->overinfo.bpl = v.bytesperline; /* bytes per line */
write_unlock_irq(&ztv->lock);
+ break;
+ }
- DEBUG(printk(KERN_DEBUG "%s: SetFrameBuffer(%p,%dx%d, bpp %d, bpl %d)\n",CARD,v.base, v.width,v.height, ztv->overinfo.bpp, ztv->overinfo.bpl));
- return 0;
+ case VIDIOCKEY:
+ {
+ /* Will be handled higher up .. */
+ break;
}
case VIDIOCSYNC:
{
int i;
get_user_ret(i,(int*)arg, -EFAULT);
- DEBUG(printk(KERN_DEBUG "%s: VIDEOCSYNC(%d)\n",CARD,i));
+ DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i));
if (i<0 || i>ZORAN_MAX_FBUFFERS)
return -EINVAL;
switch (ztv->grabinfo[i].status) {
- case FBUFFER_UNUSED:
+ case FBUFFER_FREE:
return -EINVAL;
- case FBUFFER_GRABBING:
+ case FBUFFER_BUSY:
/* wait till this buffer gets grabbed */
- while (ztv->grabinfo[i].status == FBUFFER_GRABBING) {
+ while (ztv->grabinfo[i].status == FBUFFER_BUSY) {
interruptible_sleep_on(&ztv->grabq);
/* see if a signal did it */
if (signal_pending(current))
- return -ERESTARTSYS;
+ return -EINTR;
}
- /* fall through */
+ /* don't fall through; a DONE buffer is not UNUSED */
+ break;
case FBUFFER_DONE:
- ztv->grabinfo[i].status = FBUFFER_UNUSED;
+ ztv->grabinfo[i].status = FBUFFER_FREE;
+ /* tell ppl we have a spare buffer */
+ wake_up_interruptible(&ztv->grabq);
break;
}
- return 0;
- }
-
- case VIDIOCKEY:
- {
- /* Will be handled higher up .. */
- return 0;
+ DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i));
+ break;
}
case VIDIOCMCAPTURE:
struct vidinfo* frame;
if (copy_from_user(&vm,arg,sizeof(vm)))
return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format));
if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS ||
vm.width<32 || vm.width>768 ||
vm.height<32 || vm.height>576 ||
- vm.format<0 || vm.format>NRPALETTES ||
+ vm.format>NRPALETTES ||
palette2fmt[vm.format].mode == 0)
return -EINVAL;
- DEBUG(printk(KERN_DEBUG "%s: Mcapture(%d,(%d,%d),%d=%s)\n",CARD,vm.frame,vm.width,vm.height,vm.format,palette2fmt[vm.format].name));
+ /* we are allowed to take over UNUSED and DONE buffers */
frame = &ztv->grabinfo[vm.frame];
- if (frame->status == FBUFFER_GRABBING)
+ if (frame->status == FBUFFER_BUSY)
return -EBUSY;
/* setup the other parameters if they are given */
write_lock_irq(&ztv->lock);
- if (vm.width)
- frame->w = vm.width;
- if (vm.height)
- frame->h = vm.height;
- if (vm.format)
- frame->format = vm.format;
+ frame->w = vm.width;
+ frame->h = vm.height;
+ frame->format = vm.format;
frame->bpp = palette2fmt[frame->format].bpp;
frame->bpl = frame->w*frame->bpp;
- frame->vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer+vm.frame*ZORAN_MAX_FBUFFER));
- frame->status = FBUFFER_GRABBING;
- set_bit(STATE_GRAB, &ztv->state);
+ frame->status = FBUFFER_BUSY;
+ frame->next = 0;
+ { /* add to tail of queue */
+ struct vidinfo* oldframe = ztv->workqueue;
+ if (!oldframe) ztv->workqueue = frame;
+ else {
+ while (oldframe->next) oldframe = oldframe->next;
+ oldframe->next = frame;
+ }
+ }
write_unlock_irq(&ztv->lock);
-
zoran_cap(ztv, 1);
- return 0;
+ break;
}
case VIDIOCGMBUF:
{
struct video_mbuf mb;
int i;
- DEBUG(printk(KERN_DEBUG "%s: GetMemoryBuffer\n",CARD));
+ DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD));
mb.size = ZORAN_MAX_FBUFSIZE;
mb.frames = ZORAN_MAX_FBUFFERS;
for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
mb.offsets[i] = i*ZORAN_MAX_FBUFFER;
if(copy_to_user(arg, &mb,sizeof(mb)))
return -EFAULT;
- return 0;
+ break;
}
case VIDIOCGUNIT:
{
struct video_unit vu;
- DEBUG(printk(KERN_DEBUG "%s: GetUnit\n",CARD));
+ DEBUG(printk(CARD_DEBUG "VIDIOCGUNIT\n",CARD));
vu.video = ztv->video_dev.minor;
- vu.vbi = VIDEO_NO_UNIT;
+ vu.vbi = ztv->vbi_dev.minor;
vu.radio = VIDEO_NO_UNIT;
vu.audio = VIDEO_NO_UNIT;
vu.teletext = VIDEO_NO_UNIT;
if(copy_to_user(arg, &vu,sizeof(vu)))
return -EFAULT;
- return 0;
+ break;
}
case VIDIOCGFREQ:
unsigned long v = ztv->tuner_freq;
if (copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
- return 0;
+ DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD));
+ break;
}
-
case VIDIOCSFREQ:
{
unsigned long v;
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD));
if (ztv->have_tuner) {
int fixme = v;
return -EAGAIN;
}
ztv->tuner_freq = v;
- return 0;
+ break;
}
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- case VIDIOCGCAPTURE:
- case VIDIOCSCAPTURE:
- DEBUG(printk(KERN_DEBUG "%s: unhandled video ioctl(%x)\n",CARD,cmd));
- return -EINVAL;
+ /* Why isn't this in the API?
+ * And why doesn't it take a buffer number?
+ case BTTV_FIELDNR:
+ {
+ unsigned long v = ztv->lastfieldnr;
+ if (copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD));
+ break;
+ }
+ */
default:
- DEBUG(printk(KERN_DEBUG "%s: bad ioctl(%x)\n",CARD,cmd));
+ return -ENOIOCTLCMD;
}
- return -EPERM;
+ return 0;
}
static
unsigned long start = (unsigned long)adr;
unsigned long pos;
- DEBUG(printk(KERN_DEBUG "zoran_mmap(0x%p,%ld)\n",adr,size));
+ DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size));
/* sanity checks */
if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer)
/* start mapping the whole shabang to user memory */
pos = (unsigned long)ztv->fbuffer;
while (size>0) {
-#ifdef CONFIG_BIGPHYS_AREA
unsigned long page = virt_to_phys((void*)pos);
-#else
- unsigned long page = kvirt_to_phys(pos);
-#endif
if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
start += PAGE_SIZE;
return 0;
}
-static struct video_device zoran_template=
+static struct video_device zr36120_template=
{
"UNSET",
VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
};
static
-int init_zoran(int card)
+int vbi_open(struct video_device *dev, int flags)
+{
+ struct zoran *ztv = (struct zoran*)dev->priv;
+ struct vidinfo* item;
+
+ DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags));
+
+ /*
+ * During VBI device open, we continiously grab VBI-like
+ * data in the vbi buffer when we have nothing to do.
+ * Only when there is an explicit request for VBI data
+ * (read call) we /force/ a read.
+ */
+
+ /* allocate buffers */
+ for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+ {
+ item->status = FBUFFER_FREE;
+
+ /* alloc */
+ if (!item->memadr) {
+ item->memadr = bmalloc(ZORAN_VBI_BUFSIZE);
+ if (!item->memadr) {
+ /* could not get a buffer, bail out */
+ while (item != ztv->readinfo) {
+ item--;
+ bfree(item->memadr, ZORAN_VBI_BUFSIZE);
+ item->memadr = 0;
+ item->busadr = 0;
+ }
+ return -ENOBUFS;
+ }
+ }
+
+ /* determine the DMAable address */
+ item->busadr = virt_to_bus(item->memadr);
+ }
+
+ /* do the common part of all open's */
+ zoran_common_open(ztv, flags);
+
+ set_bit(STATE_VBI, &ztv->state);
+ /* start read-ahead */
+ zoran_cap(ztv, 1);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static
+void vbi_close(struct video_device *dev)
+{
+ struct zoran *ztv = (struct zoran*)dev->priv;
+ struct vidinfo* item;
+
+ DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD));
+
+ /* driver specific closure */
+ clear_bit(STATE_VBI, &ztv->state);
+
+ zoran_common_close(ztv);
+
+ /*
+ * This is sucky but right now I can't find a good way to
+ * be sure its safe to free the buffer. We wait 5-6 fields
+ * which is more than sufficient to be sure.
+ */
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/10); /* Wait 1/10th of a second */
+
+ for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+ {
+ if (item->memadr)
+ bfree(item->memadr, ZORAN_VBI_BUFSIZE);
+ item->memadr = 0;
+ }
+
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * This read function could be used reentrant in a SMP situation.
+ *
+ * This is made possible by the spinlock which is kept till we
+ * found and marked a buffer for our own use. The lock must
+ * be released as soon as possible to prevent lock contention.
+ */
+static
+long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock)
+{
+ struct zoran *ztv = (struct zoran*)dev->priv;
+ unsigned long max;
+ struct vidinfo* unused = 0;
+ struct vidinfo* done = 0;
+
+ DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock));
+
+ /* find ourself a free or completed buffer */
+ for (;;) {
+ struct vidinfo* item;
+
+ write_lock_irq(&ztv->lock);
+ for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) {
+ if (!unused && item->status == FBUFFER_FREE)
+ unused = item;
+ if (!done && item->status == FBUFFER_DONE)
+ done = item;
+ }
+ if (done || unused)
+ break;
+
+ /* no more free buffers, wait for them. */
+ write_unlock_irq(&ztv->lock);
+ if (nonblock)
+ return -EWOULDBLOCK;
+ interruptible_sleep_on(&ztv->vbiq);
+ if (signal_pending(current))
+ return -EINTR;
+ }
+
+ /* Do we have 'ready' data? */
+ if (!done) {
+ /* no? than this will take a while... */
+ if (nonblock) {
+ write_unlock_irq(&ztv->lock);
+ return -EWOULDBLOCK;
+ }
+
+ /* mark the unused buffer as wanted */
+ unused->status = FBUFFER_BUSY;
+ unused->next = 0;
+ { /* add to tail of queue */
+ struct vidinfo* oldframe = ztv->workqueue;
+ if (!oldframe) ztv->workqueue = unused;
+ else {
+ while (oldframe->next) oldframe = oldframe->next;
+ oldframe->next = unused;
+ }
+ }
+ write_unlock_irq(&ztv->lock);
+
+ /* tell the state machine we want it filled /NOW/ */
+ zoran_cap(ztv, 1);
+
+ /* wait till this buffer gets grabbed */
+ while (unused->status == FBUFFER_BUSY) {
+ interruptible_sleep_on(&ztv->vbiq);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ done = unused;
+ }
+ else
+ write_unlock_irq(&ztv->lock);
+
+ /* Yes! we got data! */
+ max = done->bpl * -done->h;
+ if (count > max)
+ count = max;
+
+ /* check if the user gave us enough room to write the data */
+ if (!access_ok(VERIFY_WRITE, buf, count)) {
+ count = -EFAULT;
+ goto out;
+ }
+
+ /*
+ * Now transform/strip the data from YUV to Y-only
+ * NB. Assume the Y is in the LSB of the YUV data.
+ */
+ {
+ unsigned char* optr = buf;
+ unsigned char* eptr = buf+count;
+
+ /* are we beeing accessed from an old driver? */
+ if (count == 2*19*2048) {
+ /*
+ * Extreme HACK, old VBI programs expect 2048 points
+ * of data, and we only got 864 orso. Double each
+ * datapoint and clear the rest of the line.
+ * This way we have appear to have a
+ * sample_frequency of 29.5 Mc.
+ */
+ int x,y;
+ unsigned char* iptr = done->memadr+1;
+ for (y=done->h; optr<eptr && y<0; y++)
+ {
+ /* copy to doubled data to userland */
+ for (x=0; optr+1<eptr && x<-done->w; x++)
+ {
+ unsigned char a = iptr[x*2];
+ *optr++ = a;
+ *optr++ = a;
+ }
+ /* and clear the rest of the line */
+ for (x*=2; optr<eptr && x<done->bpl; x++)
+ *optr++ = 0;
+ /* next line */
+ iptr += done->bpl;
+ }
+ }
+ else {
+ /*
+ * Other (probably newer) programs asked
+ * us what geometry we are using, and are
+ * reading the correct size.
+ */
+ int x,y;
+ unsigned char* iptr = done->memadr+1;
+ for (y=done->h; optr<eptr && y<0; y++)
+ {
+ /* copy to doubled data to userland */
+ for (x=0; optr<eptr && x<-done->w; x++)
+ *optr++ = iptr[x*2];
+ /* and clear the rest of the line */
+ for (;optr<eptr && x<done->bpl; x++)
+ *optr++ = 0;
+ /* next line */
+ iptr += done->bpl;
+ }
+ }
+
+ /* API compliance:
+ * place the framenumber (half fieldnr) in the last long
+ */
+ ((ulong*)eptr)[-1] = done->fieldnr/2;
+ }
+
+ /* keep the engine running */
+ done->status = FBUFFER_FREE;
+ zoran_cap(ztv, 1);
+
+ /* tell listeners this buffer just became free */
+ wake_up_interruptible(&ztv->vbiq);
+
+ /* goodbye */
+out:
+ DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count));
+ return count;
+}
+
+#if LINUX_VERSION_CODE >= 0x020100
+static
+unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait)
+{
+ struct zoran *ztv = (struct zoran*)dev->priv;
+ struct vidinfo* item;
+ unsigned int mask = 0;
+
+ poll_wait(file, &ztv->vbiq, wait);
+
+ for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++)
+ if (item->status == FBUFFER_DONE)
+ {
+ mask |= (POLLIN | POLLRDNORM);
+ break;
+ }
+
+ DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask));
+
+ return mask;
+}
+#endif
+
+static
+int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct zoran* ztv = (struct zoran*)dev->priv;
+
+ switch (cmd) {
+ case VIDIOCGVBIFMT:
+ {
+ struct vbi_format f;
+ DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD));
+ f.sampling_rate = 14750000UL;
+ f.samples_per_line = -ztv->readinfo[0].w;
+ f.sample_format = VIDEO_PALETTE_RAW;
+ f.start[0] = f.start[1] = ztv->readinfo[0].y;
+ f.start[1] += 312;
+ f.count[0] = f.count[1] = -ztv->readinfo[0].h;
+ f.flags = VBI_INTERLACED;
+ if (copy_to_user(arg,&f,sizeof(f)))
+ return -EFAULT;
+ break;
+ }
+ case VIDIOCSVBIFMT:
+ {
+ struct vbi_format f;
+ int i;
+ if (copy_from_user(&f, arg,sizeof(f)))
+ return -EFAULT;
+ DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags));
+
+ /* lots of parameters are fixed... (PAL) */
+ if (f.sampling_rate != 14750000UL ||
+ f.samples_per_line > 864 ||
+ f.sample_format != VIDEO_PALETTE_RAW ||
+ f.start[0] < 0 ||
+ f.start[0] != f.start[1]-312 ||
+ f.count[0] != f.count[1] ||
+ f.start[0]+f.count[0] >= 288 ||
+ f.flags != VBI_INTERLACED)
+ return -EINVAL;
+
+ write_lock_irq(&ztv->lock);
+ ztv->readinfo[0].y = f.start[0];
+ ztv->readinfo[0].w = -f.samples_per_line;
+ ztv->readinfo[0].h = -f.count[0];
+ ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp;
+ for (i=1; i<ZORAN_VBI_BUFFERS; i++)
+ ztv->readinfo[i] = ztv->readinfo[i];
+ write_unlock_irq(&ztv->lock);
+ break;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static struct video_device vbi_template=
+{
+ "UNSET",
+ VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+ VID_HARDWARE_ZR36120,
+
+ vbi_open,
+ vbi_close,
+ vbi_read,
+ zoran_write,
+#if LINUX_VERSION_CODE >= 0x020100
+ vbi_poll, /* poll */
+#endif
+ vbi_ioctl,
+ NULL, /* no mmap */
+ NULL, /* no initialize */
+ NULL, /* priv */
+ 0, /* busy */
+ -1 /* minor */
+};
+
+/*
+ * Scan for a Zoran chip, request the irq and map the io memory
+ */
+static
+int __init find_zoran(void)
+{
+ int result;
+ struct zoran *ztv;
+ struct pci_dev *dev = NULL;
+ unsigned char revision;
+ int zoran_num=0;
+
+ if (!pcibios_present())
+ {
+ printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n");
+ return 0;
+ }
+
+ while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
+ {
+ /* Ok, a ZR36120/ZR36125 found! */
+ ztv = &zorans[zoran_num];
+ ztv->dev = dev;
+
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
+ printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
+ dev->device, revision);
+ printk("bus: %d, devfn: %d, irq: %d, ",
+ dev->bus->number, dev->devfn, dev->irq);
+ printk("memory: 0x%08lx.\n", ztv->zoran_adr);
+
+ ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000);
+ DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
+
+ result = request_irq(dev->irq, zoran_irq,
+ SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv);
+ if (result==-EINVAL)
+ {
+ printk(KERN_ERR "zoran: Bad irq number or handler\n");
+ return -EINVAL;
+ }
+ if (result==-EBUSY)
+ printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq);
+ if (result < 0)
+ return result;
+
+ /* Enable bus-mastering */
+ pci_set_master(dev);
+
+ zoran_num++;
+ }
+ if(zoran_num)
+ printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num);
+ return zoran_num;
+}
+
+static
+int __init init_zoran(int card)
{
struct zoran *ztv = &zorans[card];
int i;
/* if the given cardtype valid? */
- if (cardtype[card]<0 || cardtype[card]>=NRTVCARDS) {
+ if (cardtype[card]>=NRTVCARDS) {
printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]);
return -1;
}
zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
udelay(10);
- /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
-
- /* framegrabber details */
- ztv->swidth=800;
- ztv->sheight=600;
- ztv->depth=16;
-
- /* channel details */
- ztv->norm=0; /* PAL */
- ztv->card=tvcards+cardtype[card]; /* point to the selected card */
+ /* zoran chip specific details */
+ ztv->card = tvcards+cardtype[card]; /* point to the selected card */
+ ztv->norm = 0; /* PAL */
ztv->tuner_freq = 0;
- ztv->overinfo.status = FBUFFER_UNUSED;
+ /* videocard details */
+ ztv->swidth = 800;
+ ztv->sheight = 600;
+ ztv->depth = 16;
+
+ /* State details */
+ ztv->fbuffer = 0;
+ ztv->overinfo.kindof = FBUFFER_OVERLAY;
+ ztv->overinfo.status = FBUFFER_FREE;
ztv->overinfo.x = 0;
ztv->overinfo.y = 0;
ztv->overinfo.w = 768; /* 640 */
ztv->overinfo.format = VIDEO_PALETTE_RGB565;
ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp;
ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth;
- ztv->overinfo.vidadr = 0;
+ ztv->overinfo.busadr = 0;
+ ztv->overinfo.memadr = 0;
ztv->overinfo.overlay = 0;
-
- ztv->readinfo = ztv->overinfo;
- ztv->readinfo.w = 768;
- ztv->readinfo.h = -22;
- ztv->readinfo.format = VIDEO_PALETTE_YUV422;
- ztv->readinfo.bpp = palette2fmt[ztv->readinfo.format].bpp;
- ztv->readinfo.bpl = ztv->readinfo.w*ztv->readinfo.bpp;
-
- /* grabbing details */
for (i=0; i<ZORAN_MAX_FBUFFERS; i++) {
ztv->grabinfo[i] = ztv->overinfo;
- ztv->grabinfo[i].format = VIDEO_PALETTE_RGB24;
+ ztv->grabinfo[i].kindof = FBUFFER_GRAB;
}
+ init_waitqueue_head(&ztv->grabq);
+
+ /* VBI details */
+ ztv->readinfo[0] = ztv->overinfo;
+ ztv->readinfo[0].kindof = FBUFFER_VBI;
+ ztv->readinfo[0].w = -864;
+ ztv->readinfo[0].h = -38;
+ ztv->readinfo[0].format = VIDEO_PALETTE_YUV422;
+ ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp;
+ ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp;
+ for (i=1; i<ZORAN_VBI_BUFFERS; i++)
+ ztv->readinfo[i] = ztv->readinfo[0];
+ init_waitqueue_head(&ztv->vbiq);
/* maintenance data */
- ztv->fbuffer = NULL;
- ztv->user = 0;
ztv->have_decoder = 0;
ztv->have_tuner = 0;
+ ztv->tuner_type = 0;
ztv->running = 0;
- init_waitqueue_head(&ztv->grabq);
- init_waitqueue_head(&ztv->readq);
+ ztv->users = 0;
ztv->lock = RW_LOCK_UNLOCKED;
- ztv->state = 0;
- ztv->prevstate = 0;
- ztv->lastframe = -1;
-
- /* picture details */
- ztv->picture.colour=254<<7;
- ztv->picture.brightness=128<<8;
- ztv->picture.hue=128<<8;
- ztv->picture.contrast=216<<7;
+ ztv->workqueue = 0;
+ ztv->fieldnr = 0;
+ ztv->lastfieldnr = 0;
if (triton1)
zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC);
zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI);
/* implicit: 3 duration and recovery PCI clocks on guest 0-3 */
zrwrite(ztv->card->gpval<<24,ZORAN_GUEST);
-
+
/* clear interrupt status */
zrwrite(~0, ZORAN_ISR);
/*
* Now add the template and register the device unit
*/
- ztv->video_dev = zoran_template;
+ ztv->video_dev = zr36120_template;
strcpy(ztv->video_dev.name, ztv->i2c.name);
+ ztv->video_dev.priv = ztv;
if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0)
return -1;
+
+ ztv->vbi_dev = vbi_template;
+ strcpy(ztv->vbi_dev.name, ztv->i2c.name);
+ ztv->vbi_dev.priv = ztv;
+ if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) {
+ video_unregister_device(&ztv->video_dev);
+ return -1;
+ }
i2c_register_bus(&ztv->i2c);
/* set interrupt mask - the PIN enable will be set later */
zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR);
- printk(KERN_INFO "%s: installed %s\n",CARD,ztv->card->name);
+ printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name);
return 0;
}
static
-void release_zoran(int max)
+void __exit release_zoran(int max)
{
- u8 command;
struct zoran *ztv;
int i;
for (i=0;i<max; i++)
{
- ztv=&zorans[i];
+ ztv = &zorans[i];
/* turn off all capturing, DMA and IRQs */
/* reset the zoran */
/* unregister i2c_bus */
i2c_unregister_bus((&ztv->i2c));
- /* disable PCI bus-mastering */
- pci_read_config_byte(ztv->dev, PCI_COMMAND, &command);
- command&=PCI_COMMAND_MASTER;
- pci_write_config_byte(ztv->dev, PCI_COMMAND, command);
-
/* unmap and free memory */
if (ztv->zoran_mem)
iounmap(ztv->zoran_mem);
video_unregister_device(&ztv->video_dev);
+ video_unregister_device(&ztv->vbi_dev);
}
}
-#ifdef MODULE
-void cleanup_module(void)
+void __exit zr36120_exit(void)
{
release_zoran(zoran_cards);
}
-int init_module(void)
+int __init zr36120_init(void)
{
-#else
-int init_zr36120_cards(struct video_init *unused)
-{
-#endif
int card;
handle_chipset();
}
return 0;
}
+
+module_init(zr36120_init);
+module_exit(zr36120_exit);
extern struct i2c_bus zoran_i2c_bus_template;
#define ZORAN_MAX_FBUFFERS 2
-#define ZORAN_MAX_FBUFFER 0x0A2000
-#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER)
+#define ZORAN_MAX_FBUFFER (768*576*2)
+#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER)
-/* external declarations */
-extern unsigned long zoran_alloc_memory(void);
-extern void zoran_free_memory(void);
+#define ZORAN_VBI_BUFFERS 2
+#define ZORAN_VBI_BUFSIZE (22*1024*2)
struct tvcard {
char* name; /* name of the cardtype */
#define SVHS(x) ((x)|IS_SVHS)
struct vidinfo {
- int status;
-#define FBUFFER_UNUSED 0
-#define FBUFFER_GRABBING 1
-#define FBUFFER_DONE 2
- int x,y;
- int w,h;
- int bpl;
- int bpp; /* should be calculated */
- int format;
- ulong vidadr; /* physical video address */
- ulong* overlay;
+ struct vidinfo* next; /* next active buffer */
+ uint kindof;
+#define FBUFFER_OVERLAY 0
+#define FBUFFER_GRAB 1
+#define FBUFFER_VBI 2
+ uint status;
+#define FBUFFER_FREE 0
+#define FBUFFER_BUSY 1
+#define FBUFFER_DONE 2
+ ulong fieldnr; /* # of field, not framer! */
+ uint x,y;
+ int w,h; /* w,h can be negative! */
+ uint format; /* index in palette2fmt[] */
+ uint bpp; /* lookup from palette2fmt[] */
+ uint bpl; /* calc: width * bpp */
+ ulong busadr; /* bus addr for DMA engine */
+ char* memadr; /* kernel addr for making copies */
+ ulong* overlay; /* kernel addr of overlay mask */
};
struct zoran
{
struct video_device video_dev;
-#define CARD ztv->video_dev.name
- struct i2c_bus i2c;
- struct video_picture picture; /* Current picture params */
- struct video_audio audio_dev; /* Current audio params */
+#define CARD_DEBUG KERN_DEBUG "%s(%lu): "
+#define CARD_INFO KERN_INFO "%s(%lu): "
+#define CARD_ERR KERN_ERR "%s(%lu): "
+#define CARD ztv->video_dev.name,ztv->fieldnr
/* zoran chip specific details */
- struct pci_dev* dev; /* ptr to PCI device */
- ushort id; /* chip id */
- unsigned char revision; /* chip revision */
- int zoran_adr; /* bus address of IO memory */
- char* zoran_mem; /* pointer to mapped IO memory */
+ struct i2c_bus i2c; /* i2c registration data */
+ struct pci_dev* dev; /* ptr to PCI device */
+ ulong zoran_adr; /* bus address of IO memory */
+ char* zoran_mem; /* kernel address of IO memory */
+ struct tvcard* card; /* the cardtype */
+ uint norm; /* 0=PAL, 1=NTSC, 2=SECAM */
+ uint tuner_freq; /* Current freq in kHz */
+ struct video_picture picture; /* Current picture params */
/* videocard details */
- int swidth; /* screen width */
- int sheight; /* screen height */
- int depth; /* depth in bits */
-
- /* channel details */
- int norm; /* 0=PAL, 1=NTSC, 2=SECAM */
- struct tvcard* card; /* the cardtype */
- int tuner_freq; /* in Hz */
+ uint swidth; /* screen width */
+ uint sheight; /* screen height */
+ uint depth; /* depth in bits */
/* State details */
- struct vidinfo overinfo; /* overlay data */
- struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data */
- struct vidinfo readinfo; /* reading data */
+ char* fbuffer; /* framebuffers for mmap */
+ struct vidinfo overinfo; /* overlay data */
+ struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data*/
+ wait_queue_head_t grabq; /* grabbers queue */
+
+ /* VBI details */
+ struct video_device vbi_dev;
+ struct vidinfo readinfo[2]; /* VBI data - flip buffers */
+ wait_queue_head_t vbiq; /* vbi queue */
/* maintenance data */
- char* fbuffer; /* framebuffers for mmap */
- int user; /* # users */
- int have_decoder; /* did we detect a mux? */
- int have_tuner; /* did we detect a tuner? */
- int tuner_type; /* tuner type, when found */
- int running;
- wait_queue_head_t grabq; /* waiting capturers */
- wait_queue_head_t readq; /* waiting readers */
+ int have_decoder; /* did we detect a mux? */
+ int have_tuner; /* did we detect a tuner? */
+ int users; /* howmany video/vbi open? */
+ int tuner_type; /* tuner type, when found */
+ int running; /* are we rolling? */
rwlock_t lock;
- int state; /* what is requested of us? */
-#define STATE_READ 0
-#define STATE_GRAB 1
-#define STATE_OVERLAY 2
- int prevstate;
- int lastframe;
-
- int interlace; /* calculated */
+ int state; /* what is requested of us? */
+#define STATE_OVERLAY 0
+#define STATE_VBI 1
+ struct vidinfo* workqueue; /* buffers to grab, head is active */
+ ulong fieldnr; /* #field, ticked every VSYNC */
+ ulong lastfieldnr; /* #field, ticked every GRAB */
+
+ int vidInterlace; /* calculated */
int vidXshift; /* calculated */
- int vidWidth; /* calculated */
- int vidHeight; /* calculated */
+ uint vidWidth; /* calculated */
+ uint vidHeight; /* calculated */
};
#define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr)))
#define zrread(adr) readl(ztv->zoran_mem+(adr))
-#if !defined(PDEBUG) || (PDEBUG == 0)
+#if PDEBUG == 0
#define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr)
#define zror(dat,adr) zrwrite((dat) | zrread(adr), adr)
#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr)
#include <asm/io.h>
#include <linux/version.h>
+#include <linux/video_decoder.h>
#include <asm/uaccess.h>
-#include "linux/video_decoder.h"
#include "tuner.h"
#include "zr36120.h"
void attach_inform(struct i2c_bus *bus, int id)
{
struct zoran *ztv = (struct zoran*)bus->data;
+ struct video_decoder_capability dc;
+ int rv;
switch (id) {
case I2C_DRIVERID_VIDEODECODER:
- ztv->have_decoder = 1;
- DEBUG(printk(KERN_INFO "%s: decoder attached\n",CARD));
+ DEBUG(printk(CARD_INFO "decoder attached\n",CARD));
+
+ /* fetch the capabilites of the decoder */
+ rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc);
+ if (rv) {
+ DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD));
+ break;
+ }
+ DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs));
+
+ /* Test if the decoder can de VBI transfers */
+ if (dc.flags & 16 /*VIDEO_DECODER_VBI*/)
+ ztv->have_decoder = 2;
+ else
+ ztv->have_decoder = 1;
break;
case I2C_DRIVERID_TUNER:
ztv->have_tuner = 1;
- DEBUG(printk(KERN_INFO "%s: tuner attached\n",CARD));
+ DEBUG(printk(CARD_INFO "tuner attached\n",CARD));
if (ztv->tuner_type >= 0)
{
if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0)
- DEBUG(printk(KERN_INFO "%s: attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type));
+ DEBUG(printk(CARD_INFO "attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type));
}
break;
default:
- DEBUG(printk(KERN_INFO "%s: attach_inform; unknown device id=%d\n",CARD,id));
+ DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id));
break;
}
}
switch (id) {
case I2C_DRIVERID_VIDEODECODER:
ztv->have_decoder = 0;
- DEBUG(printk(KERN_INFO "%s: decoder detached\n",CARD));
+ DEBUG(printk(CARD_INFO "decoder detached\n",CARD));
break;
case I2C_DRIVERID_TUNER:
ztv->have_tuner = 0;
- DEBUG(printk(KERN_INFO "%s: tuner detached\n",CARD));
+ DEBUG(printk(CARD_INFO "tuner detached\n",CARD));
break;
default:
- DEBUG(printk(KERN_INFO "%s: detach_inform; unknown device id=%d\n",CARD,id));
+ DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id));
break;
}
}
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/wrapper.h>
+#include <linux/slab.h>
#include <asm/io.h>
#ifdef CONFIG_BIGPHYS_AREA
#include <linux/bigphysarea.h>
#include "zr36120.h"
#include "zr36120_mem.h"
-/* ----------------------------------------------------------------------- */
-/* Memory functions */
-/* shamelessly stolen and adapted from bttv.c */
-/* ----------------------------------------------------------------------- */
+/*******************************/
+/* Memory management functions */
+/*******************************/
-/*
- * convert virtual user memory address to physical address
- * (virt_to_phys only works for kmalloced kernel memory)
- */
-inline unsigned long uvirt_to_phys(unsigned long adr)
-{
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- pgd = pgd_offset(current->mm, adr);
- if (pgd_none(*pgd))
- return 0;
- pmd = pmd_offset(pgd, adr);
- if (pmd_none(*pmd))
- return 0;
- ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
- pte = *ptep;
- /* Note; page_address will panic for us if the page is high */
- if(pte_present(pte))
- return page_address(pte_page(pte))|(adr&(PAGE_SIZE-1));
- return 0;
-}
-
-/*
- * vmalloced address to physical address
- */
-inline unsigned long kvirt_to_phys(unsigned long adr)
-{
- return uvirt_to_phys(VMALLOC_VMADDR(adr));
-}
-
-/*
- * vmalloced address to bus address
- */
-inline unsigned long kvirt_to_bus(unsigned long adr)
+inline int __get_order(unsigned long size)
{
- return virt_to_bus(phys_to_virt(kvirt_to_phys(adr)));
-}
-
-inline int order(unsigned long size)
-{
- int ordr = 0;
+ int order = 0;
size = (size+PAGE_SIZE-1)/PAGE_SIZE;
while (size) {
size /= 2;
- ordr++;
+ order++;
}
- return ordr;
+ return order;
}
-
+
void* bmalloc(unsigned long size)
{
void* mem;
* The following function got a lot of memory at boottime,
* so we know its always there...
*/
- mem = (void*)__get_free_pages(GFP_USER,order(size));
+ mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,__get_order(size));
#endif
if (mem) {
unsigned long adr = (unsigned long)mem;
#ifdef CONFIG_BIGPHYS_AREA
bigphysarea_free_pages(mem);
#else
- free_pages((unsigned long)mem,order(size));
+ free_pages((unsigned long)mem,__get_order(size));
#endif
}
}
-extern inline unsigned long uvirt_to_phys(unsigned long adr);
-
-/* vmalloced address to physical address */
-extern inline unsigned long kvirt_to_phys(unsigned long adr)
-{ return uvirt_to_phys(VMALLOC_VMADDR(adr)); }
-
-/* vmalloced address to bus address */
-extern inline unsigned long kvirt_to_bus(unsigned long adr)
-{ return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); }
-
-/* always vmalloced memory - not always continuous! */
-void* rvmalloc(unsigned long size);
-void rvfree(void* mem, unsigned long size);
-
/* either kmalloc() or bigphysarea() alloced memory - continuous */
void* bmalloc(unsigned long size);
void bfree(void* mem, unsigned long size);
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
-
-/*
-static char alg_rcsid[] = "$Id: i2c-algo-bit.c,v 1.20 1999/11/12 11:26:20 frodo Exp $";
-*/
+/* $Id: i2c-algo-bit.c,v 1.21 1999/12/21 23:45:58 frodo Exp $ */
#include <linux/kernel.h>
#include <linux/module.h>
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-algo-pcf.c,v 1.15 1999/12/21 23:45:58 frodo Exp $ */
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-#define RCSID "$Id: i2c-core.c,v 1.42 1999/11/30 20:06:42 frodo Exp $"
-/* ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
return 0;
}
+int i2c_check_addr (struct i2c_adapter *adapter, int addr)
+{
+ int i;
+ for (i = 0; i < I2C_CLIENT_MAX ; i++)
+ if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+ return -EBUSY;
+ return 0;
+}
int i2c_attach_client(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
int i;
+ if (i2c_check_addr(client->adapter,client->addr))
+ return -EBUSY;
+
for (i = 0; i < I2C_CLIENT_MAX; i++)
if (NULL == adapter->clients[i])
break;
addr <= 0x7f;
addr++) {
+ /* Skip if already in use */
+ if (i2c_check_addr(adapter,addr))
+ continue;
+
/* If it is in one of the force entries, we don't do any detection
at all */
found = 0;
EXPORT_SYMBOL(i2c_detach_client);
EXPORT_SYMBOL(i2c_inc_use_client);
EXPORT_SYMBOL(i2c_dec_use_client);
+EXPORT_SYMBOL(i2c_check_addr);
EXPORT_SYMBOL(i2c_master_send);
But I have used so much of his original code and ideas that it seems
only fair to recognize him as co-author -- Frodo */
+/* $Id: i2c-dev.c,v 1.18 1999/12/21 23:45:58 frodo Exp $ */
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
switch ( cmd ) {
case I2C_SLAVE:
+ case I2C_SLAVE_FORCE:
if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
+ if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
+ return -EBUSY;
client->addr = arg;
return 0;
case I2C_TENBIT:
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */
+
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* -------------------------------------------------------------------------
-static char rcsid[] = "$Id: i2c-elv.c,v 1.11 1999/10/08 14:25:11 frodo Exp $";
- ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-elv.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* -------------------------------------------------------------------- */
-/* $Id: i2c-pcf8584.h,v 1.1 1999/07/18 14:01:33 frodo Exp $ */
/* With some changes from Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */
+
#ifndef I2C_PCF8584_H
#define I2C_PCF8584_H 1
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* -------------------------------------------------------------------------
-static char rcsid[] = "$Id: i2c-philips-par.c,v 1.11 1999/10/08 14:25:11 frodo Exp $";
- ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-philips-par.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */
+
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* -------------------------------------------------------------------------
-static char rcsid[] = "$Id: i2c-velleman.c,v 1.13 1999/10/08 14:25:11 frodo Exp $";
- ------------------------------------------------------------------------- */
+
+/* $Id: i2c-velleman.c,v 1.14 1999/12/21 23:45:58 frodo Exp $ */
#include <linux/kernel.h>
#include <linux/ioport.h>
// #define DRIVERDEBUG
// #define DEBUG_IRQ
+#define dprintk(x)
+
/*
* Size of the I2O module table
*/
static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
int i2o_num_controllers = 0;
static int core_context = 0;
-static int reply_flag = 0;
extern int i2o_online_controller(struct i2o_controller *c);
static int i2o_init_outbound_q(struct i2o_controller *c);
struct i2o_message *);
static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
-static int i2o_quiesce_system(void);
-static int i2o_enable_system(void);
-static void i2o_dump_message(u32 *);
+static void i2o_dump_message(u32 *msg);
+
+static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
static int i2o_lct_get(struct i2o_controller *);
static int i2o_hrt_get(struct i2o_controller *);
struct i2o_message *m)
{
u32 *msg=(u32 *)m;
- u32 status;
- u32 context = msg[3];
+ int status;
+ u32 context = msg[2];
#if 0
i2o_report_status(KERN_INFO, "i2o_core", msg);
if (msg[0] & (1<<13)) // Fail bit is set
{
- printk(KERN_ERR "IOP failed to process the msg:\n");
+ printk(KERN_ERR "%s: Failed to process the msg:\n",c->name);
printk(KERN_ERR " Cmd = 0x%02X, InitiatorTid = %d, TargetTid =%d\n",
(msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] &
0xFFF);
if (msg[4] >> 24)
{
/* 0x40000000 is used as an error report supress bit */
- if((msg[2]&0x40000000)==0)
+ if(msg[2]&0x40000000)
i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
status = -(msg[4] & 0xFFFF);
}
if(*p==c)
{
/* Ask the IOP to switch to HOLD state */
- if (i2o_clear_controller(c) < 0)
- printk("Unable to clear iop%d\n", c->unit);
+ i2o_clear_controller(c);
/* Release IRQ */
c->destructor(c);
return -EBUSY;
}
- if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, &reply_flag, type))
+ if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 1, type))
{
return -EBUSY;
}
if(type == I2O_CLAIM_PRIMARY)
d->owner=h;
else
- i2o_add_management_user(d, h);
+ if (i2o_add_management_user(d, h))
+ printk(KERN_WARNING "i2o: Too many managers for TID %d\n",
+ d->lct_data->tid);
+
spin_unlock(&i2o_configuration_lock);
return 0;
else
{
if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0,
- &reply_flag, type))
+ type))
{
err = -ENXIO;
}
atomic_dec(&d->controller->users);
if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0,
- &reply_flag, type))
+ type))
err = -ENXIO;
}
{
if((jiffies-time)>=5*HZ)
{
-#ifdef DRIVERDEBUG
- printk(KERN_ERR "%s: Timeout waiting for message frame to send %s.\n",
- c->name, why);
-#endif
+ dprintk((KERN_ERR "%s: Timeout waiting for message frame (%s).\n",
+ c->name, why));
return 0xFFFFFFFF;
}
schedule();
{
if(jiffies-time >= timeout*HZ )
{
-#ifdef DRIVERDEBUG
- printk(KERN_ERR "%s: timeout waiting for %s reply.\n",
- c->name, why);
-#endif
+ dprintk((KERN_ERR "%s: timeout waiting for %s reply.\n",
+ c->name, why));
return 0xFFFFFFFF;
}
schedule();
}
-static int i2o_query_scalar_polled(struct i2o_controller *c, int tid, void *buf, int buflen,
- int group, int field)
-{
- u32 m;
- u32 *msg;
- u16 op[8];
- u32 *p;
- int i;
- u32 *rbuf;
-
- op[0]=1; /* One Operation */
- op[1]=0; /* PAD */
- op[2]=1; /* FIELD_GET */
- op[3]=group; /* group number */
- op[4]=1; /* 1 field */
- op[5]=field; /* Field number */
-
- m=i2o_wait_message(c, "ParamsGet");
- if(m==0xFFFFFFFF)
- {
- return -ETIMEDOUT;
- }
-
- msg=(u32 *)(c->mem_offset+m);
-
- rbuf=kmalloc(buflen+32, GFP_KERNEL);
- if(rbuf==NULL)
- {
- printk(KERN_ERR "No free memory for scalar read.\n");
- return -ENOMEM;
- }
-
- __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_5, &msg[0]);
- __raw_writel(I2O_CMD_UTIL_PARAMS_GET<<24|HOST_TID<<12|tid, &msg[1]);
- __raw_writel(0, &msg[2]); /* Context */
- __raw_writel(0, &msg[3]);
- __raw_writel(0, &msg[4]);
- __raw_writel(0x54000000|12, &msg[5]);
- __raw_writel(virt_to_bus(op), &msg[6]);
- __raw_writel(0xD0000000|(32+buflen), &msg[7]);
- __raw_writel(virt_to_bus(rbuf), &msg[8]);
-
- i2o_post_message(c,m);
- barrier();
-
- /*
- * Now wait for a reply
- */
-
- m=i2o_wait_reply(c, "ParamsGet", 5);
-
- if(m==0xFFFFFFFF)
- {
- kfree(rbuf);
- return -ETIMEDOUT;
- }
-
- msg = (u32 *)bus_to_virt(m);
- if(msg[4]>>24)
- {
- i2o_report_status(KERN_WARNING, "i2o_core", msg);
- }
-
- p=rbuf;
-
- /* Ok 'p' is the reply block - lets see what happened */
- /* p0->p2 are the header */
-
- /* FIXME: endians - turn p3 to little endian */
-
- if((p[0]&0xFFFF)!=1)
- printk(KERN_WARNING "Suspicious field read return 0x%08X\n", p[0]);
-
- i=(p[1]&0xFFFF)<<2; /* Message size */
- if(i<buflen)
- buflen=i;
-
- /* Do we have an error block ? */
- if(p[1]&0xFF000000)
- {
-#ifdef DRIVERDEBUG
- printk(KERN_ERR "%s: error in field read.\n",
- c->name);
-#endif
- kfree(rbuf);
- return -EBADR;
- }
-
- /* p[1] holds the more flag and row count - we dont care */
-
- /* Ok it worked p[2]-> hold the data */
- memcpy(buf, p+2, buflen);
-
- kfree(rbuf);
-
- /* Finally return the message */
- I2O_REPLY_WRITE32(c,m);
- return buflen;
-}
-
/*
* Dump the information block associated with a given unit (TID)
*/
static int i2o_parse_hrt(struct i2o_controller *c)
{
#ifdef DRIVERDEBUG
- u32 *rows=(u32*)c->hrt;
+ u32 *rows=(u32 *)c->hrt;
u8 *p=(u8 *)c->hrt;
u8 *d;
int count;
int length;
int i;
int state;
-
- if(p[3]!=0)
- {
- printk(KERN_ERR "i2o: HRT table for controller is too new a version.\n");
- return -1;
+
+ if(p[3]!=0) {
+ printk(KERN_ERR "%s: HRT table for controller is too new a version.\n",
+ c->name);
+ return -1;
}
-
+
count=p[0]|(p[1]<<8);
length = p[2];
- printk(KERN_INFO "iop%d: HRT has %d entries of %d bytes each.\n",
- c->unit, count, length<<2);
+ printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
+ c->name, count, length<<2);
rows+=2;
printk("\n");
rows+=length;
}
+
#endif
return 0;
}
if(max==0)
{
- printk(KERN_ERR "LCT is empty????\n");
+ printk(KERN_ERR "%s: LCT is empty????\n",c->name);
return -1;
}
-
- printk(KERN_INFO "LCT has %d entries.\n", max);
+
+ printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max);
if(max > 128)
{
- printk(KERN_INFO "LCT was truncated.\n");
+ printk(KERN_INFO "%s: LCT was truncated.\n",c->name);
max=128;
}
if(lct->iop_flags&(1<<0))
- printk(KERN_WARNING "I2O: Configuration dialog desired by iop%d.\n", c->unit);
+ printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
for(i=0;i<max;i++)
{
d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
if(d==NULL)
{
- printk("i2o_core: Out of memory for I2O device data.\n");
+ printk(KERN_CRIT "i2o_core: Out of memory for I2O device data.\n");
return -ENOMEM;
}
int i2o_quiesce_controller(struct i2o_controller *c)
{
u32 msg[4];
+ int ret;
- if(c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)
+ if ((c->status_block->iop_state != ADAPTER_STATE_READY) &
+ (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
+ {
+ dprintk((KERN_INFO "%s: Not in READY or OPERATIONAL state\n",
+ c->name));
+ dprintk((KERN_INFO "%s: state = %d\n",
+ c->name, c->status_block->iop_state));
return -EINVAL;
+ }
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
- msg[2]=(u32)core_context;
- msg[3]=(u32)&reply_flag;
+ /* msg[2] and msg[3] filled in i2o_post_wait */
/* Long timeout needed for quiesce if lots of devices */
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Posting quiesce message to iop%d\n", c->unit);
-#endif
- if(i2o_post_wait(c, msg, sizeof(msg), 120))
- return -1;
+
+ if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120)))
+ printk(KERN_INFO "%s: Unable to quiesce.\n", c->name);
else
- return 0;
+ dprintk((KERN_INFO "%s: Quiesced.\n", c->name));
+
+ return ret;
}
/* Enable IOP */
int i2o_enable_controller(struct i2o_controller *c)
{
u32 msg[4];
-
+ int ret;
+
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
- msg[2]=core_context;
- msg[3]=(u32)&reply_flag;
+ /* msg[2] and msg[3] filled in i2o_post_wait */
/* How long of a timeout do we need? */
- return i2o_post_wait(c, msg, sizeof(msg), 240);
-}
-
-/*
- * Quiesce _all_ IOPs in OP state.
- * Used during init/shutdown time.
- */
-int i2o_quiesce_system(void)
-{
- struct i2o_controller *iop;
- int ret = 0;
-
- for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
- {
- /*
- * Quiesce only needed on operational IOPs
- */
- i2o_status_get(iop);
-
- if(iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
- {
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Attempting to quiesce iop%d\n", iop->unit);
-#endif
- if(i2o_quiesce_controller(iop))
- {
- printk(KERN_INFO "Unable to quiesce iop%d\n", iop->unit);
- ret = -ENXIO;
- }
-#ifdef DRIVERDEBUG
- else
- printk(KERN_INFO "%s quiesced\n", iop->name);
-#endif
-
- i2o_status_get(iop); // Update IOP state information
- }
- }
-
- return ret;
-}
-
-/*
- * (re)Enable _all_ IOPs in READY state.
- */
-int i2o_enable_system(void)
-{
- struct i2o_controller *iop;
- int ret = 0;
-
- for(iop=i2o_controller_chain; iop != NULL; iop=iop->next)
- {
- /*
- * Enable only valid for IOPs in READY state
- */
- i2o_status_get(iop);
- if(iop->status_block->iop_state == ADAPTER_STATE_READY)
- {
- if(i2o_enable_controller(iop)<0)
- printk(KERN_INFO "Unable to (re)enable iop%d\n",
- iop->unit);
-
- i2o_status_get(iop); // Update IOP state information
- }
- }
+ if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
+ printk(KERN_ERR "%s: Could not enable, %d\n", c->name, ret);
return ret;
}
-
/* Reset an IOP, but keep message queues alive */
int i2o_clear_controller(struct i2o_controller *c)
{
u32 msg[4];
int ret;
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Clearing iop%d\n", c->unit);
-#endif
-
- /* Then clear the IOP */
msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
- msg[2]=core_context;
- msg[3]=(u32)&reply_flag;
+ /* msg[2] and msg[3] filled in i2o_post_wait */
- if((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
- printk(KERN_INFO "ExecIopClear failed: %#10x\n", ret);
-#ifdef DRIVERDEBUG
- else
- printk(KERN_INFO "ExecIopClear success!\n");
-#endif
+ if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
+ printk(KERN_INFO "%s: Unable to clear, %#10x\n",
+ c->name, ret);
+
+ i2o_status_get(c); // Reread the Status Block
return ret;
}
static int i2o_reset_controller(struct i2o_controller *c)
{
u32 m;
- u8 *work8;
+ u8 *status;
u32 *msg;
long time;
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Reseting iop%d\n", c->unit);
-#endif
-
- /* Get a message */
m=i2o_wait_message(c, "AdapterReset");
if(m==0xFFFFFFFF)
return -ETIMEDOUT;
msg=(u32 *)(c->mem_offset+m);
-
- work8=(void *)kmalloc(4, GFP_KERNEL);
- if(work8==NULL) {
- printk(KERN_ERR "IOP reset failed - no free memory.\n");
+
+ status = kmalloc(4,GFP_KERNEL);
+ if (status==NULL) {
+ printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
+ c->name);
return -ENOMEM;
}
-
- memset(work8, 0, 4);
-
+ memset(status,0,4);
+
msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
msg[2]=core_context;
- msg[3]=(u32)&reply_flag;
+ msg[3]=0;
msg[4]=0;
msg[5]=0;
- msg[6]=virt_to_phys(work8);
+ msg[6]=virt_to_phys(status);
msg[7]=0; /* 64bit host FIXME */
- /* Then reset the IOP */
i2o_post_message(c,m);
/* Wait for a reply */
time=jiffies;
-
- /* DPT driver claims they need this */
- mdelay(5);
-
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Reset posted, waiting...\n");
-#endif
- while(work8[0]==0)
+ while (status[0]==0)
{
if((jiffies-time)>=5*HZ)
{
- printk(KERN_ERR "IOP reset timeout.\n");
- kfree(work8);
+ printk(KERN_ERR "%s: IOP reset timeout.\n", c->name);
+ kfree(status);
return -ETIMEDOUT;
}
schedule();
barrier();
}
- if (work8[0]==0x02)
- {
- printk(KERN_WARNING "IOP Reset rejected\n");
- }
+ if (status[0]==0x02)
+ printk(KERN_WARNING "%s: Reset rejected.\n",c->name);
else
{
/*
* Once the reset is sent, the IOP goes into the INIT state
- * which is indeterminate. We need to wait until the IOP
+ * which is inditerminate. We need to wait until the IOP
* has rebooted before we can let the system talk to
* it. We read the inbound Free_List until a message is
* available. If we can't read one in the given ammount of
* time, we assume the IOP could not reboot properly.
*/
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Reset succeeded...waiting for reboot\n");
-#endif
+
time = jiffies;
m = I2O_POST_READ32(c);
while(m == 0XFFFFFFFF)
{
if((jiffies-time) >= 30*HZ)
{
- printk(KERN_ERR "i2o/iop%d: Timeout waiting for IOP reset.\n",
- c->unit);
+ printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n",
+ c->name);
+ kfree(status);
return -ETIMEDOUT;
}
schedule();
barrier();
m = I2O_POST_READ32(c);
}
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Reboot completed\n");
-#endif
+
+ i2o_flush_reply(c,m);
+ printk(KERN_INFO "%s: Reset completed.\n", c->name);
}
+ kfree(status);
return 0;
}
u32 m;
u32 *msg;
u8 *status_block;
- int i;
-
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Getting status block for iop%d\n", c->unit);
-#endif
- if(c->status_block)
- kfree(c->status_block);
- c->status_block =
- (i2o_status_block *)kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
- if(c->status_block == NULL)
- {
-#ifdef DRIVERDEBUG
- printk(KERN_ERR "No memory in status get!\n");
-#endif
- return -ENOMEM;
+ if (c->status_block == NULL) {
+ c->status_block = (i2o_status_block *)
+ kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
+ if (c->status_block == NULL)
+ {
+ printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", c->name);
+ return -ENOMEM;
+ }
}
status_block = (u8*)c->status_block;
-
+ memset(c->status_block,0,sizeof(i2o_status_block));
+
m=i2o_wait_message(c, "StatusGet");
if(m==0xFFFFFFFF)
return -ETIMEDOUT;
-
- memset(status_block, 0, sizeof(i2o_status_block));
msg=(u32 *)(c->mem_offset+m);
- __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
- __raw_writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]);
- __raw_writel(0, &msg[2]);
- __raw_writel(0, &msg[3]);
- __raw_writel(0, &msg[4]);
- __raw_writel(0, &msg[5]);
- __raw_writel(virt_to_bus(c->status_block), &msg[6]);
- __raw_writel(0, &msg[7]); /* 64bit host FIXME */
- __raw_writel(sizeof(i2o_status_block), &msg[8]);
-
+
+ msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
+ msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
+ msg[2]=core_context;
+ msg[3]=0;
+ msg[4]=0;
+ msg[5]=0;
+ msg[6]=virt_to_phys(c->status_block);
+ msg[7]=0; /* 64bit host FIXME */
+ msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
+
i2o_post_message(c,m);
-
- /* DPT work around */
- mdelay(5);
/* Wait for a reply */
- time=jiffies;
- while((jiffies-time)<=HZ)
+ time=jiffies;
+ while(status_block[87]!=0xFF)
{
- if(status_block[87]!=0)
+ if((jiffies-time)>=5*HZ)
{
- /* Ok the reply has arrived. Fill in the important stuff */
- c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
- return 0;
+ printk(KERN_ERR "%s: Get status timeout.\n",c->name);
+ return -ETIMEDOUT;
}
schedule();
barrier();
}
+
+ /* Ok the reply has arrived. Fill in the important stuff */
+ c->inbound_size = c->status_block->inbound_frame_size *4;
+
#ifdef DRIVERDEBUG
- printk(KERN_ERR "IOP get status timeout.\n");
+ printk(KERN_INFO "%s: State = ", c->name);
+ switch (c->status_block->iop_state) {
+ case 0x01:
+ printk("INIT\n");
+ break;
+ case 0x02:
+ printk("RESET\n");
+ break;
+ case 0x04:
+ printk("HOLD\n");
+ break;
+ case 0x05:
+ printk("READY\n");
+ break;
+ case 0x08:
+ printk("OPERATIONAL\n");
+ break;
+ case 0x10:
+ printk("FAILED\n");
+ break;
+ case 0x11:
+ printk("FAULTED\n");
+ break;
+ default:
+ printk("%x (unknown !!)\n",c->status_block->iop_state);
+ }
#endif
- return -ETIMEDOUT;
+
+ return 0;
}
int i2o_hrt_get(struct i2o_controller *c)
{
u32 msg[6];
+ int ret, size = sizeof(i2o_hrt);
- if(c->hrt)
- kfree(c->hrt);
+ /* Read first just the header to figure out the real size */
- c->hrt=kmalloc(2048, GFP_KERNEL);
- if(c->hrt==NULL)
- {
- printk(KERN_ERR "IOP init failed; no memory.\n");
- return -ENOMEM;
- }
+ do {
+ if (c->hrt == NULL) {
+ c->hrt=kmalloc(size, GFP_KERNEL);
+ if (c->hrt == NULL) {
+ printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name);
+ return -ENOMEM;
+ }
+ }
- msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
- msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
- msg[2]= core_context;
- msg[3]= 0x0; /* Transaction context */
- msg[4]= (0xD0000000 | 2048); /* Simple transaction , 2K */
- msg[5]= virt_to_phys(c->hrt); /* Dump it here */
+ msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
+ msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
+ /* msg[2] and msg[3] filled in i2o_post_wait */
+ msg[4]= (0xD0000000 | size); /* Simple transaction */
+ msg[5]= virt_to_phys(c->hrt); /* Dump it here */
+
+ if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
+ printk(KERN_ERR "%s: Unable to get HRT,"
+ " Status = %d.\n",c->name, ret);
+ return ret;
+ }
+
+ if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) {
+ size = c->hrt->num_entries * c->hrt->entry_len << 2;
+ kfree(c->hrt);
+ c->hrt = NULL;
+ }
+ } while (c->hrt == NULL);
+
+ i2o_parse_hrt(c); // just for debugging
- return i2o_post_wait(c, msg, sizeof(msg), 20);
+ return 0;
}
-static int i2o_systab_send(struct i2o_controller* iop)
+static int i2o_systab_send(struct i2o_controller *iop)
{
- u32 msg[10];
- u32 privmem[2];
- u32 privio[2];
- int ret;
+ u32 msg[12];
+ u32 privmem[2];
+ u32 privio[2];
+ int ret;
- privmem[0]=iop->priv_mem; /* Private memory space base address */
- privmem[1]=iop->priv_mem_size;
- privio[0]=iop->priv_io; /* Private I/O address */
- privio[1]=iop->priv_io_size;
-
- msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_6;
- msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
- msg[2] = 0; /* Context not needed */
- msg[3] = 0;
- msg[4] = (0<<16)|((iop->unit+2)<<12); /* Host 0 IOP ID (unit + 2) */
- msg[5] = 0; /* Segment 0 */
-
- /*
- * Scatter Gather List
+ /* See i2o_status_block */
+#if 0
+ iop->status->current_mem_base;
+ iop->status->current_mem_size;
+ iop->status->current_io_base;
+ iop->status->current_io_size;
+#endif
+ privmem[0]=iop->priv_mem; /* Private memory space base address */
+ privmem[1]=iop->priv_mem_size;
+ privio[0]=iop->priv_io; /* Private I/O address */
+ privio[1]=iop->priv_io_size;
+
+ msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
+ msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
+ /* [2] and [3] filled in i2o_post_wait */
+ msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+ msg[5] = 0; /* Segment 0 */
+
+ /*
+ * Provide three SGL-elements:
+ * System table (SysTab), Private memory space declaration and
+ * Private i/o space declaration
*/
- msg[6] = 0x54000000|sys_tbl_len;
- msg[7] = virt_to_phys(sys_tbl);
- msg[8] = 0xD4000000|48; /* One table for now */
- msg[9] = virt_to_phys(privmem);
-/* msg[10] = virt_to_phys(privio); */
-
- ret=i2o_post_wait(iop, msg, sizeof(msg), 120);
- if(ret)
- return ret;
+ msg[6] = 0x54000000 | sys_tbl_len;
+ msg[7] = virt_to_phys(sys_tbl);
+ msg[8] = 0x54000000 | 0;
+ msg[9] = virt_to_phys(privmem);
+ msg[10] = 0xD4000000 | 0;
+ msg[11] = virt_to_phys(privio);
- return 0;
-}
+ if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
+ printk(KERN_INFO "%s: Unable to set SysTab, %d\n",
+ iop->name, ret);
+
+ return ret;
+
+ }
/*
* Initialize I2O subsystem.
*
* 1. Quiesce all controllers
* 2. Delete all controllers
- *
*/
static void i2o_sys_shutdown(void)
{
- struct i2o_controller *iop = NULL;
+ struct i2o_controller *iop, *niop;
- i2o_quiesce_system();
- for(iop = i2o_controller_chain; iop; iop = iop->next)
- {
- if(i2o_delete_controller(iop))
- iop->bus_disable(iop);
+ for (iop = i2o_controller_chain; iop ; iop=iop->next) {
+ i2o_quiesce_controller(iop);
+ i2o_status_get(iop); // Update IOP status block
+ }
+
+ for (iop = i2o_controller_chain; iop; iop = niop) {
+ niop = iop->next;
+ if (i2o_delete_controller(iop))
+ iop->bus_disable(iop);
}
}
int i;
int ret;
- printk(KERN_INFO "Configuring I2O controller at 0x%08X.\n",
- (u32)c->mem_phys);
+ printk(KERN_INFO "%s: Configuring I2O controller at 0x%08X.\n",
+ c->name, (u32)c->mem_phys);
if((ret=i2o_status_get(c)))
return ret;
return ret;
}
- if((ret=i2o_init_outbound_q(c)))
- {
- printk(KERN_ERR
- "IOP%d initialization failed: Could not initialize outbound queue\n",
- c->unit);
+ if ((ret=i2o_init_outbound_q(c))){
return ret;
}
/* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */
- c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
- if(c->page_frame==NULL)
- {
- printk(KERN_ERR "IOP init failed: no memory for message page.\n");
- return -ENOMEM;
- }
-
- m=virt_to_phys(c->page_frame);
-
- for(i=0; i< NMBR_MSG_FRAMES; i++)
- {
- I2O_REPLY_WRITE32(c,m);
- mb();
- m+=MSG_FRAME_SIZE;
- mb();
- }
-
/*
* The outbound queue is initialised and loaded,
*
* Now we need the Hardware Resource Table. We must ask for
* this next we can't issue random messages yet.
*/
- ret=i2o_hrt_get(c); if(ret) return ret;
-
- ret=i2o_parse_hrt(c);
- if(ret)
+
+ if ((ret=i2o_hrt_get(c)))
return ret;
return i2o_online_controller(c);
*/
int i2o_init_outbound_q(struct i2o_controller *c)
{
- u8 workspace[88];
+ u8 *status;
u32 m;
u32 *msg;
u32 time;
+ int i;
- memset(workspace, 0, 88);
-
-// printk(KERN_INFO "i2o/iop%d: Initializing Outbound Queue\n", c->unit);
m=i2o_wait_message(c, "OutboundInit");
if(m==0xFFFFFFFF)
- {
- kfree(workspace);
return -ETIMEDOUT;
- }
-
msg=(u32 *)(c->mem_offset+m);
+
+ status = kmalloc(4,GFP_KERNEL);
+ if (status==NULL) {
+ printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
+ c->name);
+ return -ENOMEM;
+ }
+ memset(status, 0, 4);
+
msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
msg[2]= core_context;
msg[4]= 4096; /* Host page frame size */
msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size and Initcode */
msg[6]= 0xD0000004; /* Simple SG LE, EOB */
- msg[7]= virt_to_bus(workspace);
- *((u32 *)workspace)=0;
+ msg[7]= virt_to_phys(status);
- /*
- * Post it
- */
i2o_post_message(c,m);
- barrier();
-
+ barrier();
time=jiffies;
-
- while(workspace[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE)
+ while(status[0]!=I2O_CMD_OUTBOUND_INIT_COMPLETE)
{
if((jiffies-time)>=5*HZ)
{
- printk(KERN_ERR "i2o/iop%d: IOP outbound initialise failed.\n",
- c->unit);
+ printk(KERN_ERR "%s: Outbound Q initialize timeout.\n",
+ c->name);
+ kfree(status);
return -ETIMEDOUT;
}
schedule();
barrier();
}
+ c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
+ if(c->page_frame==NULL) {
+ printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
+ c->name);
+ kfree(status);
+ return -ENOMEM;
+ }
+ m=virt_to_phys(c->page_frame);
+
+ for(i=0; i< NMBR_MSG_FRAMES; i++) {
+ I2O_REPLY_WRITE32(c,m);
+ mb();
+ m += MSG_FRAME_SIZE;
+ }
+
+ kfree(status);
return 0;
}
int i2o_lct_get(struct i2o_controller *c)
{
u32 msg[8];
+ int ret, size = c->status_block->expected_lct_size;
+
+ do {
+ if (c->lct == NULL) {
+ c->lct = kmalloc(size, GFP_KERNEL);
+ if(c->lct == NULL) {
+ printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
+ c->name);
+ return -ENOMEM;
+ }
+ }
+ memset(c->lct, 0, size);
+
+ msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+ msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+ /* msg[2] and msg[3] filled in i2o_post_wait */
+ msg[4] = 0xFFFFFFFF; /* All devices */
+ msg[5] = 0x00000000; /* Report now */
+ msg[6] = 0xD0000000|size;
+ msg[7] = virt_to_bus(c->lct);
+
+ if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) {
+ printk(KERN_ERR "%s: Unable to get LCT,"
+ " Status = %d.\n", c->name,ret);
+ return ret;
+ }
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Getting lct for iop%d\n", c->unit);
-#endif
-
- if(c->lct)
- kfree(c->lct);
+ if (c->lct->table_size << 2 > size) {
+ size = c->lct->table_size << 2;
+ kfree(c->lct);
+ c->lct = NULL;
+ }
+ } while (c->lct == NULL);
- c->lct = kmalloc(8192, GFP_KERNEL);
- if(c->lct==NULL)
- {
- printk(KERN_ERR "i2o/iop%d: No free memory for i2o controller buffer.\n",
- c->unit);
- return -ENOMEM;
- }
-
- memset(c->lct, 0, 8192);
-
- msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
- msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
- msg[2] = 0; /* Context not needed */
- msg[3] = 0;
- msg[4] = 0xFFFFFFFF; /* All devices */
- msg[5] = 0x00000000; /* Report now */
- msg[6] = 0xD0000000|8192;
- msg[7] = virt_to_bus(c->lct);
-
- return(i2o_post_wait(c, msg, sizeof(msg), 120));
+ return 0;
}
u32 msg[10];
u32 privmem[2];
u32 privio[2];
- u32 systab[32];
int ret;
- systab[0]=1;
- systab[1]=0;
- systab[2]=0;
- systab[3]=0;
- systab[4]=0; /* Organisation ID */
- systab[5]=2; /* Ident 2 for now */
- systab[6]=0<<24|0<<16|I2OVERSION<<12|1; /* Memory mapped, IOPState, v1.5, segment 1 */
- systab[7]=MSG_FRAME_SIZE>>2; /* Message size */
- systab[8]=0; /* LastChanged */
- systab[9]=0; /* Should be IOP capabilities */
- systab[10]=virt_to_phys(c->post_port);
- systab[11]=0;
-
- i2o_build_sys_table();
+ /*
+ * Build and send the system table
+ *
+ * If build_sys_table fails, we kill everything and bail
+ * as we can't init the IOPs w/o a system table
+ */
+
+ if (i2o_build_sys_table()) {
+ i2o_sys_shutdown();
+ return;
+ }
privmem[0]=c->priv_mem; /* Private memory space base address */
privmem[1]=c->priv_mem_size;
privio[0]=c->priv_io; /* Private I/O address */
privio[1]=c->priv_io_size;
- __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_6, &msg[0]);
- __raw_writel(I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
- __raw_writel(0, &msg[2]); /* Context not needed */
- __raw_writel(0, &msg[3]);
- __raw_writel((0<<16)|(2<<12), &msg[4]); /* Host 1 I2O 2 */
- __raw_writel(0, &msg[5]); /* Segment 1 */
-
- /*
- * Scatter Gather List
- */
-
- __raw_writel(0x54000000|sys_tbl_len, &msg[6]); /* One table for now */
- __raw_writel(virt_to_phys(sys_tbl), &msg[[7]);
- __raw_writel(0xD4000000|48, &msg[8]); /* One table for now */
- __raw_writel(virt_to_phys(privmem), &msg[9]);
-
- return(i2o_post_wait(c, msg, sizeof(msg), 120));
-
- /*
- * Finally we go online
- */
- ret = i2o_enable_controller(c);
- if(ret)
- return ret;
-
- /*
- * Grab the LCT, see what is attached
- */
- ret=i2o_lct_get(c);
- if(ret)
- {
- /* Maybe we should do also do something else */
- return ret;
- }
+ __raw_writel(TEN_WORD_MSG_SIZE|SGL_OFFSET_6, &msg[0]);
+ __raw_writel(I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID, &msg$
+ __raw_writel(0, &msg[2]); /* Context not needed */
+ __raw_writel(0, &msg[3]);
+ __raw_writel((0<<16)|(2<<12), &msg[4]); /* Host 1 I2O 2 */
+ __raw_writel(0, &msg[5]); /* Segment 1 */
+
+ /*
+ * Scatter Gather List
+ */
+
+ __raw_writel(0x54000000|sys_tbl_len, &msg[6]); /* One table for now */
+ __raw_writel(virt_to_phys(sys_tbl), &msg[[7]);
+ __raw_writel(0xD4000000|48, &msg[8]); /* One table for now */
+ __raw_writel(virt_to_phys(privmem), &msg[9]);
+
+ ret = (i2o_post_wait(c, msg, sizeof(msg), 120);
+ if (ret)
+ return ret;
+
+ /*
+ * Finally we go online
+ */
+ ret = i2o_enable_controller(c);
+ if(ret)
+ return ret;
+
+ /*
+ * Grab the LCT, see what is attached
+ */
+ ret=i2o_lct_get(c);
+ if(ret)
+ {
+ /* Maybe we should do also do something else */
+ return ret;
+ }
- ret=i2o_parse_lct(c);
- if(ret)
- return ret;
+ ret=i2o_parse_lct(c);
+ if(ret)
+ return ret;
- return 0;
+ return 0;
#endif
}
{
struct i2o_controller *iop = NULL;
int count = 0;
-#ifdef DRIVERDEBUG
- u32 *table;
-#endif
sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs
(i2o_num_controllers) *
sizeof(struct i2o_sys_tbl_entry);
-#ifdef DRIVERDEBUG
- printk(KERN_INFO "Building system table len = %d\n", sys_tbl_len);
-#endif
if(sys_tbl)
kfree(sys_tbl);
sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL);
- if(!sys_tbl)
+ if(!sys_tbl) {
+ printk(KERN_CRIT "SysTab Set failed. Out of memory.\n");
return -ENOMEM;
+ }
memset((void*)sys_tbl, 0, sys_tbl_len);
sys_tbl->num_entries = i2o_num_controllers;
for(iop = i2o_controller_chain; iop; iop = iop->next)
{
- // Get updated IOP state so we have the latest information
- i2o_status_get(iop);
+ // Get updated Status Block so we have the latest information
+ if (i2o_status_get(iop)) {
+ sys_tbl->num_entries--;
+ continue; // try next one
+ }
sys_tbl->iops[count].org_id = iop->status_block->org_id;
sys_tbl->iops[count].iop_id = iop->unit + 2;
}
#ifdef DRIVERDEBUG
- table = (u32*)sys_tbl;
+{
+ u32 *table = (u32*)sys_tbl;
for(count = 0; count < (sys_tbl_len >>2); count++)
- printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);
+ printk(KERN_INFO "sys_tbl[%d] = %0#10x\n",
+ count, table[count]);
+}
#endif
return 0;
if(m==0xFFFFFFFF)
{
- printk(KERN_ERR "i2o/iop%d: Timeout waiting for message frame!\n",
- c->unit);
+ printk(KERN_ERR "%s: Timeout waiting for message frame!\n",
+ c->name);
return -ETIMEDOUT;
}
+
msg = (u32 *)(c->mem_offset + m);
- memcpy_toio(msg, data, len);
+ memcpy_toio(msg, data, len);
i2o_post_message(c,m);
return 0;
}
DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post);
int status = 0;
int flags = 0;
- int ret = 0;
struct i2o_post_wait_data *p1, *p2;
struct i2o_post_wait_data *wait_data =
kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
if(!wait_data)
- return -ETIMEDOUT;
+ return -ENOMEM;
- p1 = p2 = NULL;
-
/*
* The spin locking is needed to keep anyone from playing
* with the queue pointers and id while we do the same
spin_lock_irqsave(&post_wait_lock, flags);
wait_data->next = post_wait_queue;
post_wait_queue = wait_data;
- wait_data->id = ++post_wait_id;
+ wait_data->id = (++post_wait_id) & 0x7fff;
spin_unlock_irqrestore(&post_wait_lock, flags);
wait_data->wq = &wq_i2o_post;
- wait_data->status = -ETIMEDOUT;
+ wait_data->status = -EAGAIN;
- msg[3] = (u32)wait_data->id;
- msg[2] = 0x80000000|(u32)core_context;
+ msg[2]=0x80000000|(u32)core_context|((u32)wait_data->id<<16);
- if((ret=i2o_post_this(c, msg, len)))
- return ret;
- /*
- * Go to sleep and wait for timeout or wake_up call
- */
- interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
-
- /*
- * Grab transaction status
- */
- status = wait_data->status;
+ if ((status = i2o_post_this(c, msg, len))==0) {
+ interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
+ status = wait_data->status;
+ }
- /*
- * Remove the entry from the queue.
- * Since i2o_post_wait() may have been called again by
- * a different thread while we were waiting for this
- * instance to complete, we're not guaranteed that
- * this entry is at the head of the queue anymore, so
- * we need to search for it, find it, and delete it.
- */
+ p2 = NULL;
spin_lock_irqsave(&post_wait_lock, flags);
- for(p1 = post_wait_queue; p1; )
- {
- if(p1 == wait_data)
- {
+ for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) {
+ if(p1 == wait_data) {
if(p2)
p2->next = p1->next;
else
post_wait_queue = p1->next;
-
break;
}
- p1 = p1->next;
}
spin_unlock_irqrestore(&post_wait_lock, flags);
*/
static void i2o_post_wait_complete(u32 context, int status)
{
- struct i2o_post_wait_data *p1 = NULL;
+ struct i2o_post_wait_data *p1;
/*
* We need to search through the post_wait
* around while we're looking through them.
*/
spin_lock(&post_wait_lock);
- for(p1 = post_wait_queue; p1; p1 = p1->next)
- {
- if(p1->id == context)
- {
+ for(p1 = post_wait_queue; p1; p1 = p1->next) {
+ if(p1->id == ((context >> 16) & 0x7fff)) {
p1->status = status;
- wake_up_interruptible(p1->wq);
spin_unlock(&post_wait_lock);
+ wake_up_interruptible(p1->wq);
return;
}
}
spin_unlock(&post_wait_lock);
- printk(KERN_DEBUG "i2o_post_wait reply after timeout!");
+ printk(KERN_DEBUG "i2o: i2o_post_wait reply after timeout!");
}
/*
- * Issue UTIL_CLAIM messages
+ * Send UTIL_EVENT messages
+ */
+
+int i2o_event_register(struct i2o_controller *c, int tid, int context,
+ u32 evt_mask)
+{
+ u32 msg[5];
+
+ msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
+ msg[1] = I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | tid;
+ msg[2] = context;
+ msg[3] = 0;
+ msg[4] = evt_mask;
+
+ if (i2o_post_this(c, msg, sizeof(msg)) < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+int i2o_event_ack(struct i2o_controller *c, int tid, int context,
+ u32 evt_indicator, void *evt_data, int evt_data_len)
+{
+ u32 msg[c->inbound_size];
+
+ msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5;
+ msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid;
+ /* msg[2] and msg[3] filled in i2o_post_wait */
+ msg[4] = evt_indicator;
+ memcpy(msg+5, evt_data, evt_data_len);
+
+ if (i2o_post_this(c, msg, sizeof(msg)) < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/*
+ * Issue UTIL_CLAIM or UTIL_RELEASE messages
*/
-int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, int *flag, u32 type)
+static int i2o_issue_claim(struct i2o_controller *c, int tid, int context, int onoff, u32 type)
{
- u32 msg[6];
+ u32 msg[5];
msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
if(onoff)
msg[1] = I2O_CMD_UTIL_CLAIM << 24 | HOST_TID<<12 | tid;
else
msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid;
-
- /* The 0x80000000 convention for flagging is assumed by this helper */
-
- msg[2] = 0x80000000|context;
- msg[3] = (u32)flag;
+
+ /* msg[2] and msg[3] filled in i2o_post_wait */
msg[4] = type;
- return i2o_post_wait(c, msg, 20, 2);
+ return i2o_post_wait(c, msg, sizeof(msg), 2);
}
/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
void *opblk, int oplen, void *resblk, int reslen)
{
u32 msg[9];
- u8 *res = (u8 *)resblk;
- int res_count;
- int blk_size;
- int bytes;
+ u32 *res = (u32 *)resblk;
int wait_status;
msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
msg[7] = 0xD0000000 | reslen; /* ResultBlock */
msg[8] = virt_to_bus(resblk);
- wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10);
- if (wait_status)
- return wait_status; /* -DetailedStatus */
+ if ((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 20)))
+ return wait_status; /* -DetailedStatus */
if (res[1]&0x00FF0000) /* BlockStatus != SUCCESS */
{
- printk(KERN_WARNING "%s - Error:\n ErrorInfoSize = 0x%02x, "
- "BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
- (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
- : "PARAMS_GET",
- res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
+ printk(KERN_WARNING "%s: %s - Error:\n ErrorInfoSize = 0x%02x, "
+ "BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+ iop->name,
+ (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+ : "PARAMS_GET",
+ res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
}
- res_count = res[0] & 0xFFFF; /* # of resultblocks */
- bytes = 4;
- res += 4;
- while (res_count--)
- {
- blk_size = (res[0] & 0xFFFF) << 2;
- bytes += blk_size;
- res += blk_size;
- }
-
- return bytes; /* total sizeof Result List in bytes */
+ return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */
}
/*
if (field == -1) /* whole group */
opblk[4] = -1;
-
+
size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid,
opblk, sizeof(opblk), resblk, sizeof(resblk));
-
+
if (size < 0)
return size;
EXPORT_SYMBOL(i2o_unlock_controller);
EXPORT_SYMBOL(i2o_find_controller);
EXPORT_SYMBOL(i2o_num_controllers);
+
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_event_ack);
+
EXPORT_SYMBOL(i2o_claim_device);
EXPORT_SYMBOL(i2o_release_device);
EXPORT_SYMBOL(i2o_run_queue);
EXPORT_SYMBOL(i2o_post_this);
EXPORT_SYMBOL(i2o_post_wait);
-EXPORT_SYMBOL(i2o_issue_claim);
EXPORT_SYMBOL(i2o_issue_params);
EXPORT_SYMBOL(i2o_report_status);
MODULE_AUTHOR("Red Hat Software");
MODULE_DESCRIPTION("I2O Core");
-
int init_module(void)
{
- printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
+ printk(KERN_INFO "I2O Core - (c) Copyright 1999 Red Hat Software.\n");
if (i2o_install_handler(&i2o_core_handler) < 0)
{
printk(KERN_ERR
- "i2o_core: Unable to install core handler.\nI2O stack not loaded!");
+ "i2o: Unable to install core handler.\nI2O stack not loaded!");
return 0;
}
core_context = i2o_core_handler.context;
-
/*
* Attach core to I2O PCI transport (and others as they are developed)
*/
#ifdef CONFIG_I2O_PCI_MODULE
if(i2o_pci_core_attach(&i2o_core_functions) < 0)
- printk(KERN_INFO "No PCI I2O controllers found\n");
+ printk(KERN_INFO "i2o: No PCI I2O controllers found\n");
#endif
if(i2o_num_controllers)
/*
* linux/drivers/i2o/i2o_lan.c
*
- * I2O LAN CLASS OSM Prototyping, November 8th 1999
+ * I2O LAN CLASS OSM December 2nd 1999
*
* (C) Copyright 1999 University of Helsinki,
* Department of Computer Science
* Tested: in FDDI environment (using SysKonnect's DDM)
* in Ethernet environment (using Intel 82558 DDM proto)
*
- * TODO: batch mode sends
- * error checking / timeouts
+ * TODO: check error checking / timeouts
* code / test for other LAN classes
*/
#include <linux/i2o.h>
#include "i2o_lan.h"
-#define DRIVERDEBUG
+//#define DRIVERDEBUG
#ifdef DRIVERDEBUG
#define dprintk(s, args...) printk(s, ## args)
#else
struct fddi_statistics stats; /* see also struct net_device_stats */
unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
u32 bucket_count; /* nbr of buckets sent to DDM */
- u32 tx_count; /* nbr of outstanding TXes */
- u32 max_tx; /* DDM's Tx queue len */
+ u32 tx_count; /* packets in one TX message frame */
+ u32 tx_max; /* DDM's Tx queue len */
+ u32 tx_out; /* outstanding TXes */
+ u32 sgl_max; /* max SGLs in one message frame */
+ u32 m; /* IOP address of msg frame */
+
+ struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */
+ int i2o_fbl_tail;
spinlock_t lock;
};
static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
- struct i2o_message *m);
-static void i2o_lan_event_reply(struct net_device *dev, u32 *msg);
-static int i2o_lan_receive_post(struct net_device *dev, u32 count);
+ struct i2o_message *m);
+static void i2o_lan_event_reply(struct net_device *dev, u32 *msg);
+static int i2o_lan_receive_post(struct net_device *dev);
static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg);
static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg);
0, // context
I2O_CLASS_LAN
};
-static int lan_context;
+static int lan_context;
+static struct tq_struct i2o_post_buckets_task = {
+ 0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0
+};
static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
struct i2o_message *m)
i2o_report_status(KERN_INFO, dev->name, msg);
switch (msg[1] >> 24) {
- case LAN_RECEIVE_POST:
+ case LAN_RECEIVE_POST:
{
if (dev->start) {
- if(!(msg[4]>>24)) {
+ if (!(msg[4]>>24)) {
i2o_lan_receive_post_reply(dev,msg);
break;
}
printk( KERN_WARNING "i2olan: Device %s rejected bucket post.\n", dev->name);
}
- // Getting unused buckets back
+ // Shutting down, we are getting unused buckets back
i2o_lan_release_buckets(dev,msg);
break;
}
case LAN_PACKET_SEND:
- case LAN_SDU_SEND:
+ case LAN_SDU_SEND:
{
- struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
- u8 trl_count = msg[3] & 0x000000FF;
-
- while (trl_count) {
- // The HDM has handled the outgoing packet
+ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+ u8 trl_count = msg[3] & 0x000000FF;
+
+ while (trl_count) {
+ // The HDM has handled the outgoing packet
dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]);
- printk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
+ dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
dev->name,trl_count);
- priv->tx_count--;
+ priv->tx_out--;
trl_count--;
}
-
+
if (dev->tbusy) {
clear_bit(0,(void*)&dev->tbusy);
mark_bh(NET_BH); /* inform upper layers */
break;
case I2O_EVT_IND_DEVICE_RESET:
printk("Device reset.\n");
- break;
+ break;
case I2O_EVT_IND_EVT_MASK_MODIFIED:
printk("Event mask modified, 0x%08X.\n",
evt->evt_data[0]);
/* else evt->function == I2O_CMD_UTIL_EVT_ACK) */
/* Do we need to do something here too? */
-}
-
+}
-void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
+static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
{
- struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
- u8 trl_count = (u8)(msg[3] & 0x000000FF);
+ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+ u8 trl_count = (u8)(msg[3] & 0x000000FF);
u32 *pskb = &msg[6];
- while (trl_count) {
+ while (trl_count--) {
dprintk("%s: Releasing unused sk_buff %p.\n",dev->name,
(struct sk_buff*)(*pskb));
dev_kfree_skb((struct sk_buff*)(*pskb));
pskb++;
priv->bucket_count--;
- trl_count--;
}
}
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6];
struct i2o_packet_info *packet;
-
- u8 trl_count = msg[3] & 0x000000FF;
- struct sk_buff *skb, *newskb;
+ u8 trl_count = msg[3] & 0x000000FF;
+ struct sk_buff *skb, *old_skb;
-#if 0
- dprintk(KERN_INFO "TrlFlags = 0x%02X, TrlElementSize = %d, TrlCount = %d\n"
- "msgsize = %d, buckets_remaining = %d\n",
- msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]);
-#endif
while (trl_count--) {
- skb = (struct sk_buff *)(bucket->context);
+ skb = (struct sk_buff *)bucket->context;
packet = (struct i2o_packet_info *)bucket->packet_info;
priv->bucket_count--;
-#if 0
- dprintk(KERN_INFO "Buckets_remaining = %d, bucket_count = %d, trl_count = %d\n",
- msg[5], priv->bucket_count, trl_count);
-
- dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
- packet->flags, packet->offset, packet->status, packet->len);
-#endif
if (packet->len < rx_copybreak) {
- newskb = (struct sk_buff *)
- dev_alloc_skb(packet->len+2);
- if (newskb) {
- skb_reserve(newskb,2);
- memcpy(skb_put(newskb,packet->len), skb->data, packet->len);
- newskb->dev = dev;
- newskb->protocol = priv->type_trans(newskb, dev);
-
- netif_rx(newskb);
- dev_kfree_skb(skb); // FIXME: reuse this skb?
- }
- else {
+ old_skb = skb;
+ skb = (struct sk_buff *)dev_alloc_skb(packet->len+2);
+ if (skb == NULL) {
printk("%s: Can't allocate skb.\n", dev->name);
return -ENOMEM;
- }
- } else {
- skb_put(skb,packet->len);
- skb->dev = dev;
- skb->protocol = priv->type_trans(skb, dev);
+ }
+ skb_reserve(skb,2);
+ memcpy(skb_put(skb,packet->len), old_skb->data, packet->len);
+
+ if (priv->i2o_fbl_tail < I2O_BUCKET_COUNT)
+ priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb;
+ else
+ dev_kfree_skb(old_skb);
+ } else
+ skb_put(skb,packet->len);
+
+ skb->dev = dev;
+ skb->protocol = priv->type_trans(skb, dev);
+ netif_rx(skb);
- netif_rx(skb);
- }
dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered "
"to upper level.\n",dev->name,packet->len);
if ((msg[4] & 0x000000FF) == I2O_LAN_DSC_BUCKET_OVERRUN)
printk(KERN_INFO "%s: DDM out of buckets (count = %d)!\n",
dev->name, msg[5]);
-
- if (priv->bucket_count <= bucketpost - bucketthresh)
- i2o_lan_receive_post(dev, bucketpost - priv->bucket_count);
+ if (priv->bucket_count <= bucketpost - bucketthresh) {
+// i2o_lan_receive_post(dev);
+ i2o_post_buckets_task.data = (void *)dev;
+ queue_task(&i2o_post_buckets_task, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
return 0;
}
+
/*
* i2o_lan_receive_post(): Post buckets to receive packets.
*/
-static int i2o_lan_receive_post(struct net_device *dev, u32 count)
-{
- struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+static int i2o_lan_receive_post(struct net_device *dev)
+{
+ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
struct i2o_device *i2o_dev = priv->i2o_dev;
struct i2o_controller *iop = i2o_dev->controller;
struct sk_buff *skb;
- u32 m; u32 *msg;
-
- u32 bucket_len = (dev->mtu + dev->hard_header_len);
- u32 bucket_count;
- int n_elems = (iop->inbound_size - 16 ) / 12; /* msg header + SGLs */
- u32 total = 0;
- int i;
-
- while (total < count) {
- m = I2O_POST_READ32(iop);
- if (m == 0xFFFFFFFF)
- return -ETIMEDOUT;
- msg = (u32 *)(iop->mem_offset + m);
- bucket_count = (total + n_elems < count)
- ? n_elems
- : count - total;
-
- msg[0] = I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4;
- msg[1] = LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
- msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
- msg[3] = bucket_count; // BucketCount
-
- for (i = 0; i < bucket_count; i++) {
- skb = dev_alloc_skb(bucket_len + 2);
- if (skb == NULL)
- return -ENOMEM;
- skb_reserve(skb, 2);
-
- priv->bucket_count++;
-
- msg[4 + 3*i] = 0x51000000 | bucket_len;
- msg[5 + 3*i] = (u32)skb;
- msg[6 + 3*i] = virt_to_bus(skb->data);
- }
- msg[4 + 3*i - 3] |= 0x80000000; // set LE flag
- i2o_post_message(iop,m);
-
- dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n",
- dev->name, bucket_count, bucket_len);
+ u32 m; u32 *msg;
+ u32 bucket_len = (dev->mtu + dev->hard_header_len);
+ u32 total = bucketpost - priv->bucket_count;
+ u32 bucket_count;
+ u32 *sgl_elem;
+
+ while (total) {
+ m = I2O_POST_READ32(iop);
+ if (m == 0xFFFFFFFF)
+ return -ETIMEDOUT;
+ msg = (u32 *)(iop->mem_offset + m);
+
+ bucket_count = (total >= priv->sgl_max) ? priv->sgl_max : total;
+ total -= bucket_count;
+ priv->bucket_count += bucket_count;
+
+ dprintk(KERN_INFO "%s: Sending %d buckets (size %d) to LAN HDM.\n",
+ dev->name, bucket_count, bucket_len);
+
+ __raw_writel(I2O_MESSAGE_SIZE(4 + 3 * bucket_count) | SGL_OFFSET_4, msg);
+ __raw_writel(LAN_RECEIVE_POST<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1);
+ __raw_writel(priv->unit << 16 | lan_context, msg+2);
+ __raw_writel(bucket_count, msg+3);
+ sgl_elem = &msg[4];
+
+ while (bucket_count--) {
+ if (priv->i2o_fbl_tail >= 0)
+ skb = priv->i2o_fbl[priv->i2o_fbl_tail--];
+ else {
+ skb = dev_alloc_skb(bucket_len + 2);
+ if (skb == NULL)
+ return -ENOMEM;
+ skb_reserve(skb, 2);
+ }
+ __raw_writel(0x51000000 | bucket_len, sgl_elem);
+ __raw_writel((u32)skb, sgl_elem+1);
+ __raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+ sgl_elem += 3;
+ }
- total += bucket_count;
- }
+ /* set LE flag and post buckets */
+ __raw_writel(__raw_readl(sgl_elem-3) | 0x80000000, (sgl_elem-3));
+ i2o_post_message(iop,m);
+ }
- return 0;
-}
+ return 0;
+}
/*
* i2o_lan_reset(): Reset the LAN adapter into the operational state and
struct i2o_controller *iop = i2o_dev->controller;
u32 msg[5];
- dprintk( "%s: LAN SUSPEND MESSAGE.\n", dev->name );
+ dprintk(KERN_INFO "%s: LAN SUSPEND MESSAGE.\n", dev->name);
msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
*/
static void i2o_set_batch_mode(struct net_device *dev)
{
-
-/*
- * NOTE: we have not been able to test batch mode
- * since HDMs we have, don't implement it
- */
-
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
struct i2o_device *i2o_dev = priv->i2o_dev;
struct i2o_controller *iop = i2o_dev->controller;
// enable batch mode, toggle automatically
val = 0x00000000;
-// val = 0x00000001; // turn off batch mode
if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0003, 0, &val, sizeof(val)) <0)
printk(KERN_WARNING "%s: Unable to enter I2O LAN batch mode.\n",
dev->name);
- else
+ else
dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name);
-// dprintk(KERN_INFO "%s: I2O LAN batch mode disabled.\n",dev->name);
/*
* When PacketOrphanlimit is same as the maximum packet length,
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
struct i2o_device *i2o_dev = priv->i2o_dev;
- struct i2o_controller *iop = i2o_dev->controller;
+ struct i2o_controller *iop = i2o_dev->controller;
u32 evt_mask = 0xFFC00007; // All generic events, all lan evenst
if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) {
printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
return -EAGAIN;
}
- dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n",
+ dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n",
dev->name, i2o_dev->lct_data->tid);
#if 0
if (i2o_event_register(iop, i2o_dev->lct_data->tid,
priv->unit << 16 | lan_context, evt_mask) < 0)
- printk(KERN_WARNING "%s: Unable to set the event mask.\n",
- dev->name);
+ printk(KERN_WARNING "%s: Unable to set the event mask.\n", dev->name);
#endif
i2o_lan_reset(dev);
+ priv->i2o_fbl = kmalloc(bucketpost * sizeof(struct sk_buff *),GFP_KERNEL);
+ if (priv->i2o_fbl == NULL)
+ return -ENOMEM;
+ priv->i2o_fbl_tail = -1;
+
dev->tbusy = 0;
dev->start = 1;
i2o_set_batch_mode(dev);
- i2o_lan_receive_post(dev, bucketpost);
+ i2o_lan_receive_post(dev);
MOD_INC_USE_COUNT;
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
struct i2o_device *i2o_dev = priv->i2o_dev;
-//#if 0
- struct i2o_controller *iop = i2o_dev->controller;
+#if 0
+ struct i2o_controller *iop = i2o_dev->controller;
if (i2o_event_register(iop, i2o_dev->lct_data->tid,
priv->unit << 16 | lan_context, 0) < 0)
- printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
+ printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
dev->name);
-//#endif
+#endif
dev->tbusy = 1;
dev->start = 0;
i2o_lan_suspend(dev);
printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
"(tid=%d).\n", dev->name, i2o_dev->lct_data->tid);
+ while (priv->i2o_fbl_tail >= 0)
+ dev_kfree_skb(priv->i2o_fbl[priv->i2o_fbl_tail--]);
+ kfree(priv->i2o_fbl);
+
MOD_DEC_USE_COUNT;
return 0;
}
#endif
+static void i2o_lan_batch_send(struct net_device *dev)
+{
+ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+ struct i2o_controller *iop = priv->i2o_dev->controller;
+
+ if (priv->tx_count != 0) {
+ i2o_post_message(iop, priv->m);
+ dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);
+ priv->tx_count = 0;
+ }
+}
+
+struct tq_struct i2o_post_send_task = {
+ 0, 0, (void (*)(void *))i2o_lan_batch_send, (void *) 0
+};
+
/*
* i2o_lan_packet_send(): Send a packet as is, including the MAC header.
*
struct i2o_device *i2o_dev = priv->i2o_dev;
struct i2o_controller *iop = i2o_dev->controller;
u32 m, *msg;
- u32 flags = 0;
+ u32 *sgl_elem;
/*
* Keep interrupt from changing dev->tbusy from underneath us
* (Do we really need to do this?)
*/
- spin_lock_irqsave(&priv->lock, flags);
- if(test_and_set_bit(0,(void*)&dev->tbusy) != 0) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return 1;
- }
+ if (test_and_set_bit(0,(void*)&dev->tbusy) != 0) {
+ return 1;
+ }
- m = I2O_POST_READ32(iop);
- if (m == 0xFFFFFFFF) {
- spin_unlock_irqrestore(&priv->lock, flags);
- dev_kfree_skb(skb);
- return -ETIMEDOUT;
- }
- msg = (u32 *)(iop->mem_offset + m);
+ priv->tx_count++;
+ priv->tx_out++;
-#if 0
- __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4,&msg[0]);
- __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, &msg[1]);
- __raw_writel(priv->unit << 16 | lan_context, &msg[2]); // InitiatorContext
- __raw_writel(1 << 4, &msg[3]); // TransmitControlWord
- __raw_writel(0xD5000000 | skb->len, &msg[4]); // MAC hdr included
- __raw_writel((u32)skb, &msg[5]); // TransactionContext
- __raw_writel(virt_to_bus(skb->data),&msg[6]);
-#endif
+ if (priv->tx_count == 1) {
+ dprintk("%s: New message frame\n", dev->name);
- msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4;
- msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
- msg[2] = priv->unit << 16 | lan_context; // IntiatorContext
- msg[3] = 1 << 4; // TransmitControlWord
+ m = I2O_POST_READ32(iop);
+ if (m == 0xFFFFFFFF) {
+ dev_kfree_skb(skb);
+ return -ETIMEDOUT;
+ }
+ msg = (u32 *)(iop->mem_offset + m);
+ priv->m = m;
+
+ __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4, msg);
+ __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, msg+1);
+ __raw_writel(priv->unit << 16 | lan_context, msg+2); // InitiatorContext
+ __raw_writel(1 << 4, msg+3); // TransmitControlWord
+ __raw_writel(0xD5000000 | skb->len, msg+4); // MAC hdr included
+ __raw_writel((u32)skb, msg+5); // TransactionContext
+ __raw_writel(virt_to_bus(skb->data), msg+6);
+
+ i2o_post_send_task.data = (void *)dev;
+ queue_task(&i2o_post_send_task, &tq_scheduler);
- // create a simple SGL, see fig. 3-26
- // D5 = 1101 0101 = LE eob 0 1 LA dir bc1 bc0
+ if (priv->tx_out < priv->tx_max)
+ clear_bit(0, (void *)&dev->tbusy);
- msg[4] = 0xD5000000 | skb->len; // MAC hdr included
- msg[5] = (u32)skb; // TransactionContext
- msg[6] = virt_to_bus(skb->data);
+ return 0;
+ }
+
+ /* Else add new SGL element to the previous message frame */
+
+ dprintk("%s: Adding packet %d to msg frame\n", dev->name, priv->tx_count);
- i2o_post_message(iop,m);
+ msg = (u32 *)(iop->mem_offset + priv->m);
+ sgl_elem = &msg[priv->tx_count * 3 + 1];
+
+ __raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
+ __raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
+ __raw_writel(0xD5000000 | skb->len, sgl_elem);
+ __raw_writel((u32)skb, sgl_elem+1);
+ __raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+
+ if (priv->tx_count == priv->sgl_max) { /* frame full, send now */
+// i2o_lan_batch_send(dev);
+ i2o_post_message(iop, priv->m);
+ dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);
+ priv->tx_count = 0;
+ }
- // Check to see if HDM queue is full..if so...stay busy
- if(++priv->tx_count < priv->max_tx)
+ if (priv->tx_out < priv->tx_max)
clear_bit(0, (void *)&dev->tbusy);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- dprintk(KERN_INFO "%s: Packet (%d bytes) sent to network.\n",
- dev->name, skb->len);
-
return 0;
}
+
static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
{
struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
u64 val64[16];
u64 supported_group[4] = { 0, 0, 0, 0 };
- if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64,
+ if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64,
sizeof(val64)) < 0)
printk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name);
else {
if (supported_stats != 0) {
if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0281, -1,
val64, sizeof(val64)) < 0)
-;
-// printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
+ printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
else {
dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name);
if (supported_stats & 0x1)
priv->stats.tx_heartbeat_errors = val64[2];
}
}
-
}
#ifdef CONFIG_TR
else {
struct tr_statistics *stats =
(struct tr_statistics *)&priv->stats;
-// dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
+ dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
stats->line_errors = val64[0];
stats->internal_errors = val64[7];
val64, sizeof(val64)) < 0)
printk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name);
else {
-// dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name);
+ dprintk("%s: LAN_FDDI_HISTORICAL_STATS queried.\n",dev->name);
priv->stats.smt_cf_state = val64[0];
memcpy(priv->stats.mac_upstream_nbr, &val64[1], FDDI_K_ALEN);
memcpy(priv->stats.mac_downstream_nbr, &val64[2], FDDI_K_ALEN);
if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0001, -1,
&mc_addr_group, sizeof(mc_addr_group)) < 0 ) {
- printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
+ printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
return;
}
struct net_device *dev = NULL;
struct i2o_lan_local *priv = NULL;
u8 hw_addr[8];
- u32 max_tx = 0;
+ u32 tx_max = 0;
unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
void (*unregister_dev)(struct net_device *dev);
priv->i2o_dev = i2o_dev;
priv->type_trans = type_trans;
priv->bucket_count = 0;
+ priv->sgl_max = (i2o_dev->controller->inbound_size - 16) / 12;
unit++;
i2o_landevs[unit] = dev;
memcpy(dev->dev_addr, hw_addr, 6);
if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
- 0x0007, 2, &max_tx, sizeof(max_tx)) < 0)
+ 0x0007, 2, &tx_max, sizeof(tx_max)) < 0)
{
printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
unit--;
kfree(dev);
return NULL;
}
- dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, max_tx);
- priv->max_tx = max_tx;
- priv->tx_count = 0;
-
- priv->lock = SPIN_LOCK_UNLOCKED;
+ dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max);
+ priv->tx_max = tx_max;
+ priv->tx_out = 0;
+ priv->tx_count = 0;
+ priv->lock = SPIN_LOCK_UNLOCKED;
dev->open = i2o_lan_open;
dev->stop = i2o_lan_close;
int i;
printk(KERN_INFO "Linux I2O LAN OSM (c) 1999 University of Helsinki.\n");
-
+
+ if (bucketpost > I2O_BUCKET_COUNT)
+ bucketpost = I2O_BUCKET_COUNT;
+ if (bucketthresh > bucketpost)
+ bucketthresh = bucketpost;
+
if (i2o_install_handler(&i2o_lan_handler) < 0) {
printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
return -EINVAL;
MODULE_AUTHOR("Univ of Helsinki, CS Department");
MODULE_DESCRIPTION("I2O Lan OSM");
-MODULE_PARM(bucketpost, "i"); // Number of buckets to post
+MODULE_PARM(bucketpost, "i"); // Total number of buckets to post
MODULE_PARM(bucketthresh, "i"); // Bucket post threshold
MODULE_PARM(rx_copybreak, "i");
static char irqrmap2[] = {-1,-1,4,0,1,2,-1,3,-1,4,5,6,7,-1,-1,-1};
static int eepro_grab_irq(struct net_device *dev)
{
- int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12 };
+ int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 };
int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
- Written 1994-1998 by Mika Kuoppala
+ Written 1994-1999 by Mika Kuoppala
- Copyright (C) 1994-1998 by Mika Kuoppala
+ Copyright (C) 1994-1999 by Mika Kuoppala
Based on skeleton.c and heavily on at1700.c by Donald Becker
This software may be used and distributed according to the terms
(Uses true 32 bit transfers rather than 16i compability mode)
Example Module usage:
- insmod eth16i.o ioaddr=0x2a0 mediatype=bnc
+ insmod eth16i.o io=0x2a0 mediatype=bnc
mediatype can be one of the following: bnc,tp,dix,auto,eprom
Now more shallow reset is made on
close.
+ 0.34 29.06-99 Fixed one bad #ifdef.
+ Changed ioaddr -> io for consistency
+
+ 0.35 01.07-99 transmit,-receive bytes were never
+ updated in stats.
+
Bugs:
In some cases the media interface autoprobing code doesn't find
the correct interface type. In this case you can
*/
static char *version =
- "eth16i.c: v0.33 10-09-98 Mika Kuoppala (miku@iki.fi)\n";
+ "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n";
#include <linux/module.h>
unsigned short tx_queue_len;
unsigned int tx_buf_size;
unsigned long open_time;
- unsigned long tx_buffered_packets;
+ unsigned long tx_buffered_packets;
+ unsigned long tx_buffered_bytes;
unsigned long col_16;
};
}
lp->tx_buffered_packets++;
+ lp->tx_buffered_bytes = length;
lp->tx_queue++;
lp->tx_queue_len += length + 2;
-
}
lp->tx_buf_busy = 0;
skb->protocol=eth_type_trans(skb, dev);
netif_rx(skb);
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len;
if( eth16i_debug > 5 ) {
int i;
if(status & TX_DONE) { /* The transmit has been done */
lp->stats.tx_packets = lp->tx_buffered_packets;
+ lp->stats.tx_bytes += lp->tx_buffered_bytes;
lp->col_16 = 0;
if(lp->tx_queue) { /* Is there still packets ? */
},
};
-static int ioaddr[MAX_ETH16I_CARDS] = { 0, };
+static int io[MAX_ETH16I_CARDS] = { 0, };
#if 0
static int irq[MAX_ETH16I_CARDS] = { 0, };
#endif
MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>");
MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver");
-MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
-MODULE_PARM_DESC(ioaddr, "eth16i io base address");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
+MODULE_PARM_DESC(io, "eth16i io base address");
#if 0
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i");
dev->name = namelist + (NAMELEN*this_dev);
dev->irq = 0; /* irq[this_dev]; */
- dev->base_addr = ioaddr[this_dev];
+ dev->base_addr = io[this_dev];
dev->init = eth16i_probe;
if(debug != -1)
dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]);
- if(ioaddr[this_dev] == 0)
+ if(io[this_dev] == 0)
{
if(this_dev != 0) break; /* Only autoprobe 1st one */
if(register_netdev(dev) != 0)
{
printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
- ioaddr[this_dev]);
+ io[this_dev]);
if(found != 0) return 0;
return -ENXIO;
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 3 13:49:59 1997
- * Modified at: Thu Dec 16 00:47:08 1999
+ * Modified at: Tue Dec 21 21:51:23 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c by Linus Torvalds
*
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return NULL;
}
- /* dev_alloc doesn't clear the struct */
- memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
self->netdev = dev;
/* May be overridden by piggyback drivers */
rtnl_lock();
unregister_netdevice(self->netdev);
rtnl_unlock();
- /* Must free the old-style 2.2.x device */
- kfree(self->netdev);
}
/* Release the IO-port that this driver is using */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
- * Modified at: Thu Dec 16 09:37:47 1999
+ * Modified at: Tue Dec 21 21:50:59 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
- /* dev_alloc doesn't clear the struct */
- memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
dev->priv = (void *) self;
self->netdev = dev;
rtnl_lock();
unregister_netdevice(self->netdev);
rtnl_unlock();
- /* Must free the old-style 2.2.x device */
- kfree(self->netdev);
}
/* We are not using any dongle anymore! */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Nov 7 21:43:15 1998
- * Modified at: Thu Dec 16 00:54:27 1999
+ * Modified at: Tue Dec 21 21:51:54 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
static void pc87108_dma_write(struct pc87108 *self, int iobase);
static void pc87108_change_speed(struct pc87108 *self, __u32 baud);
static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void pc87108_wait_until_sent(struct pc87108 *self);
static int pc87108_is_receiving(struct pc87108 *self);
static int pc87108_read_dongle_id (int iobase);
static void pc87108_init_dongle_interface (int iobase, int dongle_id);
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
- /* dev_alloc doesn't clear the struct, so lets do a little hack */
- memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
dev->priv = (void *) self;
self->netdev = dev;
rtnl_lock();
unregister_netdevice(self->netdev);
rtnl_unlock();
- /* Must free the old-style 2.2.x device */
- kfree(self->netdev);
}
/* Release the PORT that this driver is using */
__u8 bank;
int iobase;
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed);
ASSERT(self != NULL, return;);
pc87108_dma_write(self, iobase);
}
} else {
+ self->tx_buff.data = self->tx_buff.head;
+
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
-
- self->tx_buff.data = self->tx_buff.head;
-
+
/* Add interrupt on tx low level (will fire immediately) */
switch_bank(iobase, BANK0);
outb(IER_TXLDL_IE, iobase+IER);
switch_bank(iobase, BANK0);
outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+ self->rx_buff.data = self->rx_buff.head;
+
setup_dma(self->io.dma, self->rx_buff.data,
self->rx_buff.truesize, DMA_MODE_READ);
/* driver->media_busy = FALSE; */
self->io.direction = IO_RECV;
- self->rx_buff.data = self->rx_buff.head;
/* Reset Rx FIFO. This will also flush the ST_FIFO */
outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
/* Receive all characters in Rx FIFO */
do {
byte = inb(iobase+RXD);
- async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
- byte);
-
+ async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, byte);
} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */
}
}
/* Check if transmission has completed */
if (eir & EIR_TXEMP_EV) {
-
+ /* Check if we need to change the speed? */
+ if (self->new_speed) {
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), Changing speed!\n");
+ pc87108_change_speed(self, self->new_speed);
+ self->new_speed = 0;
+ }
+
/* Turn around and get ready to receive some data */
self->io.direction = IO_RECV;
new_ier |= IER_RXHDL_IE;
dev->interrupt = 0;
}
-/*
- * Function pc87108_wait_until_sent (self)
- *
- * This function should put the current thread to sleep until all data
- * have been sent, so it is safe to f.eks. change the speed.
- */
-static void pc87108_wait_until_sent(struct pc87108 *self)
-{
- /* Just delay 60 ms */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(MSECS_TO_JIFFIES(60));
-}
-
/*
* Function pc87108_is_receiving (self)
*
rtnl_lock();
unregister_netdevice(self->netdev);
rtnl_unlock();
- /* Must free the old-style 2.2.x device */
- kfree(self->netdev);
}
kfree (self->taskfilebuf);
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
- /* dev_alloc doesn't clear the struct, so lets do a little hack */
- memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
dev->priv = (void *) self;
self->netdev = dev;
* Status: Experimental.
* Author: Paul VanderSpek
* Created at: Wed Nov 4 11:46:16 1998
- * Modified at: Thu Dec 16 00:52:53 1999
+ * Modified at: Tue Dec 21 21:53:09 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
- /* dev_alloc doesn't clear the struct, so lets do a little hack */
- memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
dev->priv = (void *) self;
self->netdev = dev;
rtnl_lock();
unregister_netdevice(self->netdev);
rtnl_unlock();
- /* Must free the old-style 2.2.x device */
- kfree(self->netdev);
}
/* Release the PORT that this driver is using */
}
}
/* Check if transmission has completed */
- if (isr & ISR_TXEMP_I) {
-
+ if (isr & ISR_TXEMP_I) {
+ /* Check if we need to change the speed? */
+ if (self->new_speed) {
+ IRDA_DEBUG(2, __FUNCTION__
+ "(), Changing speed!\n");
+ w83977af_change_speed(self, self->new_speed);
+ self->new_speed = 0;
+ }
+
/* Turn around and get ready to receive some data */
self->io.direction = IO_RECV;
new_icr |= ICR_ERBRI;
/* update Multicast Hash Table in Receive Filter */
for (i = 0; i < 8; i++) {
-+ /* why plus 0x04 ??, That makes the correct value for hash table. */
+ /* why plus 0x04 ??, That makes the correct value for hash table. */
outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
outl(mc_filter[i], ioaddr + rfdr);
}
static int yenta_get_status(pci_socket_t *socket, unsigned int *value)
{
u32 state = cb_readl(socket, CB_SOCKET_STATE);
- u8 status;
unsigned int val;
/* Convert from Yenta status to old-style status */
val |= (state & CB_XVCARD) ? SS_XVCARD : 0;
/* Get the old compatibility status too.. */
- status = exca_readb(socket, I365_STATUS);
- val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
- val |= (status & I365_CS_READY) ? SS_READY : 0;
- val |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+ if (!(state & CB_CBCARD)) {
+ u8 status = exca_readb(socket, I365_STATUS);
+ val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+ val |= (status & I365_CS_READY) ? SS_READY : 0;
+ val |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+ }
printk("yenta_get_status(%p)= %x\n", socket, val);
bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0;
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
+ exca_writeb(socket, I365_GBLCTL, 0x00);
+ exca_writeb(socket, I365_GENCTL, 0x00);
+
/* Set the IO interrupt and socket state */
reg = state->io_irq;
reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
static void yenta_get_socket_capabilities(pci_socket_t *socket)
{
- socket->cap.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
+ /* MAGIC NUMBERS! Fixme */
+ config_writeb(socket, PCI_LATENCY_TIMER, 168);
+ config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176);
+
+ socket->cap.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
socket->cap.irq_mask = yenta_probe_irq(socket);
if (socket->cb_irq && socket->cb_irq < 16)
socket->cap.irq_mask |= 1 << socket->cb_irq;
MOD_LIST_NAME := SCSI_MODULES
SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
-CFLAGS_aha152x.o = -DDEBUG_AHA152X -DAUTOCONF
+CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
--- /dev/null
+$Id: README.aha152x,v 1.2 1999/12/25 15:32:30 fischer Exp fischer $
+Adaptec AHA-1520/1522 SCSI driver for Linux (aha152x)
+
+Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
+TC1550 patches by Luuk van Dijk (ldz@xs4all.nl)
+
+
+In Revision 2 the driver was modified a lot (especially the
+bottom-half handler complete()).
+
+The driver is much cleaner now, has support for the new
+error handling code in 2.3, produced less cpu load (much
+less polling loops), has slightly higher throughput (at
+least on my ancient test box; a i486/33Mhz/20MB).
+
+
+CONFIGURATION ARGUMENTS:
+
+IOPORT base io address (0x340/0x140)
+IRQ interrupt level (9-12; default 11)
+SCSI_ID scsi id of controller (0-7; default 7)
+RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on])
+PARITY enable parity checking (0/1; default 1 [on])
+SYNCHRONOUS enable synchronous transfers (0/1; default 1 [on])
+DELAY: bus reset delay (default 100)
+EXT_TRANS: enable extended translation (0/1: default 0 [off])
+ (see NOTES)
+
+COMPILE TIME CONFIGURATION (go into AHA152X in drivers/scsi/Makefile):
+
+-DAUTOCONF
+ use configuration the controller reports (AHA-152x only)
+
+-DSKIP_BIOSTEST
+ Don't test for BIOS signature (AHA-1510 or disabled BIOS)
+
+-DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
+ override for the first controller
+
+-DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
+ override for the second controller
+
+-DAHA152X_DEBUG
+ enable debugging output
+
+-DAHA152X_STAT
+ enable some statistics
+
+
+LILO COMMAND LINE OPTIONS:
+
+aha152x=<IOPORT>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY> [,<EXT_TRANS]]]]]]]
+
+ The normal configuration can be overridden by specifying a command line.
+ When you do this, the BIOS test is skipped. Entered values have to be
+ valid (known). Don't use values that aren't supported under normal
+ operation. If you think that you need other values: contact me.
+ For two controllers use the aha152x statement twice.
+
+
+SYMBOLS FOR MODULE CONFIGURATION:
+
+Choose from 2 alternatives:
+
+1. specify everything (old)
+
+aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
+ configuration override for first controller
+
+
+aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
+ configuration override for second controller
+
+2. specify only what you need to (irq or io is required; new)
+
+io=IOPORT0[,IOPORT1]
+ IOPORT for first and second controller
+
+irq=IRQ0[,IRQ1]
+ IRQ for first and second controller
+
+scsiid=SCSIID0[,SCSIID1]
+ SCSIID for first and second controller
+
+reconnect=RECONNECT0[,RECONNECT1]
+ allow targets to disconnect for first and second controller
+
+parity=PAR0[PAR1]
+ use parity for first and second controller
+
+sync=SYNCHRONOUS0[,SYNCHRONOUS1]
+ enable synchronous transfers for first and second controller
+
+delay=DELAY0[,DELAY1]
+ reset DELAY for first and second controller
+
+exttrans=EXTTRANS0[,EXTTRANS1]
+ enable extended translation for first and second controller
+
+
+If you use both alternatives the first will be taken.
+
+
+NOTES ON EXT_TRANS:
+
+SCSI uses block numbers to address blocks/sectors on a device.
+The BIOS uses a cylinder/head/sector addressing scheme (C/H/S)
+scheme instead. DOS expects a BIOS or driver that understands this
+C/H/S addressing.
+
+The number of cylinders/heads/sectors is called geometry and is required
+as base for requests in C/H/S addressing. SCSI only knows about the
+total capacity of disks in blocks (sectors).
+
+Therefore the SCSI BIOS/DOS driver has to calculate a logical/virtual
+geometry just to be able to support that addressing scheme. The geometry
+returned by the SCSI BIOS is a pure calculation and has nothing to
+do with the real/physical geometry of the disk (which is usually
+irrelevant anyway).
+
+Basically this has no impact at all on Linux, because it also uses block
+instead of C/H/S addressing. Unfortunately C/H/S addressing is also used
+in the partition table and therefore every operating system has to know
+the right geometry to be able to interpret it.
+
+Moreover there are certain limitations to the C/H/S addressing scheme,
+namely the address space is limited to upto 255 heads, upto 63 sectors
+and a maximum of 1023 cylinders.
+
+The AHA-1522 BIOS calculates the geometry by fixing the number of heads
+to 64, the number of sectors to 32 and by calculating the number of
+cylinders by dividing the capacity reported by the disk by 64*32 (1 MB).
+This is considered to be the default translation.
+
+With respect to the limit of 1023 cylinders using C/H/S you can only
+address the first GB of your disk in the partition table. Therefore
+BIOSes of some newer controllers based on the AIC-6260/6360 support
+extended translation. This means that the BIOS uses 255 for heads,
+63 for sectors and then divides the capacity of the disk by 255*63
+(about 8 MB), as soon it sees a disk greater than 1 GB. That results
+in a maximum of about 8 GB addressable diskspace in the partition table
+(but there are already bigger disks out there today).
+
+To make it even more complicated the translation mode might/might
+not be configurable in certain BIOS setups.
+
+This driver does some more or less failsafe guessing to get the
+geometry right in most cases:
+
+- for disks<1GB: use default translation (C/32/64)
+
+- for disks>1GB:
+ - take current geometry from the partition table
+ (using scsicam_bios_param and accept only `valid' geometries,
+ ie. either (C/32/64) or (C/63/255)). This can be extended translation
+ even if it's not enabled in the driver.
+
+ - if that fails, take extended translation if enabled by override,
+ kernel or module parameter, otherwise take default translation and
+ ask the user for verification. This might on not yet partitioned
+ disks.
+
+
+REFERENCES USED:
+
+ "AIC-6260 SCSI Chip Specification", Adaptec Corporation.
+
+ "SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h
+
+ "Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu)
+
+ "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
+
+ "Adaptec 1520/1522 User's Guide", Adaptec Corporation.
+
+ Michael K. Johnson (johnsonm@sunsite.unc.edu)
+
+ Drew Eckhardt (drew@cs.colorado.edu)
+
+ Eric Youngdale (eric@andante.org)
+
+ special thanks to Eric Youngdale for the free(!) supplying the
+ documentation on the chip.
-/* $Id: advansys.c,v 1.68 1999/11/19 01:57:47 bobf Exp bobf $ */
-#define ASC_VERSION "3.2L" /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.69 1999/11/29 18:37:53 bobf Exp bobf $ */
+#define ASC_VERSION "3.2M" /* AdvanSys Driver Version */
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
at line 7475. The reqp->sgblkp pointer must be initialized
to NULL in adv_get_sglist().
+ 3.2M (11/29/99):
+ 1. Really fix bug in adv_get_sglist().
+ 2. Incorporate v2.3.29 changes into driver.
+
J. Known Problems/Fix List (XXX)
1. Need to add memory mapping workaround. Test the memory mapping.
/* BIOS start address. */
if (ASC_NARROW_BOARD(boardp)) {
- shp->base = ((ulong) AscGetChipBiosAddress(
- asc_dvc_varp->iop_base,
- asc_dvc_varp->bus_type));
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
+ shp->base =
+#else /* version >= v2.3.29 */
+ shp->base = (char *)
+#endif /* version < v2.3.29 */
+ ((ulong) AscGetChipBiosAddress(
+ asc_dvc_varp->iop_base,
+ asc_dvc_varp->bus_type));
} else {
/*
* Fill-in BIOS board variables. The Wide BIOS saves
* Convert x86 realmode code segment to a linear
* address by shifting left 4.
*/
- shp->base = (boardp->bios_codeseg << 4);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,3,29)
+ shp->base =
+#else /* version >= v2.3.29 */
+ shp->base = (char *)
+#endif /* version < v2.3.29 */
+ ((ulong) boardp->bios_codeseg << 4);
} else {
shp->base = 0;
}
slp = (struct scatterlist *) scp->request_buffer;
sg_elem_cnt = scp->use_sg;
prev_sg_block = NULL;
- reqp->sgblkp == NULL;
+ reqp->sgblkp = NULL;
do
{
-/* $Id: advansys.h,v 1.17 1998/01/08 21:23:49 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.18 1999/11/29 21:47:16 bobf Exp bobf $ */
/*
* advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
int advansys_command(Scsi_Cmnd *);
int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int advansys_abort(Scsi_Cmnd *);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
+int advansys_reset(Scsi_Cmnd *);
+#else /* version >= v1.3.89 */
int advansys_reset(Scsi_Cmnd *, unsigned int);
+#endif /* version >= v1.3.89 */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+int advansys_biosparam(Disk *, int, int[]);
+#else /* version >= v1.3.0 */
int advansys_biosparam(Disk *, kdev_t, int[]);
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
+extern struct proc_dir_entry proc_scsi_advansys;
+#endif /* version < v2.3.28 */
int advansys_proc_info(char *, char **, off_t, int, int, int);
+#endif /* version >= v1.3.0 */
/* init/main.c setup function */
void advansys_setup(char *, int *);
/*
* AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
*/
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+#define ADVANSYS { \
+ NULL, /* struct SHT *next */ \
+ NULL, /* int *usage_count */ \
+ "advansys", /* char *name */ \
+ advansys_detect, /* int (*detect)(struct SHT *) */ \
+ advansys_release, /* int (*release)(struct Scsi_Host *) */ \
+ advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \
+ advansys_command, /* int (*command)(Scsi_Cmnd *) */ \
+ advansys_queuecommand, \
+ /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
+ advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \
+ advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \
+ NULL, /* int (*slave_attach)(int, int) */ \
+ advansys_biosparam, /* int (* bios_param)(Disk *, int, int []) */ \
+ /* \
+ * The following fields are set per adapter in advansys_detect(). \
+ */ \
+ 0, /* int can_queue */ \
+ 0, /* int this_id */ \
+ 0, /* short unsigned int sg_tablesize */ \
+ 0, /* short cmd_per_lun */ \
+ 0, /* unsigned char present */ \
+ /* \
+ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+ * must be set. The flag will be cleared in advansys_detect for non-ISA \
+ * adapters. Refer to the comment in scsi_module.c for more information. \
+ */ \
+ 1, /* unsigned unchecked_isa_dma:1 */ \
+ /* \
+ * All adapters controlled by this driver are capable of large \
+ * scatter-gather lists. According to the mid-level SCSI documentation \
+ * this obviates any performance gain provided by setting \
+ * 'use_clustering'. But empirically while CPU utilization is increased \
+ * by enabling clustering, I/O throughput increases as well. \
+ */ \
+ ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \
+}
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
+#define ADVANSYS { \
+ NULL, /* struct SHT *next */ \
+ NULL, \
+ /* version < v2.1.23 long *usage_count */ \
+ /* version >= v2.1.23 struct module * */ \
+ &proc_scsi_advansys, /* struct proc_dir_entry *proc_dir */ \
+ advansys_proc_info, \
+ /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \
+ "advansys", /* const char *name */ \
+ advansys_detect, /* int (*detect)(struct SHT *) */ \
+ advansys_release, /* int (*release)(struct Scsi_Host *) */ \
+ advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \
+ advansys_command, /* int (*command)(Scsi_Cmnd *) */ \
+ advansys_queuecommand, \
+ /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
+ advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \
+ advansys_reset, \
+ /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \
+ /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \
+ NULL, /* int (*slave_attach)(int, int) */ \
+ advansys_biosparam, /* int (* bios_param)(Disk *, kdev_t, int []) */ \
+ /* \
+ * The following fields are set per adapter in advansys_detect(). \
+ */ \
+ 0, /* int can_queue */ \
+ 0, /* int this_id */ \
+ 0, /* short unsigned int sg_tablesize */ \
+ 0, /* short cmd_per_lun */ \
+ 0, /* unsigned char present */ \
+ /* \
+ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+ * must be set. The flag will be cleared in advansys_detect for non-ISA \
+ * adapters. Refer to the comment in scsi_module.c for more information. \
+ */ \
+ 1, /* unsigned unchecked_isa_dma:1 */ \
+ /* \
+ * All adapters controlled by this driver are capable of large \
+ * scatter-gather lists. According to the mid-level SCSI documentation \
+ * this obviates any performance gain provided by setting \
+ * 'use_clustering'. But empirically while CPU utilization is increased \
+ * by enabling clustering, I/O throughput increases as well. \
+ */ \
+ ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \
+}
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
+#define ADVANSYS { \
+ proc_dir: &proc_scsi_advansys, \
+ proc_info: advansys_proc_info, \
+ name: "advansys", \
+ detect: advansys_detect, \
+ release: advansys_release, \
+ info: advansys_info, \
+ command: advansys_command, \
+ queuecommand: advansys_queuecommand, \
+ abort: advansys_abort, \
+ reset: advansys_reset, \
+ bios_param: advansys_biosparam, \
+ /* \
+ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+ * must be set. The flag will be cleared in advansys_detect for non-ISA \
+ * adapters. Refer to the comment in scsi_module.c for more information. \
+ */ \
+ unchecked_isa_dma: 1, \
+ /* \
+ * All adapters controlled by this driver are capable of large \
+ * scatter-gather lists. According to the mid-level SCSI documentation \
+ * this obviates any performance gain provided by setting \
+ * 'use_clustering'. But empirically while CPU utilization is increased \
+ * by enabling clustering, I/O throughput increases as well. \
+ */ \
+ use_clustering: ENABLE_CLUSTERING, \
+}
+#else /* version >= v2.3.28 */
#define ADVANSYS { \
proc_name: "advansys", \
proc_info: advansys_proc_info, \
queuecommand: advansys_queuecommand, \
abort: advansys_abort, \
reset: advansys_reset, \
- bios_param: advansys_biosparam, \
+ bios_param: advansys_biosparam, \
/* \
* Because the driver may control an ISA adapter 'unchecked_isa_dma' \
* must be set. The flag will be cleared in advansys_detect for non-ISA \
*/ \
use_clustering: ENABLE_CLUSTERING, \
}
+#endif /* version >= v2.3.28 */
#endif /* _ADVANSYS_H */
/* aha152x.c -- Adaptec AHA-152x driver
- * Author: Jürgen E. Fischer, fischer@et-inf.fho-emden.de
- * Copyright 1993, 1994, 1995, 1996 Jürgen E. Fischer
- *
- *
- * This driver is based on
- * fdomain.c -- Future Domain TMC-16x0 driver
- * which is
- * Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
- *
+ * Author: Jürgen E. Fischer, fischer@norbit.de
+ * Copyright 1993-1999 Jürgen E. Fischer
*
* 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
* General Public License for more details.
*
*
- * $Id: aha152x.c,v 1.18 1996/09/07 20:10:40 fischer Exp $
+ * $Id: aha152x.c,v 2.0 1999/12/25 15:07:32 fischer Exp fischer $
*
* $Log: aha152x.c,v $
+ * Revision 2.0 1999/12/25 15:07:32 fischer
+ * - interrupt routine completly reworked
+ * - basic support for new eh code
+ *
+ * Revision 1.21 1999/11/10 23:46:36 fischer
+ * - default to synchronous operation
+ * - synchronous negotiation fixed
+ * - added timeout to loops
+ * - debugging output can be controlled through procfs
+ *
+ * Revision 1.20 1999/11/07 18:37:31 fischer
+ * - synchronous operation works
+ * - resid support for sg driver
+ *
+ * Revision 1.19 1999/11/02 22:39:59 fischer
+ * - moved leading comments to README.aha152x
+ * - new additional module parameters
+ * - updates for 2.3
+ * - support for the Tripace TC1550 controller
+ * - interrupt handling changed
+ *
* Revision 1.18 1996/09/07 20:10:40 fischer
* - fixed can_queue handling (multiple outstanding commands working again)
*
*
*
**************************************************************************
-
-
-
- DESCRIPTION:
-
- This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI
- host adapters.
-
-
- CONFIGURATION ARGUMENTS:
-
- IOPORT base io address (0x340/0x140)
- IRQ interrupt level (9-12; default 11)
- SCSI_ID scsi id of controller (0-7; default 7)
- RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on])
- PARITY enable parity checking (0/1; default 1 [on])
- SYNCHRONOUS enable synchronous transfers (0/1; default 0 [off])
- (NOT WORKING YET)
- DELAY: bus reset delay (default 100)
- EXT_TRANS: enable extended translation (0/1: default 0 [off])
- (see NOTES below)
-
- COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile):
-
- -DAUTOCONF
- use configuration the controller reports (AHA-152x only)
-
- -DSKIP_BIOSTEST
- Don't test for BIOS signature (AHA-1510 or disabled BIOS)
-
- -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
- override for the first controller
-
- -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }"
- override for the second controller
-
-
- LILO COMMAND LINE OPTIONS:
-
- aha152x=<IOPORT>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY> [,<EXT_TRANS]]]]]]]
-
- The normal configuration can be overridden by specifying a command line.
- When you do this, the BIOS test is skipped. Entered values have to be
- valid (known). Don't use values that aren't supported under normal
- operation. If you think that you need other values: contact me.
- For two controllers use the aha152x statement twice.
-
-
- SYMBOLS FOR MODULE CONFIGURATION:
-
- aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
- configuration override of first controller
-
-
- aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS
- configuration override of second controller
-
-
- NOTES ON EXT_TRANS:
-
- SCSI uses block numbers to address blocks/sectors on a device.
- The BIOS uses a cylinder/head/sector addressing scheme (C/H/S)
- scheme instead. DOS expects a BIOS or driver that understands this
- C/H/S addressing.
-
- The number of cylinders/heads/sectors is called geometry and is required
- as base for requests in C/H/S addressing. SCSI only knows about the
- total capacity of disks in blocks (sectors).
-
- Therefore the SCSI BIOS/DOS driver has to calculate a logical/virtual
- geometry just to be able to support that addressing scheme. The geometry
- returned by the SCSI BIOS is a pure calculation and has nothing to
- do with the real/physical geometry of the disk (which is usually
- irrelevant anyway).
-
- Basically this has no impact at all on Linux, because it also uses block
- instead of C/H/S addressing. Unfortunately C/H/S addressing is also used
- in the partition table and therefore every operating system has to know
- the right geometry to be able to interpret it.
-
- Moreover there are certain limitations to the C/H/S addressing scheme,
- namely the address space is limited to upto 255 heads, upto 63 sectors
- and a maximum of 1023 cylinders.
-
- The AHA-1522 BIOS calculates the geometry by fixing the number of heads
- to 64, the number of sectors to 32 and by calculating the number of
- cylinders by dividing the capacity reported by the disk by 64*32 (1 MB).
- This is considered to be the default translation.
-
- With respect to the limit of 1023 cylinders using C/H/S you can only
- address the first GB of your disk in the partition table. Therefore
- BIOSes of some newer controllers based on the AIC-6260/6360 support
- extended translation. This means that the BIOS uses 255 for heads,
- 63 for sectors and then divides the capacity of the disk by 255*63
- (about 8 MB), as soon it sees a disk greater than 1 GB. That results
- in a maximum of about 8 GB addressable diskspace in the partition table
- (but there are already bigger disks out there today).
-
- To make it even more complicated the translation mode might/might
- not be configurable in certain BIOS setups.
-
- This driver does some more or less failsafe guessing to get the
- geometry right in most cases:
-
- - for disks<1GB: use default translation (C/32/64)
- - for disks>1GB:
- - take current geometry from the partition table
- (using scsicam_bios_param and accept only `valid' geometries,
- ie. either (C/32/64) or (C/63/255)). This can be extended
- translation even if it's not enabled in the driver.
- - if that fails, take extended translation if enabled by override,
- kernel or module parameter, otherwise take default translation and
- ask the user for verification. This might on not yet partitioned
- disks or
-
-
- REFERENCES USED:
-
- "AIC-6260 SCSI Chip Specification", Adaptec Corporation.
-
- "SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h
-
- "Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu)
-
- "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
-
- "Adaptec 1520/1522 User's Guide", Adaptec Corporation.
-
- Michael K. Johnson (johnsonm@sunsite.unc.edu)
-
- Drew Eckhardt (drew@cs.colorado.edu)
-
- Eric Youngdale (ericy@cais.com)
-
- special thanks to Eric Youngdale for the free(!) supplying the
- documentation on the chip.
+
+ see README.aha152x for configuration details
**************************************************************************/
-#ifdef PCMCIA
+#if defined(PCMCIA)
#define MODULE
#endif
#include <linux/module.h>
-#ifdef PCMCIA
+#if defined(PCMCIA)
#undef MODULE
#endif
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/ioport.h>
+#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <asm/semaphore.h>
+#include <linux/spinlock.h>
#include "aha152x.h"
#include <linux/stat.h>
#error define AUTOCONF or SETUP0
#endif
-#if defined(DEBUG_AHA152X)
-
-#undef SKIP_PORTS /* don't display ports */
-
-#undef DEBUG_QUEUE /* debug queue() */
-#undef DEBUG_RESET /* debug reset() */
-#undef DEBUG_INTR /* debug intr() */
-#undef DEBUG_SELECTION /* debug selection part in intr() */
-#undef DEBUG_MSGO /* debug message out phase in intr() */
-#undef DEBUG_MSGI /* debug message in phase in intr() */
-#undef DEBUG_STATUS /* debug status phase in intr() */
-#undef DEBUG_CMD /* debug command phase in intr() */
-#undef DEBUG_DATAI /* debug data in phase in intr() */
-#undef DEBUG_DATAO /* debug data out phase in intr() */
-#undef DEBUG_ABORT /* debug abort() */
-#undef DEBUG_DONE /* debug done() */
-#undef DEBUG_BIOSPARAM /* debug biosparam() */
-
-#undef DEBUG_RACE /* debug race conditions */
-#undef DEBUG_PHASES /* debug phases (useful to trace) */
-#undef DEBUG_QUEUES /* debug reselection */
-
-/* recently used for debugging */
-#if 0
-#endif
-
-#define DEBUG_SELECTION
-#define DEBUG_PHASES
-#define DEBUG_RESET
-#define DEBUG_ABORT
-
-#define DEBUG_DEFAULT (debug_reset|debug_abort)
-
-#endif
-
-/* END OF DEFINES */
+#if defined(AHA152X_DEBUG)
+#define DEBUG_DEFAULT debug_eh
+
+#define DPRINTK(when,msgs...) \
+ do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
+
+#define DO_LOCK(flags) \
+ do { \
+ if(QLOCK.lock) { \
+ DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+ } \
+ DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+ spin_lock_irqsave(&QLOCK,flags); \
+ DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+ QLOCKER=__FUNCTION__; \
+ QLOCKERL=__LINE__; \
+ } while(0)
+
+#define DO_UNLOCK(flags) \
+ do { \
+ DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+ spin_unlock_irqrestore(&QLOCK,flags); \
+ DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+ QLOCKER="(not locked)"; \
+ QLOCKERL=0; \
+ } while(0)
-extern long loops_per_sec;
+#else
+#define DPRINTK(when,msgs...)
+#define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags)
+#define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags)
+#define DEBUG_DEFAULT 0
+#endif
+
+#define LEAD "(scsi%d:%d:%d) "
+#define WARN_LEAD KERN_WARNING LEAD
+#define INFO_LEAD KERN_INFO LEAD
+#define NOTE_LEAD KERN_NOTICE LEAD
+#define ERR_LEAD KERN_ERR LEAD
+#define DEBUG_LEAD KERN_DEBUG LEAD
+#define CMDINFO(cmd) \
+ (cmd) ? ((cmd)->host->host_no) : -1, \
+ (cmd) ? ((cmd)->target & 0x0f) : -1, \
+ (cmd) ? ((cmd)->lun & 0x07) : -1
#define DELAY_DEFAULT 100
-/* some additional "phases" for getphase() */
-#define P_BUSFREE 1
-#define P_PARITY 2
-
/* possible irq range */
-#ifdef PCMCIA
+#if defined(PCMCIA)
#define IRQ_MIN 0
#define IRQ_MAX 16
#else
#define IRQS IRQ_MAX-IRQ_MIN+1
enum {
- not_issued = 0x0001,
- in_selection = 0x0002,
- disconnected = 0x0004,
- aborted = 0x0008,
- sent_ident = 0x0010,
- in_other = 0x0020,
- in_sync = 0x0040,
- sync_ok = 0x0080,
+ not_issued = 0x0001, /* command not yet issued */
+ selecting = 0x0002, /* target is beeing selected */
+ identified = 0x0004, /* IDENTIFY was sent */
+ disconnected = 0x0008, /* target disconnected */
+ completed = 0x0010, /* target sent COMMAND COMPLETE */
+ aborted = 0x0020, /* ABORT was sent */
+ resetted = 0x0040, /* BUS DEVICE RESET was sent */
+ spiordy = 0x0080, /* waiting for SPIORDY to raise */
+ syncneg = 0x0100, /* synchronous negotiation in progress */
+ aborting = 0x0200, /* ABORT is pending */
+ resetting = 0x0400, /* BUS DEVICE RESET is pending */
};
#if defined(MODULE)
-#if defined(DEBUG_AHA152X)
-int aha152x[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-int aha152x1[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-MODULE_PARM(aha152x, "1-9i");
-MODULE_PARM(aha152x1, "1-9i");
-#else
-int aha152x[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
-int aha152x1[] =
-{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+MODULE_AUTHOR("Jürgen Fischer");
+MODULE_DESCRIPTION(AHA152X_REVID);
+MODULE_PARM(io, "1-2i");
+MODULE_PARM_DESC(io,"base io address of controller");
+static int io[] = {0, 0};
+
+MODULE_PARM(irq, "1-2i");
+MODULE_PARM_DESC(irq,"interrupt for controller");
+static int irq[] = {0, 0};
+
+MODULE_PARM(scsiid, "1-2i");
+MODULE_PARM_DESC(scsiid,"scsi id of controller");
+static int scsiid[] = {7, 7};
+
+MODULE_PARM(reconnect, "1-2i");
+MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
+static int reconnect[] = {1, 1};
+
+MODULE_PARM(parity, "1-2i");
+MODULE_PARM_DESC(parity,"use scsi parity");
+static int parity[] = {1, 1};
+
+MODULE_PARM(sync, "1-2i");
+MODULE_PARM_DESC(sync,"use synchronous transfers");
+static int sync[] = {1, 1};
+
+MODULE_PARM(delay, "1-2i");
+MODULE_PARM_DESC(delay,"scsi reset delay");
+static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
+
+MODULE_PARM(exttrans, "1-2i");
+MODULE_PARM_DESC(exttrans,"use extended translation");
+static int exttrans[] = {0, 0};
+
+#if !defined(AHA152X_DEBUG)
MODULE_PARM(aha152x, "1-8i");
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+static int aha152x[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+
MODULE_PARM(aha152x1, "1-8i");
-#endif
-#endif
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+#else
+MODULE_PARM(debug, "1-2i");
+MODULE_PARM_DESC(debug, "flags for driver debugging");
+static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT};
+
+MODULE_PARM(aha152x, "1-9i");
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+
+MODULE_PARM(aha152x1, "1-9i");
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+#endif /* !defined(AHA152X_DEBUG) */
+#endif /* MODULE */
/* set by aha152x_setup according to the command line */
static int setup_count = 0;
int synchronous;
int delay;
int ext_trans;
-#ifdef DEBUG_AHA152X
+ int tc1550;
+#if defined(AHA152X_DEBUG)
int debug;
#endif
char *conf;
static struct Scsi_Host *aha152x_host[IRQS];
-#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)
-#define CURRENT_SC (HOSTDATA(shpnt)->current_SC)
-#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC)
-#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC)
-#define DELAY (HOSTDATA(shpnt)->delay)
-#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans)
-#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target])
-#define MSG(i) (HOSTDATA(shpnt)->message[i])
-#define MSGLEN (HOSTDATA(shpnt)->message_len)
-#define ADDMSG(x) (MSG(MSGLEN++)=x)
+/*
+ * internal states of the host
+ *
+ */
+enum aha152x_state {
+ idle=0,
+ unknown,
+ seldo,
+ seldi,
+ selto,
+ busfree,
+ msgo,
+ cmd,
+ msgi,
+ status,
+ datai,
+ datao,
+ parerr,
+ rsti,
+ maxstate
+};
+/*
+ * current state information of the host
+ *
+ */
struct aha152x_hostdata {
Scsi_Cmnd *issue_SC;
+ /* pending commands to issue */
+
Scsi_Cmnd *current_SC;
+ /* current command on the bus */
+
Scsi_Cmnd *disconnected_SC;
- int aborting;
- int abortion_complete;
- int abort_result;
- int commands;
+ /* commands that disconnected */
- int reconnect;
- int parity;
- int synchronous;
- int delay;
- int ext_trans;
+ Scsi_Cmnd *done_SC;
+ /* command that was completed */
- int swint;
- int service;
+ spinlock_t lock;
+ /* host lock */
- unsigned char syncrate[8];
+#if defined(AHA152X_DEBUG)
+ char *locker; /* which function has the lock */
+ int lockerl; /* where did it get it */
- unsigned char message[256];
- int message_len;
+ int debug; /* current debugging setting */
+#endif
-#ifdef DEBUG_AHA152X
- int debug;
+#if defined(AHA152X_STAT)
+ int total_commands;
+ int disconnections;
+ int busfree_without_any_action;
+ int busfree_without_old_command;
+ int busfree_without_new_command;
+ int busfree_without_done_command;
+ int busfree_with_check_condition;
+ int count[maxstate];
+ int count_trans[maxstate];
+ unsigned long time[maxstate];
#endif
+
+ int commands; /* current number of commands */
+
+ int reconnect; /* disconnection allowed */
+ int parity; /* parity checking enabled */
+ int synchronous; /* synchronous transferes enabled */
+ int delay; /* reset out delay */
+ int ext_trans; /* extended translation enabled */
+
+ int swint; /* software-interrupt was fired during detect() */
+ int service; /* bh needs to be run */
+ int in_intr; /* bh is running */
+
+ /* current state,
+ previous state,
+ last state different from current state */
+ enum aha152x_state state, prevstate, laststate;
+
+ int target;
+ /* reconnecting target */
+
+ unsigned char syncrate[8];
+ /* current synchronous transfer agreements */
+
+ unsigned char syncneg[8];
+ /* 0: no negotiation;
+ * 1: negotiation in progress;
+ * 2: negotiation completed
+ */
+
+ int cmd_i;
+ /* number of sent bytes of current command */
+
+ int msgi_len;
+ /* number of received message bytes */
+ unsigned char msgi[256];
+ /* received message bytes */
+
+ int msgo_i, msgo_len;
+ /* number of sent bytes and length of current messages */
+ unsigned char msgo[256];
+ /* pending messages */
+
+ int data_len;
+ /* number of sent/received bytes in dataphase */
+
+ unsigned long io_port0;
+ unsigned long io_port1;
+};
+
+
+/*
+ * host specific command extension
+ *
+ */
+struct aha152x_scdata {
+ Scsi_Cmnd *next; /* next sc in queue */
+ Scsi_Cmnd *done; /* done command */
+ struct semaphore *sem; /* semaphore to block on */
};
-static void aha152x_intr(int irq, void *dev_id, struct pt_regs *);
-void aha152x_done(struct Scsi_Host *shpnt, int error);
-void aha152x_setup(char *str, int *ints);
-int aha152x_checksetup(struct aha152x_setup *setup);
-static void aha152x_reset_ports(struct Scsi_Host *shpnt);
-static void aha152x_panic(struct Scsi_Host *shpnt, char *msg);
+/* access macros for hostdata */
+
+#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)
+
+#define HOSTNO ((shpnt)->host_no)
+
+#define CURRENT_SC (HOSTDATA(shpnt)->current_SC)
+#define DONE_SC (HOSTDATA(shpnt)->done_SC)
+#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC)
+#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC)
+#define QLOCK (HOSTDATA(shpnt)->lock)
+#define QLOCKER (HOSTDATA(shpnt)->locker)
+#define QLOCKERL (HOSTDATA(shpnt)->lockerl)
+
+#define STATE (HOSTDATA(shpnt)->state)
+#define PREVSTATE (HOSTDATA(shpnt)->prevstate)
+#define LASTSTATE (HOSTDATA(shpnt)->laststate)
+
+#define RECONN_TARGET (HOSTDATA(shpnt)->target)
+
+#define CMD_I (HOSTDATA(shpnt)->cmd_i)
+
+#define MSGO(i) (HOSTDATA(shpnt)->msgo[i])
+#define MSGO_I (HOSTDATA(shpnt)->msgo_i)
+#define MSGOLEN (HOSTDATA(shpnt)->msgo_len)
+#define ADDMSGO(x) (MSGOLEN<256 ? MSGO(MSGOLEN++)=x : aha152x_error(shpnt,"MSGO overflow"))
+
+#define MSGI(i) (HOSTDATA(shpnt)->msgi[i])
+#define MSGILEN (HOSTDATA(shpnt)->msgi_len)
+#define ADDMSGI(x) (MSGILEN<256 ? MSGI(MSGILEN++)=x : aha152x_error(shpnt,"MSGI overflow"))
+
+#define DATA_LEN (HOSTDATA(shpnt)->data_len)
+
+#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target])
+#define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->target])
+
+#define DELAY (HOSTDATA(shpnt)->delay)
+#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans)
+#define TC1550 (HOSTDATA(shpnt)->tc1550)
+#define RECONNECT (HOSTDATA(shpnt)->reconnect)
+#define PARITY (HOSTDATA(shpnt)->parity)
+#define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous)
+
+#define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0)
+#define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1)
+#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble)
+#define SCNEXT(SCpnt) SCDATA(SCpnt)->next
+#define SCDONE(SCpnt) SCDATA(SCpnt)->done
+#define SCSEM(SCpnt) SCDATA(SCpnt)->sem
+
+
+/* state handling */
+static void seldi_run(struct Scsi_Host *shpnt);
+static void seldo_run(struct Scsi_Host *shpnt);
+static void selto_run(struct Scsi_Host *shpnt);
+static void busfree_run(struct Scsi_Host *shpnt);
+
+static void msgo_init(struct Scsi_Host *shpnt);
+static void msgo_run(struct Scsi_Host *shpnt);
+static void msgo_end(struct Scsi_Host *shpnt);
+
+static void cmd_init(struct Scsi_Host *shpnt);
+static void cmd_run(struct Scsi_Host *shpnt);
+static void cmd_end(struct Scsi_Host *shpnt);
+
+static void datai_init(struct Scsi_Host *shpnt);
+static void datai_run(struct Scsi_Host *shpnt);
+static void datai_end(struct Scsi_Host *shpnt);
+
+static void datao_init(struct Scsi_Host *shpnt);
+static void datao_run(struct Scsi_Host *shpnt);
+static void datao_end(struct Scsi_Host *shpnt);
+
+static void status_run(struct Scsi_Host *shpnt);
+
+static void msgi_run(struct Scsi_Host *shpnt);
+static void msgi_end(struct Scsi_Host *shpnt);
+
+static void parerr_run(struct Scsi_Host *shpnt);
+static void rsti_run(struct Scsi_Host *shpnt);
+
+static void complete(struct Scsi_Host *shpnt);
+
+/*
+ * driver states
+ *
+ */
+static struct {
+ char *name;
+ void (*init)(struct Scsi_Host *);
+ void (*run)(struct Scsi_Host *);
+ void (*end)(struct Scsi_Host *);
+ int spio;
+} states[] = {
+ { "idle", 0, 0, 0, 0},
+ { "unknown", 0, 0, 0, 0},
+ { "seldo", 0, seldo_run, 0, 0},
+ { "seldi", 0, seldi_run, 0, 0},
+ { "selto", 0, selto_run, 0, 0},
+ { "busfree", 0, busfree_run, 0, 0},
+ { "msgo", msgo_init, msgo_run, msgo_end, 1},
+ { "cmd", cmd_init, cmd_run, cmd_end, 1},
+ { "msgi", 0, msgi_run, msgi_end, 1},
+ { "status", 0, status_run, 0, 1},
+ { "datai", datai_init, datai_run, datai_end, 0},
+ { "datao", datao_init, datao_run, datao_end, 0},
+ { "parerr", 0, parerr_run, 0, 0},
+ { "rsti", 0, rsti_run, 0, 0},
+};
+
+/* setup & interrupt */
+static void intr(int irq, void *dev_id, struct pt_regs *);
+static void reset_ports(struct Scsi_Host *shpnt);
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
+static void done(struct Scsi_Host *shpnt, int error);
+static int checksetup(struct aha152x_setup *setup);
+
+/* diagnostics */
static void disp_ports(struct Scsi_Host *shpnt);
static void show_command(Scsi_Cmnd * ptr);
static void show_queues(struct Scsi_Host *shpnt);
static void disp_enintr(struct Scsi_Host *shpnt);
-#if defined(DEBUG_RACE)
-static void enter_driver(const char *);
-static void leave_driver(const char *);
-#endif
-
-/* possible i/o addresses for the AIC-6260 */
-static unsigned short ports[] =
-{
- 0x340, /* default first */
- 0x140
-};
+/* possible i/o addresses for the AIC-6260; default first */
+static unsigned short ports[] = { 0x340, 0x140 };
#define PORT_COUNT (sizeof(ports) / sizeof(unsigned short))
#if !defined(SKIP_BIOSTEST)
-/* possible locations for the Adaptec BIOS */
+/* possible locations for the Adaptec BIOS; defaults first */
static unsigned int addresses[] =
{
0xdc000, /* default first */
int sig_offset;
int sig_length;
} signatures[] =
-
{
- {
- "Adaptec AHA-1520 BIOS", 0x102e, 21
- }, /* Adaptec 152x */
- {
- "Adaptec AHA-1520B", 0x0b, 19
- }, /* Adaptec 152x rev B */
- {
- "Adaptec ASW-B626 BIOS", 0x1029, 21
- }, /* on-board controller */
- {
- "Adaptec BIOS: ASW-B626", 0x0f, 22
- }, /* on-board controller */
- {
- "Adaptec ASW-B626 S2", 0x2e6c, 19
- }, /* on-board controller */
- {
- "Adaptec BIOS:AIC-6360", 0xc, 21
- }, /* on-board controller */
- {
- "ScsiPro SP-360 BIOS", 0x2873, 19
- }, /* ScsiPro-Controller */
- {
- "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26
- }, /* Gigabyte Local-Bus-SCSI */
- {
- "Adaptec BIOS:AVA-282X", 0xc, 21
- }, /* Adaptec 282x */
- {
- "Adaptec IBM Dock II SCSI", 0x2edd, 24
- }, /* IBM Thinkpad Dock II */
- {
- "Adaptec BIOS:AHA-1532P", 0x1c, 22
- }, /* IBM Thinkpad Dock II SCSI */
- {
- "DTC3520A Host Adapter BIOS", 0x318a, 26
- }, /* DTC 3520A ISA SCSI */
+ { "Adaptec AHA-1520 BIOS", 0x102e, 21 },
+ /* Adaptec 152x */
+ { "Adaptec AHA-1520B", 0x000b, 19 },
+ /* Adaptec 152x rev B */
+ { "Adaptec ASW-B626 BIOS", 0x1029, 21 },
+ /* on-board controller */
+ { "Adaptec BIOS: ASW-B626", 0x000f, 22 },
+ /* on-board controller */
+ { "Adaptec ASW-B626 S2", 0x2e6c, 19 },
+ /* on-board controller */
+ { "Adaptec BIOS:AIC-6360", 0x000c, 21 },
+ /* on-board controller */
+ { "ScsiPro SP-360 BIOS", 0x2873, 19 },
+ /* ScsiPro-Controller */
+ { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
+ /* Gigabyte Local-Bus-SCSI */
+ { "Adaptec BIOS:AVA-282X", 0x000c, 21 },
+ /* Adaptec 282x */
+ { "Adaptec IBM Dock II SCSI", 0x2edd, 24 },
+ /* IBM Thinkpad Dock II */
+ { "Adaptec BIOS:AHA-1532P", 0x001c, 22 },
+ /* IBM Thinkpad Dock II SCSI */
+ { "DTC3520A Host Adapter BIOS", 0x318a, 26 },
+ /* DTC 3520A ISA SCSI */
};
#define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature))
#endif
-static void do_pause(unsigned amount)
-{ /* Pause for amount*10 milliseconds */
- unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
-
- while (time_before(jiffies, the_time))
- barrier();
-}
-
/*
* queue services:
+ *
*/
-static inline void append_SC(Scsi_Cmnd ** SC, Scsi_Cmnd * new_SC)
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
{
Scsi_Cmnd *end;
- new_SC->host_scribble = (unsigned char *) NULL;
+ SCNEXT(new_SC) = NULL;
if (!*SC)
*SC = new_SC;
else {
- for (end = *SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble);
- end->host_scribble = (unsigned char *) new_SC;
+ for (end = *SC; SCNEXT(end); end = SCNEXT(end))
+ ;
+ SCNEXT(end) = new_SC;
}
}
Scsi_Cmnd *ptr;
ptr = *SC;
- if (ptr)
- *SC = (Scsi_Cmnd *) (*SC)->host_scribble;
+ if (ptr) {
+ *SC = SCNEXT(*SC);
+ SCNEXT(ptr)=NULL;
+ }
return ptr;
}
-static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd ** SC, int target, int lun)
+static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun)
{
Scsi_Cmnd *ptr, *prev;
for (ptr = *SC, prev = NULL;
ptr && ((ptr->target != target) || (ptr->lun != lun));
- prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+ prev = ptr, ptr = SCNEXT(ptr))
+ ;
if (ptr) {
if (prev)
- prev->host_scribble = ptr->host_scribble;
+ SCNEXT(prev) = SCNEXT(ptr);
else
- *SC = (Scsi_Cmnd *) ptr->host_scribble;
- }
- return ptr;
-}
+ *SC = SCNEXT(ptr);
-/*
- * read inbound byte and wait for ACK to get low
- */
-static void make_acklow(struct Scsi_Host *shpnt)
-{
- SETPORT(SXFRCTL0, CH1 | SPIOEN);
- GETPORT(SCSIDAT);
- SETPORT(SXFRCTL0, CH1);
+ SCNEXT(ptr)=NULL;
+ }
- while (TESTHI(SCSISIG, ACKI))
- barrier();
+ return ptr;
}
-/*
- * detect current phase more reliable:
- * phase is valid, when the target asserts REQ after we've deasserted ACK.
- *
- * return value is a valid phase or an error code.
- *
- * errorcodes:
- * P_BUSFREE BUS FREE phase detected
- * P_PARITY parity error in DATA phase
- */
-static int getphase(struct Scsi_Host *shpnt)
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
{
- int phase, sstat1;
-
- while (1) {
- do {
- while (!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE | SCSIRSTI | REQINIT)))
- barrier();
- if (sstat1 & BUSFREE)
- return P_BUSFREE;
- if (sstat1 & SCSIRSTI) {
- printk("aha152x: RESET IN\n");
- SETPORT(SSTAT1, SCSIRSTI);
- }
- } while (TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT));
-
- SETPORT(SSTAT1, CLRSCSIPERR);
+ Scsi_Cmnd *ptr, *prev;
- phase = GETPORT(SCSISIG) & P_MASK;
+ for (ptr = *SC, prev = NULL;
+ ptr && SCp!=ptr;
+ prev = ptr, ptr = SCNEXT(ptr))
+ ;
- if (TESTHI(SSTAT1, SCSIPERR)) {
- if ((phase & (CDO | MSGO)) == 0) /* DATA phase */
- return P_PARITY;
+ if (ptr) {
+ if (prev)
+ SCNEXT(prev) = SCNEXT(ptr);
+ else
+ *SC = SCNEXT(ptr);
- make_acklow(shpnt);
- } else
- return phase;
+ SCNEXT(ptr)=NULL;
}
+
+ return ptr;
}
-#ifdef PCMCIA
+#if defined(PCMCIA) || !defined(MODULE)
void aha152x_setup(char *str, int *ints)
{
- if (setup_count > 2)
- panic("aha152x: you can only configure up to two controllers\n");
-
- setup[setup_count].conf = str;
- setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340;
- setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11;
- setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7;
- setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1;
- setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1;
- setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */ ;
- setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
- setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
-#ifdef DEBUG_AHA152X
- setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
+ if(setup_count>2) {
+ printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
+ return;
+ }
+
+ setup[setup_count].conf = str;
+ setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340;
+ setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11;
+ setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7;
+ setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1;
+ setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1;
+ setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
+ setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
+ setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
+#if defined(AHA152X_DEBUG)
+ setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
if (ints[0] > 9) {
- printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+ printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
"[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
#else
- if (ints[0] > 8) {
- printk("aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+ if (ints[0] > 8) { /*}*/
+ printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
"[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
#endif
- } else
+ return;
+ } else {
setup_count++;
+ return;
+ }
}
-#endif /* PCMCIA */
+#endif
-#ifndef MODULE
-static int __init do_aha152x_setup (char * str)
+#if !defined(MODULE)
+static int __init do_setup(char *str)
{
- if (setup_count > 2) {
- printk(KERN_ERR"aha152x: you can only configure up to two
-controllers\n");
- return 0;
- }
- setup[setup_count].conf = str;
- get_option(&str,&setup[setup_count].io_port);
- get_option(&str,&setup[setup_count].irq);
- get_option(&str,&setup[setup_count].scsiid);
- get_option(&str,&setup[setup_count].reconnect);
-
- setup_count++;
- return 1;
+#if defined(AHA152X_DEBUG)
+ int ints[11];
+#else
+ int ints[10];
+#endif
+ int count=setup_count;
+
+ get_options(str, sizeof(ints)/sizeof(int), ints);
+ aha152x_setup(str,ints);
+
+ return count<setup_count;
}
-__setup("aha152x=",do_aha152x_setup);
+__setup("aha152x=", do_setup);
#endif
-
+
/*
* Test, if port_base is valid.
+ *
*/
static int aha152x_porttest(int io_port)
{
SETPORT(io_port + O_STACK, i);
SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */
- for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++);
+ for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
+ ;
+
+ return (i == 16);
+}
+
+static int tc1550_porttest(int io_port)
+{
+ int i;
+
+ if (check_region(io_port, IO_RANGE))
+ return 0;
+
+ SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */
+ for (i = 0; i < 16; i++)
+ SETPORT(io_port + O_STACK, i);
+
+ SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */
+ for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
+ ;
return (i == 16);
}
-int aha152x_checksetup(struct aha152x_setup *setup)
+static int checksetup(struct aha152x_setup *setup)
{
int i;
-#ifndef PCMCIA
- for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++);
+#if !defined(PCMCIA)
+ for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++)
+ ;
if (i == PORT_COUNT)
return 0;
#endif
- if (!aha152x_porttest(setup->io_port))
- return 0;
+ if(aha152x_porttest(setup->io_port)) {
+ setup->tc1550=0;
+ } else if(tc1550_porttest(setup->io_port)) {
+ setup->tc1550=1;
+ } else
+ return 0;
if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
return 0;
return 1;
}
-void aha152x_swintr(int irqno, void *dev_id, struct pt_regs *regs)
+static void swintr(int irqno, void *dev_id, struct pt_regs *regs)
{
struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
if (!shpnt)
- panic("aha152x: catched software interrupt for unknown controller.\n");
+ printk(KERN_ERR "aha152x%d: catched software interrupt for unknown controller.\n", HOSTNO);
HOSTDATA(shpnt)->swint++;
}
#if defined(AUTOCONF)
aha152x_config conf;
#endif
-
- tpnt->proc_name = "aha152x";
+ tpnt->proc_name = "aha152x";
for (i = 0; i < IRQS; i++)
aha152x_host[i] = (struct Scsi_Host *) NULL;
if (setup_count) {
- printk("aha152x: processing commandline: ");
+ printk(KERN_INFO "aha152x: processing commandline: ");
for (i = 0; i < setup_count; i++)
- if (!aha152x_checksetup(&setup[i])) {
- printk("\naha152x: %s\n", setup[i].conf);
- printk("aha152x: invalid line (controller=%d)\n", i + 1);
+ if (!checksetup(&setup[i])) {
+ printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
+ printk(KERN_ERR "aha152x: invalid line\n");
}
printk("ok\n");
}
-#ifdef SETUP0
+#if defined(SETUP0)
if (setup_count < 2) {
struct aha152x_setup override = SETUP0;
if (setup_count == 0 || (override.io_port != setup[0].io_port))
- if (!aha152x_checksetup(&override)) {
- printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+ if (!checksetup(&override)) {
+ printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
override.io_port,
override.irq,
override.scsiid,
}
#endif
-#ifdef SETUP1
+#if defined(SETUP1)
if (setup_count < 2) {
struct aha152x_setup override = SETUP1;
if (setup_count == 0 || (override.io_port != setup[0].io_port))
- if (!aha152x_checksetup(&override)) {
- printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+ if (!checksetup(&override)) {
+ printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
override.io_port,
override.irq,
override.scsiid,
#endif
#if defined(MODULE)
- if (setup_count < 2 && aha152x[0] != 0) {
- setup[setup_count].conf = "";
- setup[setup_count].io_port = aha152x[0];
- setup[setup_count].irq = aha152x[1];
- setup[setup_count].scsiid = aha152x[2];
- setup[setup_count].reconnect = aha152x[3];
- setup[setup_count].parity = aha152x[4];
- setup[setup_count].synchronous = aha152x[5];
- setup[setup_count].delay = aha152x[6];
- setup[setup_count].ext_trans = aha152x[7];
-#ifdef DEBUG_AHA152X
- setup[setup_count].debug = aha152x[8];
+ if (setup_count<2 && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
+ if(aha152x[0]!=0) {
+ setup[setup_count].conf = "";
+ setup[setup_count].io_port = aha152x[0];
+ setup[setup_count].irq = aha152x[1];
+ setup[setup_count].scsiid = aha152x[2];
+ setup[setup_count].reconnect = aha152x[3];
+ setup[setup_count].parity = aha152x[4];
+ setup[setup_count].synchronous = aha152x[5];
+ setup[setup_count].delay = aha152x[6];
+ setup[setup_count].ext_trans = aha152x[7];
+#if defined(AHA152X_DEBUG)
+ setup[setup_count].debug = aha152x[8];
+#endif
+ } else if(io[0]!=0 || irq[0]!=0) {
+ if(io[0]!=0) setup[setup_count].io_port = io[0];
+ if(irq[0]!=0) setup[setup_count].irq = irq[0];
+
+ setup[setup_count].scsiid = scsiid[0];
+ setup[setup_count].reconnect = reconnect[0];
+ setup[setup_count].parity = parity[0];
+ setup[setup_count].synchronous = sync[0];
+ setup[setup_count].delay = delay[0];
+ setup[setup_count].ext_trans = exttrans[0];
+#if defined(AHA152X_DEBUG)
+ setup[setup_count].debug = debug[0];
#endif
- if (aha152x_checksetup(&setup[setup_count]))
+ }
+
+ if (checksetup(&setup[setup_count]))
setup_count++;
else
- printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+ printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
setup[setup_count].io_port,
setup[setup_count].irq,
setup[setup_count].scsiid,
setup[setup_count].delay,
setup[setup_count].ext_trans);
}
- if (setup_count < 2 && aha152x1[0] != 0) {
- setup[setup_count].conf = "";
- setup[setup_count].io_port = aha152x1[0];
- setup[setup_count].irq = aha152x1[1];
- setup[setup_count].scsiid = aha152x1[2];
- setup[setup_count].reconnect = aha152x1[3];
- setup[setup_count].parity = aha152x1[4];
- setup[setup_count].synchronous = aha152x1[5];
- setup[setup_count].delay = aha152x1[6];
- setup[setup_count].ext_trans = aha152x1[7];
-#ifdef DEBUG_AHA152X
- setup[setup_count].debug = aha152x1[8];
+
+ if (setup_count < 2 && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
+ if(aha152x1[0]!=0) {
+ setup[setup_count].conf = "";
+ setup[setup_count].io_port = aha152x1[0];
+ setup[setup_count].irq = aha152x1[1];
+ setup[setup_count].scsiid = aha152x1[2];
+ setup[setup_count].reconnect = aha152x1[3];
+ setup[setup_count].parity = aha152x1[4];
+ setup[setup_count].synchronous = aha152x1[5];
+ setup[setup_count].delay = aha152x1[6];
+ setup[setup_count].ext_trans = aha152x1[7];
+#if defined(AHA152X_DEBUG)
+ setup[setup_count].debug = aha152x1[8];
+#endif
+ } else if(io[1]!=0 || irq[1]!=0) {
+ if(io[1]!=0) setup[setup_count].io_port = io[1];
+ if(irq[1]!=0) setup[setup_count].irq = irq[1];
+
+ setup[setup_count].scsiid = scsiid[1];
+ setup[setup_count].reconnect = reconnect[1];
+ setup[setup_count].parity = parity[1];
+ setup[setup_count].synchronous = sync[1];
+ setup[setup_count].delay = delay[1];
+ setup[setup_count].ext_trans = exttrans[1];
+#if defined(AHA152X_DEBUG)
+ setup[setup_count].debug = debug[1];
#endif
- if (aha152x_checksetup(&setup[setup_count]))
+ }
+ if (checksetup(&setup[setup_count]))
setup_count++;
else
- printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n",
+ printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
setup[setup_count].io_port,
setup[setup_count].irq,
setup[setup_count].scsiid,
for (i = 0; i < ADDRESS_COUNT && !ok; i++)
for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++)
ok = isa_check_signature(addresses[i] + signatures[j].sig_offset,
- signatures[j].signature, signatures[j].sig_length);
+ signatures[j].signature, signatures[j].sig_length);
if (!ok && setup_count == 0)
return 0;
- printk("aha152x: BIOS test: passed, ");
+ printk(KERN_INFO "aha152x: BIOS test: passed, ");
#else
- printk("aha152x: ");
+ printk(KERN_INFO "aha152x: ");
#endif /* !SKIP_BIOSTEST */
ok = 0;
if (aha152x_porttest(ports[i])) {
ok++;
setup[setup_count].io_port = ports[i];
+ setup[setup_count].tc1550 = 0;
+
+ conf.cf_port =
+ (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
+
+ setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
+ setup[setup_count].scsiid = conf.cf_id;
+ setup[setup_count].reconnect = conf.cf_tardisc;
+ setup[setup_count].parity = !conf.cf_parity;
+ setup[setup_count].synchronous = conf.cf_syncneg;
+ setup[setup_count].delay = DELAY_DEFAULT;
+ setup[setup_count].ext_trans = 0;
+#if defined(AHA152X_DEBUG)
+ setup[setup_count].debug = DEBUG_DEFAULT;
+#endif
+ setup_count++;
+ } else if (tc1550_porttest(ports[i])) {
+ ok++;
+ setup[setup_count].io_port = ports[i];
+ setup[setup_count].tc1550 = 1;
conf.cf_port =
(GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
setup[setup_count].scsiid = conf.cf_id;
setup[setup_count].reconnect = conf.cf_tardisc;
setup[setup_count].parity = !conf.cf_parity;
- setup[setup_count].synchronous = 0 /* FIXME: conf.cf_syncneg */ ;
+ setup[setup_count].synchronous = conf.cf_syncneg;
setup[setup_count].delay = DELAY_DEFAULT;
setup[setup_count].ext_trans = 0;
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
setup[setup_count].debug = DEBUG_DEFAULT;
#endif
setup_count++;
printk("detected %d controller(s)\n", setup_count);
- for (i = 0; i < setup_count; i++) {
+ for (i=0; i<setup_count; i++) {
struct Scsi_Host *shpnt;
- unsigned long int the_time;
- shpnt = aha152x_host[setup[i].irq - IRQ_MIN] =
+ aha152x_host[setup[i].irq - IRQ_MIN] = shpnt =
scsi_register(tpnt, sizeof(struct aha152x_hostdata));
+
+ if(!shpnt) {
+ printk(KERN_ERR "aha152x: scsi_register failed\n");
+ continue;
+ }
+
registered_count++;
- shpnt->io_port = setup[i].io_port;
+ shpnt->io_port = setup[i].io_port;
shpnt->n_io_port = IO_RANGE;
- shpnt->irq = setup[i].irq;
-
- ISSUE_SC = (Scsi_Cmnd *) NULL;
- CURRENT_SC = (Scsi_Cmnd *) NULL;
- DISCONNECTED_SC = (Scsi_Cmnd *) NULL;
-
- HOSTDATA(shpnt)->reconnect = setup[i].reconnect;
- HOSTDATA(shpnt)->parity = setup[i].parity;
- HOSTDATA(shpnt)->synchronous = setup[i].synchronous;
- HOSTDATA(shpnt)->delay = setup[i].delay;
- HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans;
-#ifdef DEBUG_AHA152X
- HOSTDATA(shpnt)->debug = setup[i].debug;
-#endif
+ shpnt->irq = setup[i].irq;
- HOSTDATA(shpnt)->aborting = 0;
- HOSTDATA(shpnt)->abortion_complete = 0;
- HOSTDATA(shpnt)->abort_result = 0;
- HOSTDATA(shpnt)->commands = 0;
+ if(!setup[i].tc1550) {
+ HOSTIOPORT0 = setup[i].io_port;
+ HOSTIOPORT1 = setup[i].io_port;
+ } else {
+ HOSTIOPORT0 = setup[i].io_port+0x10;
+ HOSTIOPORT1 = setup[i].io_port-0x10;
+ }
- HOSTDATA(shpnt)->message_len = 0;
+ ISSUE_SC = 0;
+ CURRENT_SC = 0;
+ DONE_SC = 0;
+ DISCONNECTED_SC = 0;
- for (j = 0; j < 8; j++)
- HOSTDATA(shpnt)->syncrate[j] = 0;
+ QLOCK = SPIN_LOCK_UNLOCKED;
+
+ STATE = 0;
+ PREVSTATE = 0;
+ LASTSTATE = 0;
+
+ MSGILEN = 0;
+ MSGOLEN = 0;
+
+ RECONNECT = setup[i].reconnect;
+ SYNCHRONOUS = setup[i].synchronous;
+ PARITY = setup[i].parity;
+ DELAY = setup[i].delay;
+ EXT_TRANS = setup[i].ext_trans;
+#if defined(AHA152X_DEBUG)
+ HOSTDATA(shpnt)->debug = setup[i].debug;
+#endif
+ HOSTDATA(shpnt)->in_intr = 0;
+ HOSTDATA(shpnt)->commands = 0;
+
+#if defined(AHA152X_STAT)
+ HOSTDATA(shpnt)->total_commands=0;
+ HOSTDATA(shpnt)->disconnections=0;
+ HOSTDATA(shpnt)->busfree_without_any_action=0;
+ HOSTDATA(shpnt)->busfree_without_old_command=0;
+ HOSTDATA(shpnt)->busfree_without_new_command=0;
+ HOSTDATA(shpnt)->busfree_without_done_command=0;
+ HOSTDATA(shpnt)->busfree_with_check_condition=0;
+ for (j = idle; j<maxstate; j++) {
+ HOSTDATA(shpnt)->count[j]=0;
+ HOSTDATA(shpnt)->count_trans[j]=0;
+ HOSTDATA(shpnt)->time[j]=0;
+ }
+#endif
+
+ for (j = 0; j < 8; j++) {
+ HOSTDATA(shpnt)->syncrate[j] = 0;
+ HOSTDATA(shpnt)->syncneg[j] = 0;
+ }
SETPORT(SCSIID, setup[i].scsiid << 4);
shpnt->this_id = setup[i].scsiid;
if (setup[i].reconnect)
shpnt->can_queue = AHA152X_MAXQUEUE;
- /* RESET OUT */
- SETBITS(SCSISEQ, SCSIRSTO);
- do_pause(30);
- CLRBITS(SCSISEQ, SCSIRSTO);
- do_pause(setup[i].delay);
-
- aha152x_reset_ports(shpnt);
+#if 0
+ if(!shpnt->hostt->use_new_eh_code) {
+#endif
+ /* RESET OUT */
+ printk("aha152x: resetting bus...\n");
+ SETPORT(SCSISEQ, SCSIRSTO);
+ mdelay(256);
+ SETPORT(SCSISEQ, 0);
+ mdelay(DELAY);
+#if 0
+ }
+#endif
- printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d,"
- " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n",
- i,
- shpnt->io_port,
+ reset_ports(shpnt);
+
+ printk(KERN_INFO
+ "aha152x%d%s: "
+ "vital data: rev=%x, "
+ "io=0x%03lx (0x%03lx/0x%03lx), "
+ "irq=%d, "
+ "scsiid=%d, "
+ "reconnect=%s, "
+ "parity=%s, "
+ "synchronous=%s, "
+ "delay=%d, "
+ "extended translation=%s\n",
+ HOSTNO, setup[i].tc1550 ? " (tc1550 mode)" : "",
+ GETPORT(REV) & 0x7,
+ shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
shpnt->irq,
shpnt->this_id,
- HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled",
- HOSTDATA(shpnt)->parity ? "enabled" : "disabled",
- HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled",
- HOSTDATA(shpnt)->delay,
- HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled");
+ RECONNECT ? "enabled" : "disabled",
+ PARITY ? "enabled" : "disabled",
+ SYNCHRONOUS ? "enabled" : "disabled",
+ DELAY,
+ EXT_TRANS ? "enabled" : "disabled");
- request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */
+ request_region(shpnt->io_port, IO_RANGE, "aha152x");
/* not expecting any interrupts */
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, 0);
- SETBITS(DMACNTRL0, INTEN);
-
- ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt);
+ ok = request_irq(shpnt->irq, swintr, SA_INTERRUPT, "aha152x", shpnt);
if (ok < 0) {
- if (ok == -EINVAL)
- printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq);
- else if (ok == -EBUSY)
- printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq);
+ if (ok==-EINVAL)
+ printk(KERN_ERR "aha152x%d: bad IRQ %d.\n", HOSTNO, shpnt->irq);
+ else if(ok==-EBUSY)
+ printk(KERN_ERR "aha152x%d: IRQ %d already in use.\n", HOSTNO, shpnt->irq);
else
- printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq);
- printk("aha152x: driver needs an IRQ.\n");
+ printk(KERN_ERR "aha152x%d: Unexpected error code %d on requesting IRQ %d.\n", HOSTNO, ok, shpnt->irq);
+
+ printk(KERN_ERR "aha152x%d: driver needs an IRQ.\n", HOSTNO);
scsi_unregister(shpnt);
registered_count--;
release_region(shpnt->io_port, IO_RANGE);
- shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+ aha152x_host[shpnt->irq - IRQ_MIN] = shpnt = 0;
continue;
}
HOSTDATA(shpnt)->swint = 0;
- printk("aha152x: trying software interrupt, ");
- SETBITS(DMACNTRL0, SWINT);
-
- the_time = jiffies + 100;
- while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time))
- barrier();
-
+ printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO);
+ SETPORT(DMACNTRL0, SWINT|INTEN);
+ spin_unlock_irq(&io_request_lock);
+ mdelay(1000);
+ spin_lock_irq(&io_request_lock);
free_irq(shpnt->irq, shpnt);
if (!HOSTDATA(shpnt)->swint) {
printk("failed.\n");
}
- printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq);
+ printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. Please verify.\n", HOSTNO, shpnt->irq);
scsi_unregister(shpnt);
registered_count--;
}
printk("ok.\n");
- CLRBITS(DMACNTRL0, SWINT);
+ SETPORT(DMACNTRL0, INTEN);
/* clear interrupts */
SETPORT(SSTAT0, 0x7f);
SETPORT(SSTAT1, 0xef);
- if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) {
- printk("aha152x: failed to reassign interrupt.\n");
+ if (request_irq(shpnt->irq, intr, SA_INTERRUPT, "aha152x", shpnt) < 0) {
+ printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", HOSTNO);
+
+ scsi_unregister(shpnt);
+ registered_count--;
+ release_region(shpnt->io_port, IO_RANGE);
+ shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0;
+ continue;
}
}
- return (registered_count > 0);
+ return registered_count>0;
}
{
if (shpnt->irq)
free_irq(shpnt->irq, shpnt);
+
if (shpnt->io_port)
release_region(shpnt->io_port, IO_RANGE);
+ scsi_unregister(shpnt);
+
return 0;
}
+/*
+ * setup controller to generate interrupts depending
+ * on current state (lock has to be aquired)
+ *
+ */
+static int setup_expected_interrupts(struct Scsi_Host *shpnt)
+{
+ ASSERT_LOCK(&QLOCK,1);
+
+ if(CURRENT_SC) {
+ CURRENT_SC->SCp.phase |= 1 << 16;
+
+ if(CURRENT_SC->SCp.phase & selecting) {
+ DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));
+ SETPORT(SSTAT1, SELTO);
+ SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+ SETPORT(SIMODE1, ENSELTIMO);
+ } else {
+ DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");
+ SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
+ SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
+ }
+ } else if(STATE==seldi) {
+ DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
+ } else {
+ DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",
+ CMDINFO(CURRENT_SC),
+ DISCONNECTED_SC ? "(reselection)" : "",
+ ISSUE_SC ? "(busfree)" : "");
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
+ }
+
+ if(!HOSTDATA(shpnt)->in_intr)
+ SETBITS(DMACNTRL0, INTEN);
+
+ return TESTHI(DMASTAT, INTSTAT);
+}
+
+
/*
* Queue a command and setup interrupts for a free bus.
*/
-int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, Scsi_Cmnd *done_SC, void (*done)(Scsi_Cmnd *))
{
struct Scsi_Host *shpnt = SCpnt->host;
unsigned long flags;
-#if defined(DEBUG_RACE)
- enter_driver("queue");
-#else
-#if defined(DEBUG_QUEUE)
- if (HOSTDATA(shpnt)->debug & debug_queue)
- printk("aha152x: queue(), ");
-#endif
-#endif
-
-#if defined(DEBUG_QUEUE)
+#if defined(AHA152X_DEBUG)
if (HOSTDATA(shpnt)->debug & debug_queue) {
- printk("SCpnt (target = %d lun = %d cmnd = ",
- SCpnt->target, SCpnt->lun);
+ printk(INFO_LEAD "queue: cmd_len=%d pieces=%d size=%u cmnd=",
+ CMDINFO(SCpnt), SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
print_command(SCpnt->cmnd);
- printk(", cmd_len=%d, pieces = %d size = %u), ",
- SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
- disp_ports(shpnt);
}
#endif
- SCpnt->scsi_done = done;
+ SCpnt->scsi_done = done;
+ SCpnt->resid = SCpnt->request_bufflen;
+ SCpnt->SCp.phase = not_issued | phase;
+ SCpnt->SCp.Status = CHECK_CONDITION;
+ SCpnt->SCp.Message = 0;
+ SCpnt->SCp.have_data_in = 0;
+ SCpnt->SCp.sent_command = 0;
+ SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
+ if(!SCpnt->host_scribble) {
+ printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
+ return FAILED;
+ }
+
+ SCNEXT(SCpnt) = 0;
+ SCDONE(SCpnt) = done_SC;
+ SCSEM(SCpnt) = sem;
/* setup scratch area
SCp.ptr : buffer pointer
SCp.buffer : next buffer
SCp.buffers_residual : left buffers in list
SCp.phase : current state of the command */
- SCpnt->SCp.phase = not_issued;
if (SCpnt->use_sg) {
- SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
- SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
- SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+ SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
+ SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
+ SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
} else {
- SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
- SCpnt->SCp.this_residual = SCpnt->request_bufflen;
- SCpnt->SCp.buffer = NULL;
+ SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
+ SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+ SCpnt->SCp.buffer = NULL;
SCpnt->SCp.buffers_residual = 0;
}
- SCpnt->SCp.Status = CHECK_CONDITION;
- SCpnt->SCp.Message = 0;
- SCpnt->SCp.have_data_in = 0;
- SCpnt->SCp.sent_command = 0;
+ DO_LOCK(flags);
+
+#if defined(AHA152X_STAT)
+ HOSTDATA(shpnt)->total_commands++;
+#endif
/* Turn led on, when this is the first command. */
- save_flags(flags);
- cli();
HOSTDATA(shpnt)->commands++;
- if (HOSTDATA(shpnt)->commands == 1)
+ if (HOSTDATA(shpnt)->commands==1)
SETPORT(PORTA, 1);
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("i+ (%d), ", HOSTDATA(shpnt)->commands);
-#endif
append_SC(&ISSUE_SC, SCpnt);
- /* Enable bus free interrupt, when we aren't currently on the bus */
- if (!CURRENT_SC) {
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
- }
- restore_flags(flags);
+ if(!HOSTDATA(shpnt)->in_intr)
+ setup_expected_interrupts(shpnt);
-#if defined(DEBUG_RACE)
- leave_driver("queue");
-#endif
+ DO_UNLOCK(flags);
return 0;
}
+int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+ if(*SCpnt->cmnd == REQUEST_SENSE) {
+ SCpnt->result = 0;
+ done(SCpnt);
+
+ return SUCCESS;
+ }
+
+ return aha152x_internal_queue(SCpnt, 0, 0, 0, done);
+}
+
+
/*
- * We only support commands in interrupt-driven fashion
+ * run a command
+ *
*/
+void internal_done(Scsi_Cmnd *SCpnt)
+{
+#if 0
+ struct Scsi_Host *shpnt = SCpnt->host;
+
+ DPRINTK(debug_eh, INFO_LEAD "internal_done called\n", CMDINFO(SCpnt));
+#endif
+ if(SCSEM(SCpnt))
+ up(SCSEM(SCpnt));
+}
+
int aha152x_command(Scsi_Cmnd * SCpnt)
{
- printk("aha152x: interrupt driven driver; use aha152x_queue()\n");
- return -1;
+ DECLARE_MUTEX_LOCKED(sem);
+
+ aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done);
+ down(&sem);
+
+ return SUCCESS;
}
/*
- * Abort a queued command
- * (commands that are on the bus can't be aborted easily)
+ * Abort a command
+ *
*/
-int aha152x_abort(Scsi_Cmnd * SCpnt)
+int aha152x_abort(Scsi_Cmnd *SCpnt)
{
struct Scsi_Host *shpnt = SCpnt->host;
+ Scsi_Cmnd *ptr;
unsigned long flags;
- Scsi_Cmnd *ptr, *prev;
- save_flags(flags);
- cli();
+ if(!shpnt) {
+ printk(ERR_LEAD "abort(%p): no host structure\n", CMDINFO(SCpnt), SCpnt);
+ return FAILED;
+ }
-#if defined(DEBUG_ABORT)
- if (HOSTDATA(shpnt)->debug & debug_abort) {
- printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt);
+#if defined(AHA152X_DEBUG)
+ if(HOSTDATA(shpnt)->debug & debug_eh) {
+ printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt);
show_queues(shpnt);
+ mdelay(1000);
}
#endif
- /* look for command in issue queue */
- for (ptr = ISSUE_SC, prev = NULL;
- ptr && ptr != SCpnt;
- prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+ DO_LOCK(flags);
- if (ptr) {
- /* dequeue */
- if (prev)
- prev->host_scribble = ptr->host_scribble;
- else
- ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ ptr=remove_SC(&ISSUE_SC, SCpnt);
+
+ if(ptr) {
+ DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt));
HOSTDATA(shpnt)->commands--;
+ if (!HOSTDATA(shpnt)->commands)
+ SETPORT(PORTA, 0);
+ DO_UNLOCK(flags);
- restore_flags(flags);
+ kfree(SCpnt->host_scribble);
+ SCpnt->host_scribble=0;
- ptr->host_scribble = NULL;
- ptr->result = DID_ABORT << 16;
- spin_lock_irqsave(&io_request_lock, flags);
- ptr->scsi_done(ptr);
- spin_unlock_irqrestore(&io_request_lock, flags);
+ return SUCCESS;
+ }
- return SCSI_ABORT_SUCCESS;
- }
- /* if the bus is busy or a command is currently processed,
- we can't do anything more */
- if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) {
- /* fail abortion, if bus is busy */
+ DO_UNLOCK(flags);
- if (!CURRENT_SC)
- printk("bus busy w/o current command, ");
+ /*
+ * FIXME:
+ * for current command: queue ABORT for message out and raise ATN
+ * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
+ *
+ */
- restore_flags(flags);
+ printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt));
- return SCSI_ABORT_BUSY;
- }
- /* bus is free */
+ return FAILED;
+}
- if (CURRENT_SC) {
- HOSTDATA(shpnt)->commands--;
+static void timer_expired(unsigned long p)
+{
+ struct semaphore *sem = (void *)p;
- /* target entered bus free before COMMAND COMPLETE, nothing to abort */
- restore_flags(flags);
- spin_lock_irqsave(&io_request_lock, flags);
- CURRENT_SC->result = DID_ERROR << 16;
- CURRENT_SC->scsi_done(CURRENT_SC);
- CURRENT_SC = (Scsi_Cmnd *) NULL;
- spin_unlock_irqrestore(&io_request_lock, flags);
+ printk(KERN_INFO "aha152x: timer expired\n");
+ up(sem);
+}
- return SCSI_ABORT_SUCCESS;
- }
- /* look for command in disconnected queue */
- for (ptr = DISCONNECTED_SC, prev = NULL;
- ptr && ptr != SCpnt;
- prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble);
+/*
+ * Reset a device
+ *
+ * FIXME: never seen this live. might lockup...
+ *
+ */
+int aha152x_device_reset(Scsi_Cmnd * SCpnt)
+{
+ struct Scsi_Host *shpnt = SCpnt->host;
+ DECLARE_MUTEX_LOCKED(sem);
+ struct timer_list timer;
+ Scsi_Cmnd cmnd;
- if (!ptr) {
- /* command wasn't found */
- printk("command not found\n");
- restore_flags(flags);
+#if defined(AHA152X_DEBUG)
+ if(HOSTDATA(shpnt)->debug & debug_eh) {
+ printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt);
+ show_queues(shpnt);
+ mdelay(1000);
+ }
+#endif
- return SCSI_ABORT_NOT_RUNNING;
+ if(CURRENT_SC==SCpnt) {
+ printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt));
+ return FAILED;
}
- if (!HOSTDATA(shpnt)->aborting) {
- /* dequeue */
- if (prev)
- prev->host_scribble = ptr->host_scribble;
- else
- DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
- HOSTDATA(shpnt)->commands--;
+ cmnd.cmd_len = 0;
+ cmnd.host = SCpnt->host;
+ cmnd.target = SCpnt->target;
+ cmnd.lun = SCpnt->lun;
+ cmnd.use_sg = 0;
+ cmnd.request_buffer = 0;
+ cmnd.request_bufflen = 0;
- /* set command current and initiate selection,
- let the interrupt routine take care of the abortion */
- CURRENT_SC = ptr;
- ptr->SCp.phase = in_selection | aborted;
- SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+ init_timer(&timer);
+ timer.data = (unsigned long) &sem;
+ timer.expires = jiffies + 10000; /* 10s */
+ timer.function = (void (*)(unsigned long)) timer_expired;
+ add_timer(&timer);
- ADDMSG(ABORT);
+ aha152x_internal_queue(&cmnd, &sem, resetting, 0, internal_done);
- /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
- SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
- SETPORT(SIMODE1, ENSELTIMO);
+ down(&sem);
- /* Enable SELECTION OUT sequence */
- SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+ del_timer(&timer);
- SETBITS(DMACNTRL0, INTEN);
- HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
- HOSTDATA(shpnt)->aborting++;
- HOSTDATA(shpnt)->abortion_complete = 0;
+ if(cmnd.SCp.phase & resetted) {
+ return SUCCESS;
+ } else {
+ return FAILED;
+ }
+}
- restore_flags(flags);
+void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs)
+{
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
- /* sleep until the abortion is complete */
- while (!HOSTDATA(shpnt)->abortion_complete)
- barrier();
- HOSTDATA(shpnt)->aborting = 0;
+ DO_LOCK(flags);
- return HOSTDATA(shpnt)->abort_result;
- } else {
- /* we're already aborting a command */
- restore_flags(flags);
+ ptr=*SCs;
+ while(ptr) {
+ Scsi_Cmnd *next = SCNEXT(ptr);
+
+ if (!ptr->device->soft_reset) {
+ DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr);
+ remove_SC(SCs, ptr);
+ HOSTDATA(shpnt)->commands--;
+ kfree(ptr->host_scribble);
+ ptr->host_scribble=0;
+ }
- return SCSI_ABORT_BUSY;
+ ptr = next;
}
+
+ DO_UNLOCK(flags);
}
+/*
+ * Reset the bus
+ *
+ */
+int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+{
+ struct Scsi_Host *shpnt = SCpnt->host;
+ unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+ if(HOSTDATA(shpnt)->debug & debug_eh) {
+ printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
+ show_queues(shpnt);
+ mdelay(1000);
+ }
+#endif
+
+ free_hard_reset_SCs(shpnt, &ISSUE_SC);
+ free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
+
+ DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt));
+
+ SETPORT(SCSISEQ, SCSIRSTO);
+ mdelay(256);
+ SETPORT(SCSISEQ, 0);
+ mdelay(DELAY);
+
+ DPRINTK(debug_eh, DEBUG_LEAD "bus reset returns\n", CMDINFO(SCpnt));
+
+ DO_LOCK(flags);
+ setup_expected_interrupts(shpnt);
+ if(HOSTDATA(shpnt)->commands==0)
+ SETPORT(PORTA, 0);
+ DO_UNLOCK(flags);
+
+ return SUCCESS;
+}
+
+
/*
* Restore default values to the AIC-6260 registers and reset the fifos
+ *
*/
-static void aha152x_reset_ports(struct Scsi_Host *shpnt)
+static void reset_ports(struct Scsi_Host *shpnt)
{
+ unsigned long flags;
+
/* disable interrupts */
SETPORT(DMACNTRL0, RSTFIFO);
SETPORT(SXFRCTL1, 0);
SETPORT(SCSISIG, 0);
- SETPORT(SCSIRATE, 0);
+ SETRATE(0);
/* clear all interrupt conditions */
SETPORT(SSTAT0, 0x7f);
SETPORT(BRSTCNTRL, 0xf1);
- /* clear SCSI fifo and transfer count */
- SETPORT(SXFRCTL0, CH1 | CLRCH1 | CLRSTCNT);
+ /* clear SCSI fifos and transfer count */
+ SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
SETPORT(SXFRCTL0, CH1);
- /* enable interrupts */
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+ DO_LOCK(flags);
+ setup_expected_interrupts(shpnt);
+ DO_UNLOCK(flags);
}
/*
- * Reset registers, reset a hanging bus and
- * kill active and disconnected commands for target w/o soft reset
+ * Reset the host (bus and controller)
+ *
*/
-int aha152x_reset(Scsi_Cmnd * SCpnt, unsigned int unused)
+int aha152x_host_reset(Scsi_Cmnd * SCpnt)
{
struct Scsi_Host *shpnt = SCpnt->host;
- unsigned long flags;
- Scsi_Cmnd *ptr, *prev, *next;
- aha152x_reset_ports(shpnt);
+ DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt);
- /* Reset, if bus hangs */
- if (TESTLO(SSTAT1, BUSFREE)) {
- CLRBITS(DMACNTRL0, INTEN);
+ aha152x_bus_reset(SCpnt);
-#if defined(DEBUG_RESET)
- if (HOSTDATA(shpnt)->debug & debug_reset) {
- printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
- show_queues(shpnt);
- }
-#endif
+ DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt));
+ reset_ports(SCpnt->host);
- ptr = CURRENT_SC;
- if (ptr && !ptr->device->soft_reset) {
- ptr->host_scribble = NULL;
- ptr->result = DID_RESET << 16;
- ptr->scsi_done(CURRENT_SC);
- CURRENT_SC = NULL;
- }
- save_flags(flags);
- cli();
- prev = NULL;
- ptr = DISCONNECTED_SC;
- while (ptr) {
- if (!ptr->device->soft_reset) {
- if (prev)
- prev->host_scribble = ptr->host_scribble;
- else
- DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
-
- next = (Scsi_Cmnd *) ptr->host_scribble;
-
- ptr->host_scribble = NULL;
- ptr->result = DID_RESET << 16;
- spin_lock_irqsave(&io_request_lock, flags);
- ptr->scsi_done(ptr);
- spin_unlock_irqrestore(&io_request_lock, flags);
-
- ptr = next;
- } else {
- prev = ptr;
- ptr = (Scsi_Cmnd *) ptr->host_scribble;
- }
- }
- restore_flags(flags);
-
-#if defined(DEBUG_RESET)
- if (HOSTDATA(shpnt)->debug & debug_reset) {
- printk("commands on targets w/ soft-resets:\n");
- show_queues(shpnt);
- }
-#endif
-
- /* RESET OUT */
- SETPORT(SCSISEQ, SCSIRSTO);
- do_pause(30);
- SETPORT(SCSISEQ, 0);
- do_pause(DELAY);
-
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-
- SETPORT(DMACNTRL0, INTEN);
- }
- return SCSI_RESET_SUCCESS;
+ return SUCCESS;
}
/*
* Return the "logical geometry"
+ *
*/
int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
{
struct Scsi_Host *shpnt = disk->device->host;
-#if defined(DEBUG_BIOSPARAM)
- if (HOSTDATA(shpnt)->debug & debug_biosparam)
- printk("aha152x_biosparam: dev=%s, size=%d, ",
- kdevname(dev), disk->capacity);
-#endif
-
/* try default translation */
info_array[0] = 64;
info_array[1] = 32;
if (scsicam_bios_param(disk, dev, info) < 0 ||
!((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
if (EXT_TRANS) {
- printk("aha152x: unable to verify geometry for disk with >1GB.\n"
- " using extended translation.\n");
+ printk(KERN_NOTICE
+ "aha152x: unable to verify geometry for disk with >1GB.\n"
+ " using extended translation.\n");
info_array[0] = 255;
info_array[1] = 63;
info_array[2] = disk->capacity / (255 * 63);
} else {
- printk("aha152x: unable to verify geometry for disk with >1GB.\n"
+ printk(KERN_NOTICE
+ "aha152x: unable to verify geometry for disk with >1GB.\n"
" Using default translation. Please verify yourself.\n"
" Perhaps you need to enable extended translation in the driver.\n"
- " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n");
+ " See /usr/src/linux/drivers/scsi/README.aha152x for details.\n");
}
} else {
info_array[0] = info[0];
info_array[2] = info[2];
if (info[0] == 255 && !EXT_TRANS) {
- printk("aha152x: current partition table is using extended translation.\n"
- " using it also, although it's not explicty enabled.\n");
+ printk(KERN_NOTICE
+ "aha152x: current partition table is using extended translation.\n"
+ " using it also, although it's not explictly enabled.\n");
}
}
}
-#if defined(DEBUG_BIOSPARAM)
- if (HOSTDATA(shpnt)->debug & debug_biosparam) {
- printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
- info_array[0], info_array[1], info_array[2]);
- printk("WARNING: check, if the bios geometry is correct.\n");
- }
-#endif
return 0;
}
/*
* Internal done function
+ *
*/
-void aha152x_done(struct Scsi_Host *shpnt, int error)
+static void done(struct Scsi_Host *shpnt, int error)
{
- unsigned long flags;
- Scsi_Cmnd *done_SC;
-
-#if defined(DEBUG_DONE)
- if (HOSTDATA(shpnt)->debug & debug_done) {
- printk("\naha152x: done(), ");
- disp_ports(shpnt);
- }
-#endif
-
if (CURRENT_SC) {
-#if defined(DEBUG_DONE)
- if (HOSTDATA(shpnt)->debug & debug_done)
- printk("done(%x), ", error);
-#endif
+ if(DONE_SC)
+ printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC);
- save_flags(flags);
- cli();
-
- done_SC = CURRENT_SC;
- CURRENT_SC = NULL;
-
- /* turn led off, when no commands are in the driver */
- HOSTDATA(shpnt)->commands--;
- if (!HOSTDATA(shpnt)->commands)
- SETPORT(PORTA, 0); /* turn led off */
-
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("ok (%d), ", HOSTDATA(shpnt)->commands);
-#endif
- restore_flags(flags);
-
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
-
-#if 0
-/* Why poll for the BUS FREE phase, when we have setup the interrupt!? */
-#if defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & debug_phases)
- printk("BUS FREE loop, ");
-#endif
- while (TESTLO(SSTAT1, BUSFREE))
- barrier();
-#if defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & debug_phases)
- printk("BUS FREE\n");
-#endif
-#endif
-
- done_SC->result = error;
- if (done_SC->scsi_done) {
-#if defined(DEBUG_DONE)
- if (HOSTDATA(shpnt)->debug & debug_done)
- printk("calling scsi_done, ");
-#endif
- spin_lock_irqsave(&io_request_lock, flags);
- done_SC->scsi_done(done_SC);
- spin_unlock_irqrestore(&io_request_lock, flags);
-#if defined(DEBUG_DONE)
- if (HOSTDATA(shpnt)->debug & debug_done)
- printk("done returned, ");
-#endif
- } else
- panic("aha152x: current_SC->scsi_done() == NULL");
+ DONE_SC = CURRENT_SC;
+ CURRENT_SC = 0;
+ DONE_SC->result = error;
} else
- aha152x_panic(shpnt, "done() called outside of command");
+ printk(KERN_ERR "aha152x: done() called outside of command\n");
}
-
-static void aha152x_complete(struct Scsi_Host *);
-
static struct tq_struct aha152x_tq;
/*
- * Run service completions on the card with interrupts enabled.
+ * Run service completions on the card with interrupts enabled.
+ *
*/
-
-static void aha152x_run(void)
+static void run(void)
{
int i;
for (i = 0; i < IRQS; i++) {
struct Scsi_Host *shpnt = aha152x_host[i];
if (shpnt && HOSTDATA(shpnt)->service) {
- HOSTDATA(shpnt)->service = 0;
- aha152x_complete(shpnt);
+ HOSTDATA(shpnt)->service=0;
+ complete(shpnt);
}
}
}
/*
- * Interrupts handler (main routine of the driver)
+ * Interrupts handler
+ *
*/
-static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs)
+static void intr(int irqno, void *dev_id, struct pt_regs *regs)
{
struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN];
-#if defined(DEBUG_RACE)
- enter_driver("intr");
-#else
-#if defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & debug_intr)
- printk("\naha152x: intr(), ");
-#endif
-#endif
-
- if (!shpnt)
- panic("aha152x: catched interrupt for unknown controller.\n");
+ if (!shpnt) {
+ printk(KERN_ERR "aha152x: catched interrupt for unknown controller.\n");
+ return;
+ }
/* no more interrupts from the controller, while we're busy.
INTEN is restored by the BH handler */
-
CLRBITS(DMACNTRL0, INTEN);
+#if 0
+ /* check if there is already something to be
+ serviced; should not happen */
+ if(HOSTDATA(shpnt)->service) {
+ printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service);
+ show_queues(shpnt);
+ }
+#endif
+
/* Poke the BH handler */
-
- HOSTDATA(shpnt)->service = 1;
- aha152x_tq.routine = (void *) aha152x_run;
+ HOSTDATA(shpnt)->service++;
+ aha152x_tq.routine = (void *) run;
queue_task(&aha152x_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
-static void aha152x_complete(struct Scsi_Host *shpnt)
+/*
+ * busfree phase
+ * - handle completition/disconnection/error of current command
+ * - start selection for next command (if any)
+ */
+static void busfree_run(struct Scsi_Host *shpnt)
{
- unsigned int flags;
- int done = 0, phase;
+ unsigned long flags;
+#if defined(AHA152X_STAT)
+ int action=0;
+#endif
- /* disconnected target is trying to reconnect.
- Only possible, if we have disconnected nexuses and
- nothing is occupying the bus.
- */
+ SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+ SETPORT(SXFRCTL0, CH1);
- if (TESTHI(SSTAT0, SELDI) &&
- DISCONNECTED_SC &&
- (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) {
- int identify_msg, target, i;
-
- /* Avoid conflicts when a target reconnects
- while we are trying to connect to another. */
- if (CURRENT_SC) {
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("i+, ");
+ SETPORT(SSTAT1, CLRBUSFREE);
+
+ if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+ action++;
#endif
- save_flags(flags);
- cli();
- append_SC(&ISSUE_SC, CURRENT_SC);
- CURRENT_SC = NULL;
- restore_flags(flags);
- }
- /* disable sequences */
- SETPORT(SCSISEQ, 0);
- SETPORT(SSTAT0, CLRSELDI);
- SETPORT(SSTAT1, CLRBUSFREE);
-
-#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases))
- printk("reselected, ");
+ CURRENT_SC->SCp.phase &= ~syncneg;
+
+ if(CURRENT_SC->SCp.phase & completed) {
+ /* target sent COMMAND COMPLETE */
+ done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
+
+ } else if(CURRENT_SC->SCp.phase & aborted) {
+ DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC));
+ done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
+
+ } else if(CURRENT_SC->SCp.phase & resetted) {
+ DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC));
+ done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
+
+ } else if(CURRENT_SC->SCp.phase & disconnected) {
+ /* target sent DISCONNECT */
+ DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
+ CMDINFO(CURRENT_SC),
+ CURRENT_SC->resid,
+ CURRENT_SC->request_bufflen);
+#if defined(AHA152X_STAT)
+ HOSTDATA(shpnt)->disconnections++;
#endif
+ append_SC(&DISCONNECTED_SC, CURRENT_SC);
+ CURRENT_SC->SCp.phase |= 1 << 16;
+ CURRENT_SC = 0;
- i = GETPORT(SELID) & ~(1 << shpnt->this_id);
- target = 0;
+ } else {
+ done(shpnt, DID_ERROR << 16);
+ }
+#if defined(AHA152X_STAT)
+ } else {
+ HOSTDATA(shpnt)->busfree_without_old_command++;
+#endif
+ }
- if (i == 0)
- aha152x_panic(shpnt, "reconnecting target unknown");
+ DO_LOCK(flags);
- for (; (i & 1) == 0; target++, i >>= 1);
+ if(DONE_SC) {
+#if defined(AHA152X_STAT)
+ action++;
+#endif
+ if(SCDONE(DONE_SC)) {
+ Scsi_Cmnd *ptr=DONE_SC;
+ DONE_SC=SCDONE(DONE_SC);
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);
+#if 0
+ if(HOSTDATA(shpnt)->debug & debug_eh) {
+ printk(ERR_LEAD "received sense: ", CMDINFO(ptr));
+ print_sense("bh", DONE_SC);
+ }
#endif
- SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
- SETPORT(SCSISEQ, ENRESELI);
- if (TESTLO(SSTAT0, SELDI))
- aha152x_panic(shpnt, "RESELI failed");
+ HOSTDATA(shpnt)->commands--;
+ if (!HOSTDATA(shpnt)->commands)
+ SETPORT(PORTA, 0); /* turn led off */
- SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f);
+ kfree(ptr->host_scribble);
+ kfree(ptr);
+ } else if(DONE_SC->SCp.Status==0x02) {
+#if defined(AHA152X_STAT)
+ HOSTDATA(shpnt)->busfree_with_check_condition++;
+#endif
+#if 0
+ DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
+#endif
+
+ if(!(DONE_SC->SCp.Status & not_issued)) {
+ Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
- SETPORT(SCSISIG, P_MSGI);
+ if(cmnd) {
+ Scsi_Cmnd *ptr=DONE_SC;
+ DONE_SC=0;
- /* Get identify message */
- if ((i = getphase(shpnt)) != P_MSGI) {
- printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
- aha152x_panic(shpnt, "unknown lun");
+#if 0
+ DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
+#endif
+
+ cmnd->cmnd[0] = REQUEST_SENSE;
+ cmnd->cmnd[1] = 0;
+ cmnd->cmnd[2] = 0;
+ cmnd->cmnd[3] = 0;
+ cmnd->cmnd[4] = sizeof(ptr->sense_buffer);
+ cmnd->cmnd[5] = 0;
+ cmnd->cmd_len = 6;
+ cmnd->host = ptr->host;
+ cmnd->target = ptr->target;
+ cmnd->lun = ptr->lun;
+ cmnd->use_sg = 0;
+ cmnd->request_buffer = ptr->sense_buffer;
+ cmnd->request_bufflen = sizeof(ptr->sense_buffer);
+
+ DO_UNLOCK(flags);
+ aha152x_internal_queue(cmnd, 0, 0, ptr, internal_done);
+ DO_LOCK(flags);
+ } else {
+ printk(ERR_LEAD "allocation failed\n", CMDINFO(CURRENT_SC));
+ if(cmnd)
+ kfree(cmnd);
+ }
+ } else {
+#if 0
+ DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC));
+#endif
+ }
}
- SETPORT(SCSISEQ, 0);
- SETPORT(SXFRCTL0, CH1);
+ if(DONE_SC && DONE_SC->scsi_done) {
+ /* turn led off, when no commands are in the driver */
+ HOSTDATA(shpnt)->commands--;
+ if (!HOSTDATA(shpnt)->commands)
+ SETPORT(PORTA, 0); /* turn led off */
- identify_msg = GETPORT(SCSIBUS);
+ kfree(DONE_SC->host_scribble);
+ DONE_SC->host_scribble=0;
- if (!(identify_msg & IDENTIFY_BASE)) {
- printk("target=%d, inbound message (%02x) != IDENTIFY\n",
- target, identify_msg);
- aha152x_panic(shpnt, "unknown lun");
+ DO_UNLOCK(flags);
+ DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC);
+ DONE_SC->scsi_done(DONE_SC);
+ DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC);
+ DO_LOCK(flags);
}
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);
+
+ DONE_SC=0;
+#if defined(AHA152X_STAT)
+ } else {
+ HOSTDATA(shpnt)->busfree_without_done_command++;
#endif
+ }
+
+ if(ISSUE_SC)
+ CURRENT_SC = remove_first_SC(&ISSUE_SC);
- save_flags(flags);
- cli();
+ DO_UNLOCK(flags);
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("d-, ");
+ if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+ action++;
#endif
- CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f);
+ CURRENT_SC->SCp.phase |= selecting;
- if (!CURRENT_SC) {
- printk("lun=%d, ", identify_msg & 0x3f);
- aha152x_panic(shpnt, "no disconnected command for that lun");
- }
- CURRENT_SC->SCp.phase &= ~disconnected;
- restore_flags(flags);
-
- make_acklow(shpnt);
- if (getphase(shpnt) != P_MSGI) {
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-#if defined(DEBUG_RACE)
- leave_driver("(reselected) intr");
+ DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC));
+
+ /* clear selection timeout */
+ SETPORT(SSTAT1, SELTO);
+
+ SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+ SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
+ SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
+ } else {
+#if defined(AHA152X_STAT)
+ HOSTDATA(shpnt)->busfree_without_new_command++;
#endif
- SETBITS(DMACNTRL0, INTEN);
- return;
- }
+ SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
}
- /* Check, if we aren't busy with a command */
- if (!CURRENT_SC) {
- /* bus is free to issue a queued command */
- if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) {
- save_flags(flags);
- cli();
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("i-, ");
-#endif
- CURRENT_SC = remove_first_SC(&ISSUE_SC);
- restore_flags(flags);
-#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
- printk("issuing command, ");
+#if defined(AHA152X_STAT)
+ if(!action)
+ HOSTDATA(shpnt)->busfree_without_any_action++;
#endif
- CURRENT_SC->SCp.phase = in_selection;
+}
-#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases))
- printk("selecting %d, ", CURRENT_SC->target);
-#endif
- SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+/*
+ * Selection done (OUT)
+ * - queue IDENTIFY message and SDTR to selected target for message out
+ * (ATN asserted automagically via ENAUTOATNO in busfree())
+ */
+static void seldo_run(struct Scsi_Host *shpnt)
+{
+ SETPORT(SCSISIG, 0);
+ SETPORT(SSTAT1, CLRBUSFREE);
+ SETPORT(SSTAT1, CLRPHASECHG);
- /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
- SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER);
+ CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
- /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
- SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
- SETPORT(SIMODE1, ENSELTIMO);
+ SETPORT(SCSISEQ, 0);
- /* Enable SELECTION OUT sequence */
- SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+ if (TESTLO(SSTAT0, SELDO)) {
+ printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC));
+ done(shpnt, DID_NO_CONNECT << 16);
+ return;
+ }
- } else {
- /* No command we are busy with and no new to issue */
- printk("aha152x: ignoring spurious interrupt, nothing to do\n");
- if (TESTHI(DMACNTRL0, SWINT)) {
- printk("aha152x: SWINT is set! Why?\n");
- CLRBITS(DMACNTRL0, SWINT);
- }
- show_queues(shpnt);
- }
+ SETPORT(SSTAT0, CLRSELDO);
+
+ ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun));
+
+ if (CURRENT_SC->SCp.phase & aborting) {
+ ADDMSGO(ABORT);
+ } else if (CURRENT_SC->SCp.phase & resetting) {
+ ADDMSGO(BUS_DEVICE_RESET);
+ } else if (SYNCNEG==0 && SYNCHRONOUS) {
+ CURRENT_SC->SCp.phase |= syncneg;
+ ADDMSGO(EXTENDED_MESSAGE);
+ ADDMSGO(3);
+ ADDMSGO(EXTENDED_SDTR);
+ ADDMSGO(50); /* 200ns */
+ ADDMSGO(8); /* 8 byte req/ack offset */
+
+ SYNCNEG=1; /* negotiation in progress */
+ }
-#if defined(DEBUG_RACE)
- leave_driver("(selecting) intr");
-#endif
- SETBITS(DMACNTRL0, INTEN);
+ SETRATE(SYNCRATE);
+}
+
+/*
+ * Selection timeout
+ * - return command to mid-level with failure cause
+ *
+ */
+static void selto_run(struct Scsi_Host *shpnt)
+{
+ SETPORT(SCSISEQ, 0);
+ SETPORT(SSTAT1, CLRSELTIMO);
+
+ DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC));
+
+ if(!CURRENT_SC) {
+ DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC));
return;
}
- /* the bus is busy with something */
-#if defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & debug_intr)
- disp_ports(shpnt);
-#endif
+ CURRENT_SC->SCp.phase &= ~selecting;
- /* we are waiting for the result of a selection attempt */
- if (CURRENT_SC->SCp.phase & in_selection) {
- if (TESTLO(SSTAT1, SELTO)) {
- /* no timeout */
- if (TESTHI(SSTAT0, SELDO)) {
- /* clear BUS FREE interrupt */
- SETPORT(SSTAT1, CLRBUSFREE);
-
- /* Disable SELECTION OUT sequence */
- CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+ if (CURRENT_SC->SCp.phase & aborted) {
+ DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC));
+ done(shpnt, DID_ABORT << 16);
+ } else if (TESTLO(SSTAT0, SELINGO)) {
+ DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC));
+ done(shpnt, DID_BUS_BUSY << 16);
+ } else {
+ /* ARBITRATION won, but SELECTION failed */
+ DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC));
+ done(shpnt, DID_NO_CONNECT << 16);
+ }
+}
- /* Disable SELECTION OUT DONE interrupt */
- CLRBITS(SIMODE0, ENSELDO);
- CLRBITS(SIMODE1, ENSELTIMO);
+/*
+ * Selection in done
+ * - put current command back to issue queue
+ * (reconnection of a disconnected nexus instead
+ * of successful selection out)
+ *
+ */
+static void seldi_run(struct Scsi_Host *shpnt)
+{
+ int selid;
+ int target;
+ unsigned long flags;
- if (TESTLO(SSTAT0, SELDO)) {
- printk("aha152x: passing bus free condition\n");
+ SETPORT(SCSISIG, 0);
+ SETPORT(SSTAT0, CLRSELDI);
+ SETPORT(SSTAT1, CLRBUSFREE);
+ SETPORT(SSTAT1, CLRPHASECHG);
-#if defined(DEBUG_RACE)
- leave_driver("(passing bus free) intr");
-#endif
- SETBITS(DMACNTRL0, INTEN);
+ if(CURRENT_SC) {
+ if(!(CURRENT_SC->SCp.phase & not_issued))
+ printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC));
- if (CURRENT_SC->SCp.phase & aborted) {
- HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
- HOSTDATA(shpnt)->abortion_complete++;
- }
- aha152x_done(shpnt, DID_NO_CONNECT << 16);
+ DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC));
- return;
- }
-#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
- printk("SELDO (SELID=%x), ", GETPORT(SELID));
-#endif
+ DO_LOCK(flags);
+ append_SC(&ISSUE_SC, CURRENT_SC);
+ DO_UNLOCK(flags);
- /* selection was done */
- SETPORT(SSTAT0, CLRSELDO);
+ CURRENT_SC = 0;
+ }
-#if defined(DEBUG_ABORT)
- if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted))
- printk("(ABORT) target selected, ");
-#endif
+ if(!DISCONNECTED_SC) {
+ DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC));
+ return;
+ }
- CURRENT_SC->SCp.phase &= ~in_selection;
- CURRENT_SC->SCp.phase |= in_other;
+ RECONN_TARGET=-1;
- ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun));
+ selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
- if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) {
- ADDMSG(EXTENDED_MESSAGE);
- ADDMSG(3);
- ADDMSG(EXTENDED_SDTR);
- ADDMSG(50);
- ADDMSG(8);
+ if (selid==0) {
+ printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid);
+ return;
+ }
- printk("outbound SDTR: ");
- print_msg(&MSG(MSGLEN - 5));
+ for(target=7; !(selid & (1 << target)); target--)
+ ;
- SYNCRATE = 0x80;
- CURRENT_SC->SCp.phase |= in_sync;
- }
-#if defined(DEBUG_RACE)
- leave_driver("(SELDO) intr");
-#endif
- SETPORT(SCSIRATE, SYNCRATE & 0x7f);
+ if(selid & ~(1 << target)) {
+ printk("aha152x%d: multiple targets reconnected (%02x)\n",
+ HOSTNO, selid);
+ }
- SETPORT(SCSISIG, P_MSGO);
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
- SETBITS(DMACNTRL0, INTEN);
+ SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
+ SETPORT(SCSISEQ, 0);
- return;
- } else
- aha152x_panic(shpnt, "neither timeout nor selection\007");
- } else {
-#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases))
- printk("SELTO, ");
-#endif
- /* end selection attempt */
- CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO);
+ SETRATE(HOSTDATA(shpnt)->syncrate[target]);
- /* timeout */
- SETPORT(SSTAT1, CLRSELTIMO);
+ RECONN_TARGET=target;
+ DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid);
+}
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
- SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
- leave_driver("(SELTO) intr");
-#endif
+/*
+ * message in phase
+ * - handle initial message after reconnection to identify
+ * reconnecting nexus
+ * - queue command on DISCONNECTED_SC on DISCONNECT message
+ * - set completed flag on COMMAND COMPLETE
+ * (other completition code moved to busfree_run)
+ * - handle response to SDTR
+ * - clear synchronous transfer agreements on BUS RESET
+ *
+ * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
+ *
+ */
+static void msgi_run(struct Scsi_Host *shpnt)
+{
+ for(;;) {
+ int sstat1 = GETPORT(SSTAT1);
- if (CURRENT_SC->SCp.phase & aborted) {
-#if defined(DEBUG_ABORT)
- if (HOSTDATA(shpnt)->debug & debug_abort)
- printk("(ABORT) selection timeout, ");
-#endif
- HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR;
- HOSTDATA(shpnt)->abortion_complete++;
- }
- if (TESTLO(SSTAT0, SELINGO))
- /* ARBITRATION not won */
- aha152x_done(shpnt, DID_BUS_BUSY << 16);
- else
- /* ARBITRATION won, but SELECTION failed */
- aha152x_done(shpnt, DID_NO_CONNECT << 16);
+ if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
+ return;
+ if(TESTLO(SSTAT0,SPIORDY)) {
+ DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
return;
+ }
+
+ ADDMSGI(GETPORT(SCSIDAT));
+
+#if defined(AHA152X_DEBUG)
+ if (HOSTDATA(shpnt)->debug & debug_msgi) {
+ printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0));
+ print_msg(&MSGI(0));
+ printk("\n");
}
- }
- /* enable interrupt, when target leaves current phase */
- phase = getphase(shpnt);
- if (!(phase & ~P_MASK)) /* "real" phase */
- SETPORT(SCSISIG, phase);
- SETPORT(SSTAT1, CLRPHASECHG);
- CURRENT_SC->SCp.phase =
- (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16);
-
- /* information transfer phase */
- switch (phase) {
- case P_MSGO: /* MESSAGE OUT */
- {
- int i, identify = 0, abort = 0;
-
-#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases))
- printk("MESSAGE OUT, ");
#endif
- if (MSGLEN == 0) {
- ADDMSG(MESSAGE_REJECT);
-#if defined(DEBUG_MSGO)
- if (HOSTDATA(shpnt)->debug & debug_msgo)
- printk("unexpected MESSAGE OUT phase; rejecting, ");
-#endif
- }
- CLRBITS(SXFRCTL0, ENDMA);
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+ if(!CURRENT_SC) {
+ if(LASTSTATE!=seldi) {
+ printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO);
+ }
- /* wait for data latch to become ready or a phase change */
- while (TESTLO(DMASTAT, INTSTAT))
- barrier();
+ /*
+ * Handle reselection
+ */
+ if(!(MSGI(0) & IDENTIFY_BASE)) {
+ printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO);
+ continue;
+ }
-#if defined(DEBUG_MSGO)
- if (HOSTDATA(shpnt)->debug & debug_msgo) {
- int i;
+ CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
- printk("messages (");
- for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" "));
- printk("), ");
+ if (!CURRENT_SC) {
+ show_queues(shpnt);
+ printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f);
+ continue;
}
-#endif
- for (i = 0; i < MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++) {
-#if defined(DEBUG_MSGO)
- if (HOSTDATA(shpnt)->debug & debug_msgo)
- printk("%x ", MSG(i));
-#endif
- if (i == MSGLEN - 1) {
- /* Leave MESSAGE OUT after transfer */
- SETPORT(SSTAT1, CLRATNO);
- }
- SETPORT(SCSIDAT, MSG(i));
+ DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC));
- make_acklow(shpnt);
- getphase(shpnt);
+ CURRENT_SC->SCp.Message = MSGI(0);
+ CURRENT_SC->SCp.phase &= ~disconnected;
- if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun))
- identify++;
+ MSGILEN=0;
- if (MSG(i) == ABORT)
- abort++;
+ /* next message if any */
+ continue;
+ }
- }
+ CURRENT_SC->SCp.Message = MSGI(0);
- MSGLEN = 0;
+ switch (MSGI(0)) {
+ case DISCONNECT:
+ if (!RECONNECT)
+ printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC));
- if (identify)
- CURRENT_SC->SCp.phase |= sent_ident;
+ CURRENT_SC->SCp.phase |= disconnected;
+ break;
- if (abort) {
- /* revive abort(); abort() enables interrupts */
- HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS;
- HOSTDATA(shpnt)->abortion_complete++;
+ case COMMAND_COMPLETE:
+ if(CURRENT_SC->SCp.phase & completed)
+ DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC));
- CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
+ CURRENT_SC->SCp.phase |= completed;
+ break;
- /* exit */
- SETBITS(DMACNTRL0, INTEN);
-#if defined(DEBUG_RACE)
- leave_driver("(ABORT) intr");
-#endif
- aha152x_done(shpnt, DID_ABORT << 16);
+ case MESSAGE_REJECT:
+ if (SYNCNEG==1) {
+ printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+ SYNCNEG=2; /* negotiation completed */
+ } else
+ printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC));
+ break;
- return;
- }
- }
- break;
+ case SAVE_POINTERS:
+ break;
- case P_CMD: /* COMMAND phase */
-#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_intr | debug_cmd | debug_phases))
- printk("COMMAND, ");
-#endif
- if (!(CURRENT_SC->SCp.sent_command)) {
- int i;
+ case RESTORE_POINTERS:
+ break;
- CLRBITS(SXFRCTL0, ENDMA);
+ case EXTENDED_MESSAGE:
+ if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
+ /* not yet completed */
+ continue;
+ }
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE);
+ switch (MSGI(2)) {
+ case EXTENDED_SDTR:
+ {
+ long ticks;
- /* wait for data latch to become ready or a phase change */
- while (TESTLO(DMASTAT, INTSTAT))
- barrier();
+ if (MSGI(1) != 3) {
+ printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC));
+ break;
+ }
- for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) {
- SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]);
+ if (!HOSTDATA(shpnt)->synchronous)
+ break;
- make_acklow(shpnt);
- getphase(shpnt);
- }
+ printk(INFO_LEAD, CMDINFO(CURRENT_SC));
+ print_msg(&MSGI(0));
+ printk("\n");
- if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS))
- aha152x_panic(shpnt, "target left COMMAND");
+ ticks = (MSGI(3) * 4 + 49) / 50;
- CURRENT_SC->SCp.sent_command++;
- } else
- aha152x_panic(shpnt, "Nothing to send while in COMMAND");
- break;
+ if (syncneg) {
+ /* negotiation in progress */
+ if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
+ ADDMSGO(MESSAGE_REJECT);
+ printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC));
+ break;
+ }
+
+ SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+ } else if (ticks <= 9 && MSGI(4) >= 1) {
+ ADDMSGO(EXTENDED_MESSAGE);
+ ADDMSGO(3);
+ ADDMSGO(EXTENDED_SDTR);
+ if (ticks < 4) {
+ ticks = 4;
+ ADDMSGO(50);
+ } else
+ ADDMSGO(MSGI(3));
+
+ if (MSGI(4) > 8)
+ MSGI(4) = 8;
+
+ ADDMSGO(MSGI(4));
+
+ SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+ } else {
+ /* requested SDTR is too slow, do it asynchronously */
+ printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC));
+ ADDMSGO(MESSAGE_REJECT);
+ }
- case P_MSGI: /* MESSAGE IN phase */
- {
- int start_sync = 0;
+ SYNCNEG=2; /* negotiation completed */
+ SETRATE(SYNCRATE);
+ }
+ break;
-#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgi | debug_phases))
- printk("MESSAGE IN, ");
-#endif
- SETPORT(SXFRCTL0, CH1);
+ case BUS_DEVICE_RESET:
+ {
+ int i;
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENBUSFREE);
+ for(i=0; i<8; i++) {
+ HOSTDATA(shpnt)->syncrate[i]=0;
+ HOSTDATA(shpnt)->syncneg[i]=0;
+ }
- while (phase == P_MSGI) {
- CURRENT_SC->SCp.Message = GETPORT(SCSIDAT);
- switch (CURRENT_SC->SCp.Message) {
- case DISCONNECT:
-#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
- printk("target disconnected, ");
-#endif
- CURRENT_SC->SCp.Message = 0;
- CURRENT_SC->SCp.phase |= disconnected;
- if (!HOSTDATA(shpnt)->reconnect)
- aha152x_panic(shpnt, "target was not allowed to disconnect");
+ }
+ break;
+
+ case EXTENDED_MODIFY_DATA_POINTER:
+ case EXTENDED_EXTENDED_IDENTIFY:
+ case EXTENDED_WDTR:
+ default:
+ ADDMSGO(MESSAGE_REJECT);
+ break;
+ }
+ break;
+ }
- break;
+ MSGILEN=0;
+ }
+}
- case COMMAND_COMPLETE:
-#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases))
- printk("inbound message (COMMAND COMPLETE), ");
-#endif
- done++;
- break;
-
- case MESSAGE_REJECT:
- if (CURRENT_SC->SCp.phase & in_sync) {
- CURRENT_SC->SCp.phase &= ~in_sync;
- SYNCRATE = 0x80;
- printk("synchronous rejected, ");
- } else
- printk("inbound message (MESSAGE REJECT), ");
-#if defined(DEBUG_MSGI)
- if (HOSTDATA(shpnt)->debug & debug_msgi)
- printk("inbound message (MESSAGE REJECT), ");
-#endif
- break;
+static void msgi_end(struct Scsi_Host *shpnt)
+{
+ if(MSGILEN>0)
+ printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN);
- case SAVE_POINTERS:
-#if defined(DEBUG_MSGI)
- if (HOSTDATA(shpnt)->debug & debug_msgi)
- printk("inbound message (SAVE DATA POINTERS), ");
-#endif
- break;
+ if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) {
+ DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC));
+ SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
+ }
+}
- case RESTORE_POINTERS:
-#if defined(DEBUG_MSGI)
- if (HOSTDATA(shpnt)->debug & debug_msgi)
- printk("inbound message (RESTORE DATA POINTERS), ");
-#endif
- break;
+/*
+ * message out phase
+ *
+ */
+static void msgo_init(struct Scsi_Host *shpnt)
+{
+ if(MSGOLEN==0) {
+ if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
+ ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun));
+ } else {
+ printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC));
+ ADDMSGO(MESSAGE_REJECT);
+ }
+ }
- case EXTENDED_MESSAGE:
- {
- char buffer[16];
- int i;
+#if defined(AHA152X_DEBUG)
+ if(HOSTDATA(shpnt)->debug & debug_msgo) {
+ int i;
-#if defined(DEBUG_MSGI)
- if (HOSTDATA(shpnt)->debug & debug_msgi)
- printk("inbound message (EXTENDED MESSAGE), ");
+ printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
+ for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" "))
+ ;
+ printk(")\n");
+ }
#endif
- make_acklow(shpnt);
- if (getphase(shpnt) != P_MSGI)
- break;
-
- buffer[0] = EXTENDED_MESSAGE;
- buffer[1] = GETPORT(SCSIDAT);
+}
- for (i = 0; i < buffer[1] &&
- (make_acklow(shpnt), getphase(shpnt) == P_MSGI); i++)
- buffer[2 + i] = GETPORT(SCSIDAT);
+/*
+ * message out phase
+ *
+ */
+static void msgo_run(struct Scsi_Host *shpnt)
+{
+ if(MSGO_I==MSGOLEN)
+ DPRINTK(debug_msgo, DEBUG_LEAD "messages all sent (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
-#if defined(DEBUG_MSGI)
- if (HOSTDATA(shpnt)->debug & debug_msgi)
- print_msg(buffer);
-#endif
+ while(MSGO_I<MSGOLEN) {
+ DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN);
- switch (buffer[2]) {
- case EXTENDED_SDTR:
- {
- long ticks;
+ if(TESTLO(SSTAT0, SPIORDY)) {
+ DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ return;
+ }
- if (buffer[1] != 3)
- aha152x_panic(shpnt, "SDTR message length != 3");
+ if (MSGO_I==MSGOLEN-1) {
+ /* Leave MESSAGE OUT after transfer */
+ SETPORT(SSTAT1, CLRATNO);
+ }
- if (!HOSTDATA(shpnt)->synchronous)
- break;
- printk("inbound SDTR: ");
- print_msg(buffer);
+ if (MSGO(MSGO_I) & IDENTIFY_BASE)
+ CURRENT_SC->SCp.phase |= identified;
- ticks = (buffer[3] * 4 + 49) / 50;
+ if (MSGO(MSGO_I)==ABORT)
+ CURRENT_SC->SCp.phase |= aborted;
- if (CURRENT_SC->SCp.phase & in_sync) {
- /* we initiated SDTR */
- if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8)
- aha152x_panic(shpnt, "received SDTR invalid");
+ if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
+ CURRENT_SC->SCp.phase |= resetted;
- SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
- } else if (ticks <= 9 && buffer[4] >= 1) {
- if (buffer[4] > 8)
- buffer[4] = 8;
+ SETPORT(SCSIDAT, MSGO(MSGO_I++));
+ }
+}
- ADDMSG(EXTENDED_MESSAGE);
- ADDMSG(3);
- ADDMSG(EXTENDED_SDTR);
- if (ticks < 4) {
- ticks = 4;
- ADDMSG(50);
- } else
- ADDMSG(buffer[3]);
+static void msgo_end(struct Scsi_Host *shpnt)
+{
+ if(MSGO_I<MSGOLEN)
+ printk(ERR_LEAD "message sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+
+ MSGO_I = 0;
+ MSGOLEN = 0;
+}
- ADDMSG(buffer[4]);
+/*
+ * command phase
+ *
+ */
+static void cmd_init(struct Scsi_Host *shpnt)
+{
+ if (CURRENT_SC->SCp.sent_command) {
+ printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC));
+ done(shpnt, DID_ERROR << 16);
+ return;
+ }
- printk("outbound SDTR: ");
- print_msg(&MSG(MSGLEN - 5));
+#if defined(AHA152X_DEBUG)
+ if (HOSTDATA(shpnt)->debug & debug_cmd) {
+ printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
+ print_command(CURRENT_SC->cmnd);
+ }
+#endif
- CURRENT_SC->SCp.phase |= in_sync;
+ CMD_I=0;
+}
- SYNCRATE |= ((ticks - 2) << 4) + buffer[4];
+/*
+ * command phase
+ *
+ */
+static void cmd_run(struct Scsi_Host *shpnt)
+{
+ if(CMD_I==CURRENT_SC->cmd_len) {
+ DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+ disp_ports(shpnt);
+ }
- start_sync++;
- } else {
- /* requested SDTR is too slow, do it asynchronously */
- ADDMSG(MESSAGE_REJECT);
- SYNCRATE = 0;
- }
+ while(CMD_I<CURRENT_SC->cmd_len) {
+ DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len);
- SETPORT(SCSIRATE, SYNCRATE & 0x7f);
- }
- break;
+ if(TESTLO(SSTAT0, SPIORDY)) {
+ DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ return;
+ }
- case EXTENDED_MODIFY_DATA_POINTER:
- case EXTENDED_EXTENDED_IDENTIFY:
- case EXTENDED_WDTR:
- default:
- ADDMSG(MESSAGE_REJECT);
- break;
- }
- }
- break;
+ SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
+ }
+}
- default:
- printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message);
- break;
+static void cmd_end(struct Scsi_Host *shpnt)
+{
+ if(CMD_I<CURRENT_SC->cmd_len)
+ printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+ else
+ CURRENT_SC->SCp.sent_command++;
+}
- }
+/*
+ * status phase
+ *
+ */
+static void status_run(struct Scsi_Host *shpnt)
+{
+ if(TESTLO(SSTAT0,SPIORDY)) {
+ DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ return;
+ }
- make_acklow(shpnt);
- phase = getphase(shpnt);
- }
+ CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
- if (start_sync)
- CURRENT_SC->SCp.phase |= in_sync;
- else
- CURRENT_SC->SCp.phase &= ~in_sync;
+#if defined(AHA152X_DEBUG)
+ if (HOSTDATA(shpnt)->debug & debug_status) {
+ printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status);
+ print_status(CURRENT_SC->SCp.Status);
+ printk("\n");
+ }
+#endif
+}
- if (MSGLEN > 0)
- SETPORT(SCSISIG, P_MSGI | ATNO);
+/*
+ * data in phase
+ *
+ */
+static void datai_init(struct Scsi_Host *shpnt)
+{
+ SETPORT(DMACNTRL0, RSTFIFO);
+ SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
- /* clear SCSI fifo on BUSFREE */
- if (phase == P_BUSFREE)
- SETPORT(SXFRCTL0, CH1 | CLRCH1);
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+ SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
- if (CURRENT_SC->SCp.phase & disconnected) {
- save_flags(flags);
- cli();
-#if defined(DEBUG_QUEUES)
- if (HOSTDATA(shpnt)->debug & debug_queues)
- printk("d+, ");
-#endif
- append_SC(&DISCONNECTED_SC, CURRENT_SC);
- CURRENT_SC->SCp.phase |= 1 << 16;
- CURRENT_SC = NULL;
- restore_flags(flags);
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
- SETBITS(SCSISEQ, ENRESELI);
+ DATA_LEN=0;
+ DPRINTK(debug_datai,
+ DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
+ CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+static void datai_run(struct Scsi_Host *shpnt)
+{
+ unsigned int the_time;
+ int fifodata, data_count;
- SETBITS(DMACNTRL0, INTEN);
+ /*
+ * loop while the phase persists or the fifos are not empty
+ *
+ */
+ while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
+ /* FIXME: maybe this should be done by setting up
+ * STCNT to trigger ENSWRAP interrupt, instead of
+ * polling for DFIFOFULL
+ */
+ the_time=jiffies + 100;
+ while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
+ barrier();
- return;
- }
+ if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
+ printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ break;
}
- break;
-
- case P_STATUS: /* STATUS IN phase */
-#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_status | debug_intr | debug_phases))
- printk("STATUS, ");
-#endif
- SETPORT(SXFRCTL0, CH1);
-
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENREQINIT | ENBUSFREE);
- if (TESTHI(SSTAT1, PHASEMIS))
- printk("aha152x: passing STATUS phase");
+ if(TESTHI(DMASTAT, DFIFOFULL)) {
+ fifodata = 128;
+ } else {
+ the_time=jiffies + 100;
+ while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
+ barrier();
- CURRENT_SC->SCp.Status = GETPORT(SCSIBUS);
- make_acklow(shpnt);
- getphase(shpnt);
+ if(TESTLO(SSTAT2, SEMPTY)) {
+ printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ break;
+ }
-#if defined(DEBUG_STATUS)
- if (HOSTDATA(shpnt)->debug & debug_status) {
- printk("inbound status ");
- print_status(CURRENT_SC->SCp.Status);
- printk(", ");
+ fifodata = GETPORT(FIFOSTAT);
}
-#endif
- break;
- case P_DATAI: /* DATA IN phase */
- {
- int fifodata, data_count, done;
+ while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
+ data_count = fifodata>CURRENT_SC->SCp.this_residual ?
+ CURRENT_SC->SCp.this_residual :
+ fifodata;
+ fifodata -= data_count;
+
+ if(data_count & 1) {
+ DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
+ SETPORT(DMACNTRL0, ENDMA|_8BIT);
+ *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+ CURRENT_SC->SCp.this_residual--;
+ DATA_LEN++;
+ SETPORT(DMACNTRL0, ENDMA);
+ }
+
+ if(data_count > 1) {
+ DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
+ data_count >>= 1;
+ insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+ CURRENT_SC->SCp.ptr += 2 * data_count;
+ CURRENT_SC->SCp.this_residual -= 2 * data_count;
+ DATA_LEN += 2 * data_count;
+ }
+
+ if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+ /* advance to next buffer */
+ CURRENT_SC->SCp.buffers_residual--;
+ CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+ }
+ }
+
+ if(fifodata>0 && CURRENT_SC->SCp.this_residual==0) {
+ printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT));
+ break;
+ }
+ }
-#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases))
- printk("DATA IN, ");
-#endif
+ if(TESTLO(DMASTAT, INTSTAT) ||
+ TESTLO(DMASTAT, DFIFOEMP) ||
+ TESTLO(SSTAT2, SEMPTY) ||
+ GETPORT(FIFOSTAT)>0) {
+ /*
+ * something went wrong, if there's something left in the fifos
+ * or the phase didn't change
+ */
+ printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ }
-#if 0
- if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT))
- printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
- GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
-#endif
+ if(DATA_LEN!=GETSTCNT()) {
+ printk(ERR_LEAD
+ "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)",
+ CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT));
+ disp_ports(shpnt);
+ mdelay(10000);
+ }
+}
- /* reset host fifo */
- SETPORT(DMACNTRL0, RSTFIFO);
- SETPORT(DMACNTRL0, RSTFIFO | ENDMA);
+static void datai_end(struct Scsi_Host *shpnt)
+{
+ CURRENT_SC->resid -= GETSTCNT();
- SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN);
+ DPRINTK(debug_datai,
+ DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
+ CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT());
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+ SETPORT(DMACNTRL0, 0);
+}
- /* done is set when the FIFO is empty after the target left DATA IN */
- done = 0;
+/*
+ * data out phase
+ *
+ */
+static void datao_init(struct Scsi_Host *shpnt)
+{
+ SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+ SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
- /* while the target stays in DATA to transfer data */
- while (!done) {
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("expecting data, ");
-#endif
- /* wait for PHASEMIS or full FIFO */
- while (TESTLO(DMASTAT, DFIFOFULL | INTSTAT))
- barrier();
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+ SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("ok, ");
-#endif
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
- if (TESTHI(DMASTAT, DFIFOFULL))
- fifodata = GETPORT(FIFOSTAT);
- else {
- /* wait for SCSI fifo to get empty */
- while (TESTLO(SSTAT2, SEMPTY))
- barrier();
-
- /* rest of data in FIFO */
- fifodata = GETPORT(FIFOSTAT);
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("last transfer, ");
-#endif
- done = 1;
- }
+ DATA_LEN = CURRENT_SC->resid;
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("fifodata=%d, ", fifodata);
-#endif
+ DPRINTK(debug_datao,
+ DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
+ CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
- while (fifodata && CURRENT_SC->SCp.this_residual) {
- data_count = fifodata;
+static void datao_run(struct Scsi_Host *shpnt)
+{
+ unsigned int the_time;
+ int data_count;
+
+ /* until phase changes or all data sent */
+ while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
+ data_count = 128;
+ if(data_count > CURRENT_SC->SCp.this_residual)
+ data_count=CURRENT_SC->SCp.this_residual;
+
+ if(TESTLO(DMASTAT, DFIFOEMP)) {
+ printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT));
+ disp_ports(shpnt);
+ break;
+ }
- /* limit data transfer to size of first sg buffer */
- if (data_count > CURRENT_SC->SCp.this_residual)
- data_count = CURRENT_SC->SCp.this_residual;
+ if(data_count & 1) {
+ SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
+ SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
+ CURRENT_SC->SCp.this_residual--;
+ CURRENT_SC->resid--;
+ SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
+ }
- fifodata -= data_count;
+ if(data_count > 1) {
+ data_count >>= 1;
+ outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+ CURRENT_SC->SCp.ptr += 2 * data_count;
+ CURRENT_SC->SCp.this_residual -= 2 * data_count;
+ CURRENT_SC->resid -= 2 * data_count;
+ }
+
+ if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+ /* advance to next buffer */
+ CURRENT_SC->SCp.buffers_residual--;
+ CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+ }
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- printk("data_count=%d, ", data_count);
-#endif
+ the_time=jiffies+100;
+ while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
+ barrier();
- if (data_count & 1) {
- /* get a single byte in byte mode */
- SETBITS(DMACNTRL0, _8BIT);
- *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
- CURRENT_SC->SCp.this_residual--;
- }
- if (data_count > 1) {
- CLRBITS(DMACNTRL0, _8BIT);
- data_count >>= 1; /* Number of words */
- insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- /* show what comes with the last transfer */
- if (done) {
-#if 0
- int i;
- unsigned char *data;
-#endif
+ if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
+ printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ break;
+ }
+ }
+}
- printk("data on last transfer (%d bytes) ",
- 2 * data_count);
-#if 0
- printk("data on last transfer (%d bytes: ",
- 2 * data_count);
- data = (unsigned char *) CURRENT_SC->SCp.ptr;
- for (i = 0; i < 2 * data_count; i++)
- printk("%2x ", *data++);
- printk("), ");
-#endif
- }
-#endif
- CURRENT_SC->SCp.ptr += 2 * data_count;
- CURRENT_SC->SCp.this_residual -= 2 * data_count;
- }
- /* if this buffer is full and there are more buffers left */
- if (!CURRENT_SC->SCp.this_residual &&
- CURRENT_SC->SCp.buffers_residual) {
- /* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
- CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
- CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
- }
- }
+static void datao_end(struct Scsi_Host *shpnt)
+{
+ if(TESTLO(DMASTAT, DFIFOEMP)) {
+ int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
+
+ DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transfered)\n",
+ CMDINFO(CURRENT_SC),
+ data_count,
+ DATA_LEN-CURRENT_SC->resid,
+ GETSTCNT());
+
+ CURRENT_SC->resid += data_count;
+
+ data_count -= CURRENT_SC->SCp.ptr - CURRENT_SC->SCp.buffer->address;
+ while(data_count>0) {
+ CURRENT_SC->SCp.buffer--;
+ CURRENT_SC->SCp.buffers_residual++;
+ data_count -= CURRENT_SC->SCp.buffer->length;
+ }
+ CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address - data_count;
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
+ }
- /*
- * FIFO should be empty
- */
- if (fifodata > 0) {
- printk("aha152x: more data than expected (%d bytes)\n",
- GETPORT(FIFOSTAT));
- SETBITS(DMACNTRL0, _8BIT);
- printk("aha152x: data (");
- while (fifodata--)
- printk("%2x ", GETPORT(DATAPORT));
- printk(")\n");
- }
-#if defined(DEBUG_DATAI)
- if (HOSTDATA(shpnt)->debug & debug_datai)
- if (!fifodata)
- printk("fifo empty, ");
- else
- printk("something left in fifo, ");
-#endif
- }
+ DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
+ CMDINFO(CURRENT_SC),
+ CURRENT_SC->request_bufflen,
+ CURRENT_SC->resid,
+ GETSTCNT());
-#if defined(DEBUG_DATAI)
- if ((HOSTDATA(shpnt)->debug & debug_datai) &&
- (CURRENT_SC->SCp.buffers_residual ||
- CURRENT_SC->SCp.this_residual))
- printk("left buffers (buffers=%d, bytes=%d), ",
- CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual);
-#endif
- /* transfer can be considered ended, when SCSIEN reads back zero */
- CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
- while (TESTHI(SXFRCTL0, SCSIEN))
- barrier();
- CLRBITS(DMACNTRL0, ENDMA);
+ SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+ SETPORT(SXFRCTL0, CH1);
-#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr))
- printk("got %d bytes, ", GETSTCNT());
-#endif
+ SETPORT(DMACNTRL0, 0);
+}
- CURRENT_SC->SCp.have_data_in++;
+/*
+ * figure out what state we're in
+ *
+ */
+static int update_state(struct Scsi_Host *shpnt)
+{
+ int dataphase=0;
+ unsigned int stat0 = GETPORT(SSTAT0);
+ unsigned int stat1 = GETPORT(SSTAT1);
+
+ PREVSTATE = STATE;
+ STATE=unknown;
+
+ if(stat1 & SCSIRSTI) {
+ STATE=rsti;
+ SETPORT(SCSISEQ,0);
+ SETPORT(SSTAT1,SCSIRSTI);
+ } else if(stat0 & SELDI && PREVSTATE==busfree) {
+ STATE=seldi;
+ } else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
+ STATE=seldo;
+ } else if(stat1 & SELTO) {
+ STATE=selto;
+ } else if(stat1 & BUSFREE) {
+ STATE=busfree;
+ SETPORT(SSTAT1,BUSFREE);
+ } else if(stat1 & SCSIPERR) {
+ STATE=parerr;
+ SETPORT(SSTAT1,SCSIPERR);
+ } else if(stat1 & REQINIT) {
+ switch(GETPORT(SCSISIG) & P_MASK) {
+ case P_MSGI: STATE=msgi; break;
+ case P_MSGO: STATE=msgo; break;
+ case P_DATAO: STATE=datao; break;
+ case P_DATAI: STATE=datai; break;
+ case P_STATUS: STATE=status; break;
+ case P_CMD: STATE=cmd; break;
}
- break;
+ dataphase=1;
+ }
- case P_DATAO: /* DATA OUT phase */
- {
- int data_count;
+ if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
+ printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC));
+ disp_ports(shpnt);
+ }
-#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr | debug_phases))
- printk("DATA OUT, ");
-#endif
-#if defined(DEBUG_DATAO)
- if (HOSTDATA(shpnt)->debug & debug_datao)
- printk("got data to send (bytes=%d, buffers=%d), ",
- CURRENT_SC->SCp.this_residual,
- CURRENT_SC->SCp.buffers_residual);
-#endif
+ if(STATE!=PREVSTATE) {
+ LASTSTATE=PREVSTATE;
+ }
- if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) {
- printk("%d(%d) left in FIFO, ",
- GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT));
- aha152x_panic(shpnt, "FIFO should be empty");
- }
- SETPORT(SXFRCTL0, CH1 | CLRSTCNT | CLRCH1);
- SETPORT(SXFRCTL0, SCSIEN | DMAEN | CH1);
-
- SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
- SETPORT(DMACNTRL0, ENDMA | WRITE_READ);
-
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-
- /* while current buffer is not empty or
- there are more buffers to transfer */
- while (TESTLO(SSTAT1, PHASEMIS) &&
- (CURRENT_SC->SCp.this_residual ||
- CURRENT_SC->SCp.buffers_residual)) {
-#if defined(DEBUG_DATAO)
- if (HOSTDATA(shpnt)->debug & debug_datao)
- printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
- CURRENT_SC->SCp.this_residual,
- CURRENT_SC->SCp.buffers_residual);
-#endif
- /* transfer rest of buffer, but max. 128 byte */
- data_count =
- CURRENT_SC->SCp.this_residual > 128 ?
- 128 : CURRENT_SC->SCp.this_residual;
-
-#if defined(DEBUG_DATAO)
- if (HOSTDATA(shpnt)->debug & debug_datao)
- printk("data_count=%d, ", data_count);
-#endif
+ return dataphase;
+}
- if (data_count & 1) {
- /* put a single byte in byte mode */
- SETBITS(DMACNTRL0, _8BIT);
- SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
- CURRENT_SC->SCp.this_residual--;
- }
- if (data_count > 1) {
- CLRBITS(DMACNTRL0, _8BIT);
- data_count >>= 1; /* number of words */
- outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
- CURRENT_SC->SCp.ptr += 2 * data_count;
- CURRENT_SC->SCp.this_residual -= 2 * data_count;
- }
- /* wait for FIFO to get empty */
- while (TESTLO(DMASTAT, DFIFOEMP | INTSTAT))
- barrier();
-
-#if defined(DEBUG_DATAO)
- if (HOSTDATA(shpnt)->debug & debug_datao)
- printk("fifo (%d bytes), transfered (%d bytes), ",
- GETPORT(FIFOSTAT), GETSTCNT());
-#endif
+/*
+ * handle parity error
+ *
+ * FIXME: in which phase?
+ *
+ */
+static void parerr_run(struct Scsi_Host *shpnt)
+{
+ printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC));
+ done(shpnt, DID_PARITY << 16);
+}
- /* if this buffer is empty and there are more buffers left */
- if (TESTLO(SSTAT1, PHASEMIS) &&
- !CURRENT_SC->SCp.this_residual &&
- CURRENT_SC->SCp.buffers_residual) {
- /* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
- CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
- CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
- }
- }
+/*
+ * handle reset in
+ *
+ */
+static void rsti_run(struct Scsi_Host *shpnt)
+{
+ Scsi_Cmnd *ptr;
- if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) {
- /* target leaves DATA OUT for an other phase (perhaps disconnect) */
-
- /* data in fifos has to be resend */
- data_count = GETPORT(SSTAT2) & (SFULL | SFCNT);
-
- data_count += GETPORT(FIFOSTAT);
- CURRENT_SC->SCp.ptr -= data_count;
- CURRENT_SC->SCp.this_residual += data_count;
-#if defined(DEBUG_DATAO)
- if (HOSTDATA(shpnt)->debug & debug_datao)
- printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), "
- "transfer incomplete, resetting fifo, ",
- CURRENT_SC->SCp.this_residual,
- CURRENT_SC->SCp.buffers_residual,
- data_count);
-#endif
- SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
- CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
- CLRBITS(DMACNTRL0, ENDMA);
- } else {
-#if defined(DEBUG_DATAO)
- if (HOSTDATA(shpnt)->debug & debug_datao)
- printk("waiting for SCSI fifo to get empty, ");
-#endif
- /* wait for SCSI fifo to get empty */
- while (TESTLO(SSTAT2, SEMPTY))
- barrier();
-#if defined(DEBUG_DATAO)
- if (HOSTDATA(shpnt)->debug & debug_datao)
- printk("ok, left data (bytes=%d, buffers=%d) ",
- CURRENT_SC->SCp.this_residual,
- CURRENT_SC->SCp.buffers_residual);
-#endif
- CLRBITS(SXFRCTL0, SCSIEN | DMAEN);
+ printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO);
+
+ ptr=DISCONNECTED_SC;
+ while(ptr) {
+ Scsi_Cmnd *next = SCNEXT(ptr);
- /* transfer can be considered ended, when SCSIEN reads back zero */
- while (TESTHI(SXFRCTL0, SCSIEN))
- barrier();
+ if (!ptr->device->soft_reset) {
+ remove_SC(&DISCONNECTED_SC, ptr);
- CLRBITS(DMACNTRL0, ENDMA);
- }
+ kfree(ptr->host_scribble);
+ ptr->host_scribble=0;
-#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr))
- printk("sent %d data bytes, ", GETSTCNT());
-#endif
+ ptr->result = DID_RESET << 16;
+ ptr->scsi_done(ptr);
}
- break;
-
- case P_BUSFREE: /* BUSFREE */
-#if defined(DEBUG_RACE)
- leave_driver("(BUSFREE) intr");
-#endif
-#if defined(DEBUG_PHASES)
- if (HOSTDATA(shpnt)->debug & debug_phases)
- printk("unexpected BUS FREE, ");
-#endif
- CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
-
- aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */
- return;
- break;
-
- case P_PARITY: /* parity error in DATA phase */
-#if defined(DEBUG_RACE)
- leave_driver("(DID_PARITY) intr");
-#endif
- printk("PARITY error in DATA phase, ");
-
- CURRENT_SC->SCp.phase &= ~(P_MASK << 16);
-
- SETBITS(DMACNTRL0, INTEN);
- aha152x_done(shpnt, DID_PARITY << 16);
- return;
- break;
- default:
- printk("aha152x: unexpected phase\n");
- break;
+ ptr = next;
}
- if (done) {
-#if defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & debug_intr)
- printk("command done.\n");
-#endif
-#if defined(DEBUG_RACE)
- leave_driver("(done) intr");
-#endif
-
- SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
- SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
- SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+ if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
+ done(shpnt, DID_RESET << 16 );
+}
- SETBITS(DMACNTRL0, INTEN);
- aha152x_done(shpnt,
- (CURRENT_SC->SCp.Status & 0xff)
- | ((CURRENT_SC->SCp.Message & 0xff) << 8)
- | (DID_OK << 16));
+/*
+ * bottom-half handler
+ *
+ */
+static void complete(struct Scsi_Host *shpnt)
+{
+ int dataphase;
+ unsigned long flags;
+ int pending;
-#if defined(DEBUG_RACE)
- printk("done returned (DID_OK: Status=%x; Message=%x).\n",
- CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message);
-#endif
- return;
- }
- if (CURRENT_SC)
- CURRENT_SC->SCp.phase |= 1 << 16;
+ DO_LOCK(flags);
+ if(HOSTDATA(shpnt)->in_intr!=0)
+ aha152x_error(shpnt, "bottom-half already running!?");
+ HOSTDATA(shpnt)->in_intr++;
+ DO_UNLOCK(flags);
- SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE);
-#if defined(DEBUG_INTR)
- if (HOSTDATA(shpnt)->debug & debug_intr)
- disp_enintr(shpnt);
-#endif
-#if defined(DEBUG_RACE)
- leave_driver("(PHASEEND) intr");
-#endif
+ /*
+ * loop while there are interrupt conditions pending
+ *
+ */
+ do {
+ unsigned long start = jiffies;
+ dataphase=update_state(shpnt);
+
+ DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+
+ /*
+ * end previous state
+ *
+ */
+ if(PREVSTATE!=STATE && states[PREVSTATE].end)
+ states[PREVSTATE].end(shpnt);
+
+ /*
+ * disable SPIO mode if previous phase used it
+ * and this one doesn't
+ *
+ */
+ if(states[PREVSTATE].spio && !states[STATE].spio) {
+ SETPORT(SXFRCTL0, CH1);
+ SETPORT(DMACNTRL0, 0);
+ if(CURRENT_SC)
+ CURRENT_SC->SCp.phase &= ~spiordy;
+ }
+ /*
+ * accept current dataphase phase
+ *
+ */
+ if(dataphase) {
+ SETPORT(SSTAT0, REQINIT);
+ SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
+ SETPORT(SSTAT1, PHASECHG);
+ }
+
+ /*
+ * enable SPIO mode if previous didn't use it
+ * and this one does
+ *
+ */
+ if(!states[PREVSTATE].spio && states[STATE].spio) {
+ SETPORT(DMACNTRL0, 0);
+ SETPORT(SXFRCTL0, CH1|SPIOEN);
+ if(CURRENT_SC)
+ CURRENT_SC->SCp.phase |= spiordy;
+ }
+
+ /*
+ * initialize for new state
+ *
+ */
+ if(PREVSTATE!=STATE && states[STATE].init)
+ states[STATE].init(shpnt);
+
+ /*
+ * handle current state
+ *
+ */
+ if(states[STATE].run)
+ states[STATE].run(shpnt);
+ else
+ printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE);
+
+ /*
+ * setup controller to interrupt on
+ * the next expected condition and
+ * loop if it's already there
+ *
+ */
+ DO_LOCK(flags);
+ pending=setup_expected_interrupts(shpnt);
+#if defined(AHA152X_STAT)
+ HOSTDATA(shpnt)->count[STATE]++;
+ if(PREVSTATE!=STATE)
+ HOSTDATA(shpnt)->count_trans[STATE]++;
+ HOSTDATA(shpnt)->time[STATE] += jiffies-start;
+#endif
+ DO_UNLOCK(flags);
+
+ DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+ } while(pending);
+
+ /*
+ * enable interrupts and leave bottom-half
+ *
+ */
+ DO_LOCK(flags);
+ HOSTDATA(shpnt)->in_intr--;
SETBITS(DMACNTRL0, INTEN);
- return;
+ DO_UNLOCK(flags);
}
+
/*
- * Dump the current driver status and panic...
+ * Dump the current driver status and panic
*/
-static void aha152x_panic(struct Scsi_Host *shpnt, char *msg)
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
{
- printk("\naha152x: %s\n", msg);
+ printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg);
show_queues(shpnt);
- panic("aha152x panic");
+ panic("aha152x panic\n");
}
/*
*/
static void disp_ports(struct Scsi_Host *shpnt)
{
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
int s;
-#ifdef SKIP_PORTS
- if (HOSTDATA(shpnt)->debug & debug_skipports)
- return;
-#endif
-
- printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+ printk("\n%s: %s(%s) ",
+ CURRENT_SC ? "busy" : "waiting",
+ states[STATE].name,
+ states[PREVSTATE].name);
s = GETPORT(SCSISEQ);
- printk("SCSISEQ (");
+ printk("SCSISEQ( ");
if (s & TEMODEO)
printk("TARGET MODE ");
if (s & ENSELO)
printk("SCSIRSTO ");
printk(");");
- printk(" SCSISIG (");
+ printk(" SCSISIG(");
s = GETPORT(SCSISIG);
switch (s & P_MASK) {
case P_DATAO:
printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
- printk("SSTAT (");
+ printk("SSTAT( ");
s = GETPORT(SSTAT0);
if (s & TARGET)
printk("TARGET ");
printk("); ");
- printk("SSTAT (");
+ printk("SSTAT( ");
s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
printk("REQINIT ");
printk("); ");
- printk("SXFRCTL0 (");
+ printk("SXFRCTL0( ");
s = GETPORT(SXFRCTL0);
if (s & SCSIEN)
printk("CLRCH1 ");
printk("); ");
- printk("SIGNAL (");
+ printk("SIGNAL( ");
s = GETPORT(SCSISIG);
- if (s & ATNI)
+ if (s & SIG_ATNI)
printk("ATNI ");
- if (s & SELI)
+ if (s & SIG_SELI)
printk("SELI ");
- if (s & BSYI)
+ if (s & SIG_BSYI)
printk("BSYI ");
- if (s & REQI)
+ if (s & SIG_REQI)
printk("REQI ");
- if (s & ACKI)
+ if (s & SIG_ACKI)
printk("ACKI ");
printk("); ");
printk("SELID (%02x), ", GETPORT(SELID));
- printk("SSTAT2 (");
+ printk("STCNT (%d), ", GETSTCNT());
+
+ printk("SSTAT2( ");
s = GETPORT(SSTAT2);
if (s & SOFFSET)
s = GETPORT(SSTAT3);
printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
- printk("SSTAT4 (");
+ printk("SSTAT4( ");
s = GETPORT(SSTAT4);
if (s & SYNCERR)
printk("SYNCERR ");
printk("FRERR ");
printk("); ");
- printk("DMACNTRL0 (");
+ printk("DMACNTRL0( ");
s = GETPORT(DMACNTRL0);
printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
printk("%s ", s & DMA ? "DMA" : "PIO");
printk("SWINT ");
printk("); ");
- printk("DMASTAT (");
+ printk("DMASTAT( ");
s = GETPORT(DMASTAT);
if (s & ATDONE)
printk("ATDONE ");
printk("DFIFOFULL ");
if (s & DFIFOEMP)
printk("DFIFOEMP ");
- printk(")");
-
- printk("\n");
+ printk(")\n");
#endif
}
{
int s;
- printk("enabled interrupts (");
+ printk(KERN_DEBUG "enabled interrupts ( ");
s = GETPORT(SIMODE0);
if (s & ENSELDO)
printk(")\n");
}
-#if defined(DEBUG_RACE)
-
-static const char *should_leave;
-static int in_driver = 0;
-
-/*
- * Only one routine can be in the driver at once.
- */
-static void enter_driver(const char *func)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- printk("aha152x: entering %s() (%x)\n", func, jiffies);
- if (in_driver) {
- printk("%s should leave first.\n", should_leave);
- panic("aha152x: already in driver\n");
- }
- in_driver++;
- should_leave = func;
- restore_flags(flags);
-}
-
-static void leave_driver(const char *func)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- printk("\naha152x: leaving %s() (%x)\n", func, jiffies);
- if (!in_driver) {
- printk("aha152x: %s already left.\n", should_leave);
- panic("aha152x: %s already left driver.\n");
- }
- in_driver--;
- should_leave = func;
- restore_flags(flags);
-}
-#endif
-
/*
* Show the command data of a command
*/
-static void show_command(Scsi_Cmnd * ptr)
+static void show_command(Scsi_Cmnd *ptr)
{
- printk("0x%08x: target=%d; lun=%d; cmnd=(",
+ printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(",
(unsigned int) ptr, ptr->target, ptr->lun);
print_command(ptr->cmnd);
- printk("); residual=%d; buffers=%d; phase |",
- ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+ printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
+ ptr->request_bufflen, ptr->resid);
if (ptr->SCp.phase & not_issued)
printk("not issued|");
- if (ptr->SCp.phase & in_selection)
- printk("in selection|");
+ if (ptr->SCp.phase & selecting)
+ printk("selecting|");
+ if (ptr->SCp.phase & identified)
+ printk("identified|");
if (ptr->SCp.phase & disconnected)
printk("disconnected|");
+ if (ptr->SCp.phase & completed)
+ printk("completed|");
+ if (ptr->SCp.phase & spiordy)
+ printk("spiordy|");
+ if (ptr->SCp.phase & syncneg)
+ printk("syncneg|");
if (ptr->SCp.phase & aborted)
printk("aborted|");
- if (ptr->SCp.phase & sent_ident)
- printk("send_ident|");
- if (ptr->SCp.phase & in_other) {
- printk("; in other(");
- switch ((ptr->SCp.phase >> 16) & P_MASK) {
- case P_DATAO:
- printk("DATA OUT");
- break;
- case P_DATAI:
- printk("DATA IN");
- break;
- case P_CMD:
- printk("COMMAND");
- break;
- case P_STATUS:
- printk("STATUS");
- break;
- case P_MSGO:
- printk("MESSAGE OUT");
- break;
- case P_MSGI:
- printk("MESSAGE IN");
- break;
- default:
- printk("*illegal*");
- break;
- }
- printk(")");
- if (ptr->SCp.phase & (1 << 16))
- printk("; phaseend");
- }
- printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+ if (ptr->SCp.phase & resetted)
+ printk("resetted|");
+ printk("; next=0x%p\n", SCNEXT(ptr));
}
/*
*/
static void show_queues(struct Scsi_Host *shpnt)
{
- unsigned long flags;
Scsi_Cmnd *ptr;
+ unsigned long flags;
- save_flags(flags);
- cli();
- printk("QUEUE STATUS:\nissue_SC:\n");
- for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ DO_LOCK(flags);
+ printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
+ for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
show_command(ptr);
+ DO_UNLOCK(flags);
- printk("current_SC:\n");
+ printk(KERN_DEBUG "current_SC:\n");
if (CURRENT_SC)
show_command(CURRENT_SC);
else
- printk("none\n");
+ printk(KERN_DEBUG "none\n");
- printk("disconnected_SC:\n");
- for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ printk(KERN_DEBUG "disconnected_SC:\n");
+ for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
show_command(ptr);
disp_ports(shpnt);
disp_enintr(shpnt);
- restore_flags(flags);
-}
-
-int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
-{
- return (-ENOSYS); /* Currently this is a no-op */
}
#undef SPRINTF
for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
SPRINTF("0x%02x ", ptr->cmnd[i]);
- SPRINTF("); residual=%d; buffers=%d; phase |",
- ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+ SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
+ ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual);
if (ptr->SCp.phase & not_issued)
SPRINTF("not issued|");
- if (ptr->SCp.phase & in_selection)
- SPRINTF("in selection|");
+ if (ptr->SCp.phase & selecting)
+ SPRINTF("selecting|");
if (ptr->SCp.phase & disconnected)
SPRINTF("disconnected|");
if (ptr->SCp.phase & aborted)
SPRINTF("aborted|");
- if (ptr->SCp.phase & sent_ident)
- SPRINTF("send_ident|");
- if (ptr->SCp.phase & in_other) {
- SPRINTF("; in other(");
- switch ((ptr->SCp.phase >> 16) & P_MASK) {
- case P_DATAO:
- SPRINTF("DATA OUT");
- break;
- case P_DATAI:
- SPRINTF("DATA IN");
- break;
- case P_CMD:
- SPRINTF("COMMAND");
- break;
- case P_STATUS:
- SPRINTF("STATUS");
- break;
- case P_MSGO:
- SPRINTF("MESSAGE OUT");
- break;
- case P_MSGI:
- SPRINTF("MESSAGE IN");
- break;
- default:
- SPRINTF("*illegal*");
- break;
- }
- SPRINTF(")");
- if (ptr->SCp.phase & (1 << 16))
- SPRINTF("; phaseend");
- }
- SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+ if (ptr->SCp.phase & identified)
+ SPRINTF("identified|");
+ if (ptr->SCp.phase & completed)
+ SPRINTF("completed|");
+ if (ptr->SCp.phase & spiordy)
+ SPRINTF("spiordy|");
+ if (ptr->SCp.phase & syncneg)
+ SPRINTF("syncneg|");
+ SPRINTF("; next=0x%p\n", SCNEXT(ptr));
return (pos - start);
}
char *start = pos;
int s;
-#ifdef SKIP_PORTS
- if (HOSTDATA(shpnt)->debug & debug_skipports)
- return;
-#endif
-
- SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
+ SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
s = GETPORT(SCSISEQ);
- SPRINTF("SCSISEQ (");
+ SPRINTF("SCSISEQ( ");
if (s & TEMODEO)
SPRINTF("TARGET MODE ");
if (s & ENSELO)
SPRINTF("SCSIRSTO ");
SPRINTF(");");
- SPRINTF(" SCSISIG (");
+ SPRINTF(" SCSISIG(");
s = GETPORT(SCSISIG);
switch (s & P_MASK) {
case P_DATAO:
SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
- SPRINTF("SSTAT (");
+ SPRINTF("SSTAT( ");
s = GETPORT(SSTAT0);
if (s & TARGET)
SPRINTF("TARGET ");
SPRINTF("); ");
- SPRINTF("SSTAT (");
+ SPRINTF("SSTAT( ");
s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
SPRINTF("REQINIT ");
SPRINTF("); ");
- SPRINTF("SXFRCTL0 (");
+ SPRINTF("SXFRCTL0( ");
s = GETPORT(SXFRCTL0);
if (s & SCSIEN)
SPRINTF("CLRCH1 ");
SPRINTF("); ");
- SPRINTF("SIGNAL (");
+ SPRINTF("SIGNAL( ");
s = GETPORT(SCSISIG);
- if (s & ATNI)
+ if (s & SIG_ATNI)
SPRINTF("ATNI ");
- if (s & SELI)
+ if (s & SIG_SELI)
SPRINTF("SELI ");
- if (s & BSYI)
+ if (s & SIG_BSYI)
SPRINTF("BSYI ");
- if (s & REQI)
+ if (s & SIG_REQI)
SPRINTF("REQI ");
- if (s & ACKI)
+ if (s & SIG_ACKI)
SPRINTF("ACKI ");
SPRINTF("); ");
- SPRINTF("SELID (%02x), ", GETPORT(SELID));
+ SPRINTF("SELID(%02x), ", GETPORT(SELID));
+
+ SPRINTF("STCNT(%d), ", GETSTCNT());
- SPRINTF("SSTAT2 (");
+ SPRINTF("SSTAT2( ");
s = GETPORT(SSTAT2);
if (s & SOFFSET)
s = GETPORT(SSTAT3);
SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
- SPRINTF("SSTAT4 (");
+ SPRINTF("SSTAT4( ");
s = GETPORT(SSTAT4);
if (s & SYNCERR)
SPRINTF("SYNCERR ");
SPRINTF("FRERR ");
SPRINTF("); ");
- SPRINTF("DMACNTRL0 (");
+ SPRINTF("DMACNTRL0( ");
s = GETPORT(DMACNTRL0);
SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT");
SPRINTF("%s ", s & DMA ? "DMA" : "PIO");
SPRINTF("SWINT ");
SPRINTF("); ");
- SPRINTF("DMASTAT (");
+ SPRINTF("DMASTAT( ");
s = GETPORT(DMASTAT);
if (s & ATDONE)
SPRINTF("ATDONE ");
SPRINTF("DFIFOFULL ");
if (s & DFIFOEMP)
SPRINTF("DFIFOEMP ");
- SPRINTF(")\n\n");
+ SPRINTF(")\n");
- SPRINTF("enabled interrupts (");
+ SPRINTF("enabled interrupts( ");
s = GETPORT(SIMODE0);
if (s & ENSELDO)
return (pos - start);
}
+int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+ if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
+ return -EINVAL;
+
+#if defined(AHA152X_DEBUG)
+ if(length>14 && strncmp("debug ", buffer+8, 6)==0) {
+ int debug = HOSTDATA(shpnt)->debug;
+
+ HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0);
+
+ printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug);
+ } else
+#endif
+#if defined(AHA152X_STAT)
+ if(length>13 && strncmp("reset", buffer+8, 5)==0) {
+ int i;
+
+ HOSTDATA(shpnt)->total_commands=0;
+ HOSTDATA(shpnt)->disconnections=0;
+ HOSTDATA(shpnt)->busfree_without_any_action=0;
+ HOSTDATA(shpnt)->busfree_without_old_command=0;
+ HOSTDATA(shpnt)->busfree_without_new_command=0;
+ HOSTDATA(shpnt)->busfree_without_done_command=0;
+ HOSTDATA(shpnt)->busfree_with_check_condition=0;
+ for (i = idle; i<maxstate; i++) {
+ HOSTDATA(shpnt)->count[i]=0;
+ HOSTDATA(shpnt)->count_trans[i]=0;
+ HOSTDATA(shpnt)->time[i]=0;
+ }
+
+ printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO);
+
+ } else
+#endif
+ {
+ return -EINVAL;
+ }
+
+
+ return length;
+}
+
#undef SPRINTF
-#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+#define SPRINTF(args...) \
+ do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
int aha152x_proc_info(char *buffer, char **start,
off_t offset, int length, int hostno, int inout)
int i;
char *pos = buffer;
struct Scsi_Host *shpnt;
- unsigned long flags;
Scsi_Cmnd *ptr;
+ unsigned long flags;
+ int thislength;
for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++)
if (aha152x_host[i] && aha152x_host[i]->host_no == hostno)
shpnt = aha152x_host[i];
if (!shpnt)
- return (-ESRCH);
+ return -ESRCH;
- if (inout) /* Has data been written to the file ? */
- return (aha152x_set_info(buffer, length, shpnt));
+ DPRINTK(debug_procinfo,
+ KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n",
+ buffer, offset, length, hostno, inout);
- SPRINTF(AHA152X_REVID "\n");
- save_flags(flags);
- cli();
+ if (inout)
+ return aha152x_set_info(buffer, length, shpnt);
+
+ SPRINTF(AHA152X_REVID "\n");
SPRINTF("ioports 0x%04lx to 0x%04lx\n",
shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
SPRINTF("interrupt 0x%02x\n", shpnt->irq);
SPRINTF("disconnection/reconnection %s\n",
- HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled");
+ RECONNECT ? "enabled" : "disabled");
SPRINTF("parity checking %s\n",
- HOSTDATA(shpnt)->parity ? "enabled" : "disabled");
+ PARITY ? "enabled" : "disabled");
SPRINTF("synchronous transfers %s\n",
- HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled");
+ SYNCHRONOUS ? "enabled" : "disabled");
SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
- if (HOSTDATA(shpnt)->synchronous) {
-#if 0
- SPRINTF("synchronously operating targets (tick=%ld ns):\n",
- 250000000 / loops_per_sec);
- for (i = 0; i < 8; i++)
- if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
- SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n",
- i,
- (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
- (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) *
- 250000000 / loops_per_sec,
- HOSTDATA(shpnt)->syncrate[i] & 0x0f);
-#else
+ if(SYNCHRONOUS) {
SPRINTF("synchronously operating targets (tick=50 ns):\n");
for (i = 0; i < 8; i++)
if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
HOSTDATA(shpnt)->syncrate[i] & 0x0f);
-#endif
}
-#ifdef DEBUG_AHA152X
-#define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
+#if defined(AHA152X_DEBUG)
+#define PDEBUG(flags,txt) \
+ if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
SPRINTF("enabled debugging options: ");
- PDEBUG(debug_skipports, "skip ports");
+ PDEBUG(debug_procinfo, "procinfo");
PDEBUG(debug_queue, "queue");
PDEBUG(debug_intr, "interrupt");
PDEBUG(debug_selection, "selection");
PDEBUG(debug_cmd, "command");
PDEBUG(debug_datai, "data in");
PDEBUG(debug_datao, "data out");
- PDEBUG(debug_abort, "abort");
- PDEBUG(debug_done, "done");
- PDEBUG(debug_biosparam, "bios parameters");
+ PDEBUG(debug_eh, "eh");
+ PDEBUG(debug_locks, "locks");
PDEBUG(debug_phases, "phases");
- PDEBUG(debug_queues, "queues");
- PDEBUG(debug_reset, "reset");
SPRINTF("\n");
#endif
SPRINTF("\nqueue status:\n");
+ DO_LOCK(flags);
if (ISSUE_SC) {
SPRINTF("not yet issued commands:\n");
- for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
pos += get_command(pos, ptr);
} else
SPRINTF("no not yet issued commands\n");
+ DO_UNLOCK(flags);
if (CURRENT_SC) {
SPRINTF("current command:\n");
if (DISCONNECTED_SC) {
SPRINTF("disconnected commands:\n");
- for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
pos += get_command(pos, ptr);
} else
SPRINTF("no disconnected commands\n");
- restore_flags(flags);
-
pos += get_ports(shpnt, pos);
- *start = buffer + offset;
- if (pos - buffer < offset)
+#if defined(AHA152X_STAT)
+ SPRINTF("statistics:\n"
+ "total commands: %d\n"
+ "disconnections: %d\n"
+ "busfree with check condition: %d\n"
+ "busfree without old command: %d\n"
+ "busfree without new command: %d\n"
+ "busfree without done command: %d\n"
+ "busfree without any action: %d\n"
+ "state "
+ "transitions "
+ "count "
+ "time\n",
+ HOSTDATA(shpnt)->total_commands,
+ HOSTDATA(shpnt)->disconnections,
+ HOSTDATA(shpnt)->busfree_with_check_condition,
+ HOSTDATA(shpnt)->busfree_without_old_command,
+ HOSTDATA(shpnt)->busfree_without_new_command,
+ HOSTDATA(shpnt)->busfree_without_done_command,
+ HOSTDATA(shpnt)->busfree_without_any_action);
+ for(i=0; i<maxstate; i++) {
+ SPRINTF("%-10s %-12d %-12d %-12ld\n",
+ states[i].name,
+ HOSTDATA(shpnt)->count_trans[i],
+ HOSTDATA(shpnt)->count[i],
+ HOSTDATA(shpnt)->time[i]);
+ }
+#endif
+
+ DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos);
+
+ thislength = pos - (buffer + offset);
+ DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength);
+
+ if(thislength<0) {
+ DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n");
+ *start = 0;
return 0;
- else if (pos - buffer - offset < length)
- return pos - buffer - offset;
- else
- return length;
+ }
+
+ thislength = thislength<length ? thislength : length;
+
+ DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: return %d\n", thislength);
+
+ *start = buffer + offset;
+ return thislength < length ? thislength : length;
}
-#ifdef MODULE
+#if defined(MODULE)
/* Eventually this will go into an include file, but this will be later */
Scsi_Host_Template driver_template = AHA152X;
#define _AHA152X_H
/*
- * $Id: aha152x.h,v 1.7 1997/01/19 23:07:11 davem Exp $
+ * $Id: aha152x.h,v 2.0 1999/12/25 15:08:35 fischer Exp fischer $
*/
#if defined(__KERNEL__)
#include <linux/blk.h>
#include "scsi.h"
#include <asm/io.h>
+#include <linux/version.h>
int aha152x_detect(Scsi_Host_Template *);
int aha152x_command(Scsi_Cmnd *);
int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int aha152x_abort(Scsi_Cmnd *);
int aha152x_release(struct Scsi_Host *shpnt);
-int aha152x_reset(Scsi_Cmnd *, unsigned int);
+int aha152x_device_reset(Scsi_Cmnd *);
+int aha152x_bus_reset(Scsi_Cmnd *);
+int aha152x_host_reset(Scsi_Cmnd *);
int aha152x_biosparam(Disk *, kdev_t, int*);
int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
(unless we support more than 1 cmd_per_lun this should do) */
#define AHA152X_MAXQUEUE 7
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.7 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.0 $"
/* Initial value of Scsi_Host entry */
-#define AHA152X { proc_name: "a152x", \
- proc_info: aha152x_proc_info, \
- name: AHA152X_REVID, \
- detect: aha152x_detect, \
- command: aha152x_command, \
- queuecommand: aha152x_queue, \
- abort: aha152x_abort, \
- reset: aha152x_reset, \
- release: aha152x_release, \
- slave_attach: 0, \
- bios_param: aha152x_biosparam, \
- can_queue: 1, \
- this_id: 7, \
- sg_tablesize: SG_ALL, \
- cmd_per_lun: 1, \
- present: 0, \
- unchecked_isa_dma: 0, \
- use_clustering: DISABLE_CLUSTERING }
+#define AHA152X { proc_name: "aha152x", \
+ proc_info: aha152x_proc_info, \
+ name: AHA152X_REVID, \
+ detect: aha152x_detect, \
+ command: aha152x_command, \
+ queuecommand: aha152x_queue, \
+ eh_abort_handler: aha152x_abort, \
+ eh_device_reset_handler: aha152x_device_reset, \
+ eh_bus_reset_handler: aha152x_bus_reset, \
+ eh_host_reset_handler: aha152x_host_reset, \
+ release: aha152x_release, \
+ slave_attach: 0, \
+ bios_param: aha152x_biosparam, \
+ can_queue: 1, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ present: 0, \
+ unchecked_isa_dma: 0, \
+ use_clustering: DISABLE_CLUSTERING, \
+ use_new_eh_code: 1 }
#endif
/* port addresses */
-#define SCSISEQ (shpnt->io_port+0x00) /* SCSI sequence control */
-#define SXFRCTL0 (shpnt->io_port+0x01) /* SCSI transfer control 0 */
-#define SXFRCTL1 (shpnt->io_port+0x02) /* SCSI transfer control 1 */
-#define SCSISIG (shpnt->io_port+0x03) /* SCSI signal in/out */
-#define SCSIRATE (shpnt->io_port+0x04) /* SCSI rate control */
-#define SELID (shpnt->io_port+0x05) /* selection/reselection ID */
-#define SCSIID SELID /* SCSI ID */
-#define SCSIDAT (shpnt->io_port+0x06) /* SCSI latched data */
-#define SCSIBUS (shpnt->io_port+0x07) /* SCSI data bus */
-#define STCNT0 (shpnt->io_port+0x08) /* SCSI transfer count 0 */
-#define STCNT1 (shpnt->io_port+0x09) /* SCSI transfer count 1 */
-#define STCNT2 (shpnt->io_port+0x0a) /* SCSI transfer count 2 */
-#define SSTAT0 (shpnt->io_port+0x0b) /* SCSI interrupt status 0 */
-#define SSTAT1 (shpnt->io_port+0x0c) /* SCSI interrupt status 1 */
-#define SSTAT2 (shpnt->io_port+0x0d) /* SCSI interrupt status 2 */
-#define SCSITEST (shpnt->io_port+0x0e) /* SCSI test control */
-#define SSTAT3 SCSITEST /* SCSI interrupt status 3 */
-#define SSTAT4 (shpnt->io_port+0x0f) /* SCSI status 4 */
-#define SIMODE0 (shpnt->io_port+0x10) /* SCSI interrupt mode 0 */
-#define SIMODE1 (shpnt->io_port+0x11) /* SCSI interrupt mode 1 */
-#define DMACNTRL0 (shpnt->io_port+0x12) /* DMA control 0 */
-#define DMACNTRL1 (shpnt->io_port+0x13) /* DMA control 1 */
-#define DMASTAT (shpnt->io_port+0x14) /* DMA status */
-#define FIFOSTAT (shpnt->io_port+0x15) /* FIFO status */
-#define DATAPORT (shpnt->io_port+0x16) /* DATA port */
-#define BRSTCNTRL (shpnt->io_port+0x18) /* burst control */
-#define PORTA (shpnt->io_port+0x1a) /* PORT A */
-#define PORTB (shpnt->io_port+0x1b) /* PORT B */
-#define REV (shpnt->io_port+0x1c) /* revision */
-#define STACK (shpnt->io_port+0x1d) /* stack */
-#define TEST (shpnt->io_port+0x1e) /* test register */
+#define SCSISEQ (HOSTIOPORT0+0x00) /* SCSI sequence control */
+#define SXFRCTL0 (HOSTIOPORT0+0x01) /* SCSI transfer control 0 */
+#define SXFRCTL1 (HOSTIOPORT0+0x02) /* SCSI transfer control 1 */
+#define SCSISIG (HOSTIOPORT0+0x03) /* SCSI signal in/out */
+#define SCSIRATE (HOSTIOPORT0+0x04) /* SCSI rate control */
+#define SELID (HOSTIOPORT0+0x05) /* selection/reselection ID */
+#define SCSIID SELID /* SCSI ID */
+#define SCSIDAT (HOSTIOPORT0+0x06) /* SCSI latched data */
+#define SCSIBUS (HOSTIOPORT0+0x07) /* SCSI data bus */
+#define STCNT0 (HOSTIOPORT0+0x08) /* SCSI transfer count 0 */
+#define STCNT1 (HOSTIOPORT0+0x09) /* SCSI transfer count 1 */
+#define STCNT2 (HOSTIOPORT0+0x0a) /* SCSI transfer count 2 */
+#define SSTAT0 (HOSTIOPORT0+0x0b) /* SCSI interrupt status 0 */
+#define SSTAT1 (HOSTIOPORT0+0x0c) /* SCSI interrupt status 1 */
+#define SSTAT2 (HOSTIOPORT0+0x0d) /* SCSI interrupt status 2 */
+#define SCSITEST (HOSTIOPORT0+0x0e) /* SCSI test control */
+#define SSTAT3 SCSITEST /* SCSI interrupt status 3 */
+#define SSTAT4 (HOSTIOPORT0+0x0f) /* SCSI status 4 */
+#define SIMODE0 (HOSTIOPORT1+0x10) /* SCSI interrupt mode 0 */
+#define SIMODE1 (HOSTIOPORT1+0x11) /* SCSI interrupt mode 1 */
+#define DMACNTRL0 (HOSTIOPORT1+0x12) /* DMA control 0 */
+#define DMACNTRL1 (HOSTIOPORT1+0x13) /* DMA control 1 */
+#define DMASTAT (HOSTIOPORT1+0x14) /* DMA status */
+#define FIFOSTAT (HOSTIOPORT1+0x15) /* FIFO status */
+#define DATAPORT (HOSTIOPORT1+0x16) /* DATA port */
+#define BRSTCNTRL (HOSTIOPORT1+0x18) /* burst control */
+#define PORTA (HOSTIOPORT1+0x1a) /* PORT A */
+#define PORTB (HOSTIOPORT1+0x1b) /* PORT B */
+#define REV (HOSTIOPORT1+0x1c) /* revision */
+#define STACK (HOSTIOPORT1+0x1d) /* stack */
+#define TEST (HOSTIOPORT1+0x1e) /* test register */
+
+#define IO_RANGE 0x20
/* used in aha152x_porttest */
-#define O_PORTA 0x1a /* PORT A */
-#define O_PORTB 0x1b /* PORT B */
-#define O_DMACNTRL1 0x13 /* DMA control 1 */
-#define O_STACK 0x1d /* stack */
-#define IO_RANGE 0x20
+#define O_PORTA 0x1a /* PORT A */
+#define O_PORTB 0x1b /* PORT B */
+#define O_DMACNTRL1 0x13 /* DMA control 1 */
+#define O_STACK 0x1d /* stack */
+
+/* used in tc1550_porttest */
+#define O_TC_PORTA 0x0a /* PORT A */
+#define O_TC_PORTB 0x0b /* PORT B */
+#define O_TC_DMACNTRL1 0x03 /* DMA control 1 */
+#define O_TC_STACK 0x0d /* stack */
/* bits and bitmasks to ports */
#define BYTEALIGN 0x02
/* SCSI signal IN */
-#define CDI 0x80
-#define IOI 0x40
-#define MSGI 0x20
-#define ATNI 0x10
-#define SELI 0x08
-#define BSYI 0x04
-#define REQI 0x02
-#define ACKI 0x01
+#define SIG_CDI 0x80
+#define SIG_IOI 0x40
+#define SIG_MSGI 0x20
+#define SIG_ATNI 0x10
+#define SIG_SELI 0x08
+#define SIG_BSYI 0x04
+#define SIG_REQI 0x02
+#define SIG_ACKI 0x01
/* SCSI Phases */
-#define P_MASK (MSGI|CDI|IOI)
+#define P_MASK (SIG_MSGI|SIG_CDI|SIG_IOI)
#define P_DATAO (0)
-#define P_DATAI (IOI)
-#define P_CMD (CDI)
-#define P_STATUS (CDI|IOI)
-#define P_MSGO (MSGI|CDI)
-#define P_MSGI (MSGI|CDI|IOI)
+#define P_DATAI (SIG_IOI)
+#define P_CMD (SIG_CDI)
+#define P_STATUS (SIG_CDI|SIG_IOI)
+#define P_MSGO (SIG_MSGI|SIG_CDI)
+#define P_MSGI (SIG_MSGI|SIG_CDI|SIG_IOI)
/* SCSI signal OUT */
-#define CDO 0x80
-#define IOO 0x40
-#define MSGO 0x20
-#define ATNO 0x10
-#define SELO 0x08
-#define BSYO 0x04
-#define REQO 0x02
-#define ACKO 0x01
+#define SIG_CDO 0x80
+#define SIG_IOO 0x40
+#define SIG_MSGO 0x20
+#define SIG_ATNO 0x10
+#define SIG_SELO 0x08
+#define SIG_BSYO 0x04
+#define SIG_REQO 0x02
+#define SIG_ACKO 0x01
/* SCSI rate control */
#define SXFR 0x70 /* mask */
/* Some macros to manipulate ports and their bits */
-#define SETPORT(PORT, VAL) outb( (VAL), (PORT) )
-#define SETPORTP(PORT, VAL) outb_p( (VAL), (PORT) )
-#define SETPORTW(PORT, VAL) outw( (VAL), (PORT) )
-
-#define GETPORT(PORT) inb( PORT )
-#define GETPORTW(PORT) inw( PORT )
-
-#define SETBITS(PORT, BITS) outb( (inb(PORT) | (BITS)), (PORT) )
-#define CLRBITS(PORT, BITS) outb( (inb(PORT) & ~(BITS)), (PORT) )
-#define CLRSETBITS(PORT, CLR, SET) outb( (inb(PORT) & ~(CLR)) | (SET) , (PORT) )
+#define SETPORT(PORT, VAL) outb( (VAL), (PORT) )
+#define GETPORT(PORT) inb( PORT )
+#define SETBITS(PORT, BITS) outb( (inb(PORT) | (BITS)), (PORT) )
+#define CLRBITS(PORT, BITS) outb( (inb(PORT) & ~(BITS)), (PORT) )
+#define TESTHI(PORT, BITS) ((inb(PORT) & (BITS)) == (BITS))
+#define TESTLO(PORT, BITS) ((inb(PORT) & (BITS)) == 0)
-#define TESTHI(PORT, BITS) ((inb(PORT) & (BITS)) == BITS)
-#define TESTLO(PORT, BITS) ((inb(PORT) & (BITS)) == 0)
+#define SETRATE(RATE) SETPORT(SCSIRATE,(RATE) & 0x7f)
-#ifdef DEBUG_AHA152X
+#if defined(AHA152X_DEBUG)
enum {
- debug_skipports = 0x0001,
+ debug_procinfo = 0x0001,
debug_queue = 0x0002,
- debug_intr = 0x0004,
- debug_selection = 0x0008,
- debug_msgo = 0x0010,
- debug_msgi = 0x0020,
- debug_status = 0x0040,
- debug_cmd = 0x0080,
- debug_datai = 0x0100,
- debug_datao = 0x0200,
- debug_abort = 0x0400,
- debug_done = 0x0800,
- debug_biosparam = 0x1000,
+ debug_locks = 0x0004,
+ debug_intr = 0x0008,
+ debug_selection = 0x0010,
+ debug_msgo = 0x0020,
+ debug_msgi = 0x0040,
+ debug_status = 0x0080,
+ debug_cmd = 0x0100,
+ debug_datai = 0x0200,
+ debug_datao = 0x0400,
+ debug_eh = 0x0800,
+ debug_done = 0x1000,
debug_phases = 0x2000,
- debug_queues = 0x4000,
- debug_reset = 0x8000,
};
#endif
* Set up on-board DMA controller, such that we do not have to
* have the bios enabled to use the aha1542.
* Modified by David Gentzel
- * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus
+ * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus
* controller).
* Modified by Matti Aarnio
* Accept parameters from LILO cmd-line. -- 1-Oct-94
* 1-Jan-97
* Modified by Bjorn L. Thordarson and Einar Thor Einarsson
* Recognize that DMA0 is valid DMA channel -- 13-Jul-98
- * Modified by Chris Faulhaber <jedgar@fxp.org>
+ * Modified by Chris Faulhaber <jedgar@fxp.org>
* Added module command-line options
* 19-Jul-99
*/
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
#define SCSI_PA(address) virt_to_bus(address)
-static void BAD_DMA(void * address, unsigned int length)
+static void BAD_DMA(void *address, unsigned int length)
{
- printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
- address,
- SCSI_PA(address),
- length);
- panic("Buffer at physical address > 16Mb used for aha1542");
+ printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
+ address,
+ SCSI_PA(address),
+ length);
+ panic("Buffer at physical address > 16Mb used for aha1542");
}
-static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
- struct scatterlist * sgpnt,
- int nseg,
+static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
+ struct scatterlist *sgpnt,
+ int nseg,
int badseg)
{
- printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx alt %p/0x%lx length %d\n",
- badseg, nseg,
- sgpnt[badseg].address,
- SCSI_PA(sgpnt[badseg].address),
- sgpnt[badseg].alt_address,
- sgpnt[badseg].alt_address ? SCSI_PA(sgpnt[badseg].alt_address) : 0,
- sgpnt[badseg].length);
-
- /*
- * Not safe to continue.
- */
- panic("Buffer at physical address > 16Mb used for aha1542");
+ printk(KERN_CRIT "sgpnt[%d:%d] addr %p/0x%lx alt %p/0x%lx length %d\n",
+ badseg, nseg,
+ sgpnt[badseg].address,
+ SCSI_PA(sgpnt[badseg].address),
+ sgpnt[badseg].alt_address,
+ sgpnt[badseg].alt_address ? SCSI_PA(sgpnt[badseg].alt_address) : 0,
+ sgpnt[badseg].length);
+
+ /*
+ * Not safe to continue.
+ */
+ panic("Buffer at physical address > 16Mb used for aha1542");
}
#include<linux/stat.h>
#else
#define DEB(x)
#endif
+
/*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
-*/
+ static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
+ */
/* The adaptec can be configured for quite a number of addresses, but
-I generally do not want the card poking around at random. We allow
-two addresses - this allows people to use the Adaptec with a Midi
-card, which also used 0x330 -- can be overridden with LILO! */
+ I generally do not want the card poking around at random. We allow
+ two addresses - this allows people to use the Adaptec with a Midi
+ card, which also used 0x330 -- can be overridden with LILO! */
-#define MAXBOARDS 2 /* Increase this and the sizes of the
- arrays below, if you need more.. */
+#define MAXBOARDS 4 /* Increase this and the sizes of the
+ arrays below, if you need more.. */
-static unsigned int bases[MAXBOARDS]={0x330, 0x334};
+/* Boards 3,4 slots are reserved for ISAPnP scans */
+
+static unsigned int bases[MAXBOARDS] = {0x330, 0x334, 0, 0};
/* set by aha1542_setup according to the command line */
-static int setup_called[MAXBOARDS] = {0,0};
-static int setup_buson[MAXBOARDS] = {0,0};
-static int setup_busoff[MAXBOARDS] = {0,0};
-static int setup_dmaspeed[MAXBOARDS] = {-1,-1};
-static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL};
+static int setup_called[MAXBOARDS];
+static int setup_buson[MAXBOARDS];
+static int setup_busoff[MAXBOARDS];
+static int setup_dmaspeed[MAXBOARDS] = { -1, -1, -1, -1 };
+
+static char *setup_str[MAXBOARDS];
/*
* LILO/Module params: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]
*
* Where: <PORTBASE> is any of the valid AHA addresses:
- * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334
- * <BUSON> is the time (in microsecs) that AHA spends on the AT-bus
- * when transferring data. 1542A power-on default is 11us,
- * valid values are in range: 2..15 (decimal)
- * <BUSOFF> is the time that AHA spends OFF THE BUS after while
- * it is transferring data (not to monopolize the bus).
- * Power-on default is 4us, valid range: 1..64 microseconds.
- * <DMASPEED> Default is jumper selected (1542A: on the J1),
- * but experimenter can alter it with this.
- * Valid values: 5, 6, 7, 8, 10 (MB/s)
- * Factory default is 5 MB/s.
+ * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334
+ * <BUSON> is the time (in microsecs) that AHA spends on the AT-bus
+ * when transferring data. 1542A power-on default is 11us,
+ * valid values are in range: 2..15 (decimal)
+ * <BUSOFF> is the time that AHA spends OFF THE BUS after while
+ * it is transferring data (not to monopolize the bus).
+ * Power-on default is 4us, valid range: 1..64 microseconds.
+ * <DMASPEED> Default is jumper selected (1542A: on the J1),
+ * but experimenter can alter it with this.
+ * Valid values: 5, 6, 7, 8, 10 (MB/s)
+ * Factory default is 5 MB/s.
*/
#if defined(MODULE)
-int aha1542[] = { 0x330, 11, 4, -1 };
+int isapnp=0;
+int aha1542[] = {0x330, 11, 4, -1};
MODULE_PARM(aha1542, "1-4i");
+MODULE_PARM(isapnp, "i");
+#else
+int isapnp=1;
#endif
-#define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */
-#define BIOS_TRANSLATION_6432 1 /* Default case these days */
-#define BIOS_TRANSLATION_25563 2 /* Big disk case */
+#define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */
+#define BIOS_TRANSLATION_6432 1 /* Default case these days */
+#define BIOS_TRANSLATION_25563 2 /* Big disk case */
-struct aha1542_hostdata{
+struct aha1542_hostdata {
/* This will effectively start both of them at the first mailbox */
- int bios_translation; /* Mapping bios uses - for compatibility */
+ int bios_translation; /* Mapping bios uses - for compatibility */
int aha1542_last_mbi_used;
int aha1542_last_mbo_used;
- Scsi_Cmnd * SCint[AHA1542_MAILBOXES];
- struct mailbox mb[2*AHA1542_MAILBOXES];
+ Scsi_Cmnd *SCint[AHA1542_MAILBOXES];
+ struct mailbox mb[2 * AHA1542_MAILBOXES];
struct ccb ccb[AHA1542_MAILBOXES];
};
#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata)
-static struct Scsi_Host * aha_host[7] = {NULL,}; /* One for each IRQ level (9-15) */
+static struct Scsi_Host *aha_host[7]; /* One for each IRQ level (9-15) */
#define WAITnexttimeout 3000000
-static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt);
-static int aha1542_restart(struct Scsi_Host * shost);
+static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
+static int aha1542_restart(struct Scsi_Host *shost);
static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
static void aha1542_stat(void)
{
-/* int s = inb(STATUS), i = inb(INTRFLAGS);
- printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
+/* int s = inb(STATUS), i = inb(INTRFLAGS);
+ printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
}
/* This is a bit complicated, but we need to make sure that an interrupt
routine does not send something out while we are in the middle of this.
Fortunately, it is only at boot time that multi-byte messages
are ever sent. */
-static int aha1542_out(unsigned int base, unchar *cmdp, int len)
+static int aha1542_out(unsigned int base, unchar * cmdp, int len)
{
- unsigned long flags = 0;
-
- save_flags(flags);
- if(len == 1) {
- while(1==1){
- WAIT(STATUS(base), CDF, 0, CDF);
- cli();
- if(inb(STATUS(base)) & CDF) {restore_flags(flags); continue;}
- outb(*cmdp, DATA(base));
- restore_flags(flags);
+ unsigned long flags = 0;
+
+ save_flags(flags);
+ if (len == 1) {
+ while (1 == 1) {
+ WAIT(STATUS(base), CDF, 0, CDF);
+ cli();
+ if (inb(STATUS(base)) & CDF) {
+ restore_flags(flags);
+ continue;
+ }
+ outb(*cmdp, DATA(base));
+ restore_flags(flags);
+ return 0;
+ }
+ } else {
+ cli();
+ while (len--) {
+ WAIT(STATUS(base), CDF, 0, CDF);
+ outb(*cmdp++, DATA(base));
+ }
+ restore_flags(flags);
+ }
return 0;
- }
- } else {
- cli();
- while (len--)
- {
- WAIT(STATUS(base), CDF, 0, CDF);
- outb(*cmdp++, DATA(base));
- }
- restore_flags(flags);
- }
- return 0;
- fail:
- restore_flags(flags);
- printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
- return 1;
+fail:
+ restore_flags(flags);
+ printk(KERN_ERR "aha1542_out failed(%d): ", len + 1);
+ aha1542_stat();
+ return 1;
}
/* Only used at boot time, so we do not need to worry about latency as much
here */
-static int aha1542_in(unsigned int base, unchar *cmdp, int len)
+
+static int aha1542_in(unsigned int base, unchar * cmdp, int len)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- while (len--)
- {
- WAIT(STATUS(base), DF, DF, 0);
- *cmdp++ = inb(DATA(base));
- }
- restore_flags(flags);
- return 0;
- fail:
- restore_flags(flags);
- printk("aha1542_in failed(%d): ", len+1); aha1542_stat();
- return 1;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ while (len--) {
+ WAIT(STATUS(base), DF, DF, 0);
+ *cmdp++ = inb(DATA(base));
+ }
+ restore_flags(flags);
+ return 0;
+fail:
+ restore_flags(flags);
+ printk(KERN_ERR "aha1542_in failed(%d): ", len + 1);
+ aha1542_stat();
+ return 1;
}
/* Similar to aha1542_in, except that we wait a very short period of time.
We use this if we know the board is alive and awake, but we are not sure
if the board will respond to the command we are about to send or not */
-static int aha1542_in1(unsigned int base, unchar *cmdp, int len)
+static int aha1542_in1(unsigned int base, unchar * cmdp, int len)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- while (len--)
- {
- WAITd(STATUS(base), DF, DF, 0, 100);
- *cmdp++ = inb(DATA(base));
- }
- restore_flags(flags);
- return 0;
- fail:
- restore_flags(flags);
- return 1;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ while (len--) {
+ WAITd(STATUS(base), DF, DF, 0, 100);
+ *cmdp++ = inb(DATA(base));
+ }
+ restore_flags(flags);
+ return 0;
+fail:
+ restore_flags(flags);
+ return 1;
}
static int makecode(unsigned hosterr, unsigned scsierr)
{
- switch (hosterr) {
- case 0x0:
- case 0xa: /* Linked command complete without error and linked normally */
- case 0xb: /* Linked command complete without error, interrupt generated */
- hosterr = 0;
- break;
-
- case 0x11: /* Selection time out-The initiator selection or target
- reselection was not complete within the SCSI Time out period */
- hosterr = DID_TIME_OUT;
- break;
-
- case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
- than was allocated by the Data Length field or the sum of the
- Scatter / Gather Data Length fields. */
-
- case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
-
- case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
- invalid. This usually indicates a software failure. */
-
- case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
- This usually indicates a software failure. */
-
- case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
- of linked CCB's does not specify the same logical unit number as
- the first. */
- case 0x18: /* Invalid Target Direction received from Host-The direction of a
- Target Mode CCB was invalid. */
-
- case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
- received to service data transfer between the same target LUN
- and initiator SCSI ID in the same direction. */
-
- case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
- length segment or invalid segment list boundaries was received.
- A CCB parameter was invalid. */
- DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
- hosterr = DID_ERROR; /* Couldn't find any better */
- break;
-
- case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
- phase sequence was requested by the target. The host adapter
- will generate a SCSI Reset Condition, notifying the host with
- a SCRD interrupt */
- hosterr = DID_RESET;
- break;
- default:
- printk("makecode: unknown hoststatus %x\n", hosterr);
- break;
- }
- return scsierr|(hosterr << 16);
+ switch (hosterr) {
+ case 0x0:
+ case 0xa: /* Linked command complete without error and linked normally */
+ case 0xb: /* Linked command complete without error, interrupt generated */
+ hosterr = 0;
+ break;
+
+ case 0x11: /* Selection time out-The initiator selection or target
+ reselection was not complete within the SCSI Time out period */
+ hosterr = DID_TIME_OUT;
+ break;
+
+ case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
+ than was allocated by the Data Length field or the sum of the
+ Scatter / Gather Data Length fields. */
+
+ case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+ case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
+ invalid. This usually indicates a software failure. */
+
+ case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
+ This usually indicates a software failure. */
+
+ case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
+ of linked CCB's does not specify the same logical unit number as
+ the first. */
+ case 0x18: /* Invalid Target Direction received from Host-The direction of a
+ Target Mode CCB was invalid. */
+
+ case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
+ received to service data transfer between the same target LUN
+ and initiator SCSI ID in the same direction. */
+
+ case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
+ length segment or invalid segment list boundaries was received.
+ A CCB parameter was invalid. */
+ DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
+ hosterr = DID_ERROR; /* Couldn't find any better */
+ break;
+
+ case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
+ phase sequence was requested by the target. The host adapter
+ will generate a SCSI Reset Condition, notifying the host with
+ a SCRD interrupt */
+ hosterr = DID_RESET;
+ break;
+ default:
+ printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
+ break;
+ }
+ return scsierr | (hosterr << 16);
}
-static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
+static int aha1542_test_port(int bse, struct Scsi_Host *shpnt)
{
- unchar inquiry_cmd[] = {CMD_INQUIRY };
- unchar inquiry_result[4];
- unchar *cmdp;
- int len;
- volatile int debug = 0;
-
- /* Quick and dirty test for presence of the card. */
- if(inb(STATUS(bse)) == 0xff) return 0;
-
- /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
-
- /* DEB(printk("aha1542_test_port called \n")); */
-
- /* In case some other card was probing here, reset interrupts */
- aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
-
- outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
-
- mdelay(20); /* Wait a little bit for things to settle down. */
-
- debug = 1;
- /* Expect INIT and IDLE, any of the others are bad */
- WAIT(STATUS(bse), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
-
- debug = 2;
- /* Shouldn't have generated any interrupts during reset */
- if (inb(INTRFLAGS(bse))&INTRMASK) goto fail;
-
-
- /* Perform a host adapter inquiry instead so we do not need to set
- up the mailboxes ahead of time */
-
- aha1542_out(bse, inquiry_cmd, 1);
-
- debug = 3;
- len = 4;
- cmdp = &inquiry_result[0];
-
- while (len--)
- {
- WAIT(STATUS(bse), DF, DF, 0);
- *cmdp++ = inb(DATA(bse));
- }
-
- debug = 8;
- /* Reading port should reset DF */
- if (inb(STATUS(bse)) & DF) goto fail;
-
- debug = 9;
- /* When HACC, command is completed, and we're though testing */
- WAIT(INTRFLAGS(bse), HACC, HACC, 0);
- /* now initialize adapter */
-
- debug = 10;
- /* Clear interrupts */
- outb(IRST, CONTROL(bse));
-
- debug = 11;
-
- return debug; /* 1 = ok */
- fail:
- return 0; /* 0 = not ok */
+ unchar inquiry_cmd[] = {CMD_INQUIRY};
+ unchar inquiry_result[4];
+ unchar *cmdp;
+ int len;
+ volatile int debug = 0;
+
+ /* Quick and dirty test for presence of the card. */
+ if (inb(STATUS(bse)) == 0xff)
+ return 0;
+
+ /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
+
+ /* DEB(printk("aha1542_test_port called \n")); */
+
+ /* In case some other card was probing here, reset interrupts */
+ aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
+
+ outb(SRST | IRST /*|SCRST */ , CONTROL(bse));
+
+ mdelay(20); /* Wait a little bit for things to settle down. */
+
+ debug = 1;
+ /* Expect INIT and IDLE, any of the others are bad */
+ WAIT(STATUS(bse), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+ debug = 2;
+ /* Shouldn't have generated any interrupts during reset */
+ if (inb(INTRFLAGS(bse)) & INTRMASK)
+ goto fail;
+
+
+ /* Perform a host adapter inquiry instead so we do not need to set
+ up the mailboxes ahead of time */
+
+ aha1542_out(bse, inquiry_cmd, 1);
+
+ debug = 3;
+ len = 4;
+ cmdp = &inquiry_result[0];
+
+ while (len--) {
+ WAIT(STATUS(bse), DF, DF, 0);
+ *cmdp++ = inb(DATA(bse));
+ }
+
+ debug = 8;
+ /* Reading port should reset DF */
+ if (inb(STATUS(bse)) & DF)
+ goto fail;
+
+ debug = 9;
+ /* When HACC, command is completed, and we're though testing */
+ WAIT(INTRFLAGS(bse), HACC, HACC, 0);
+ /* now initialize adapter */
+
+ debug = 10;
+ /* Clear interrupts */
+ outb(IRST, CONTROL(bse));
+
+ debug = 11;
+
+ return debug; /* 1 = ok */
+fail:
+ return 0; /* 0 = not ok */
}
/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned long flags;
+ unsigned long flags;
- spin_lock_irqsave(&io_request_lock, flags);
- aha1542_intr_handle(irq, dev_id, regs);
- spin_unlock_irqrestore(&io_request_lock, flags);
+ spin_lock_irqsave(&io_request_lock, flags);
+ aha1542_intr_handle(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
/* A "high" level interrupt handler */
static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
{
- void (*my_done)(Scsi_Cmnd *) = NULL;
- int errstatus, mbi, mbo, mbistatus;
- int number_serviced;
- unsigned int flags;
- struct Scsi_Host * shost;
- Scsi_Cmnd * SCtmp;
- int flag;
- int needs_restart;
- struct mailbox * mb;
- struct ccb *ccb;
-
- shost = aha_host[irq - 9];
- if(!shost) panic("Splunge!");
-
- mb = HOSTDATA(shost)->mb;
- ccb = HOSTDATA(shost)->ccb;
+ void (*my_done) (Scsi_Cmnd *) = NULL;
+ int errstatus, mbi, mbo, mbistatus;
+ int number_serviced;
+ unsigned int flags;
+ struct Scsi_Host *shost;
+ Scsi_Cmnd *SCtmp;
+ int flag;
+ int needs_restart;
+ struct mailbox *mb;
+ struct ccb *ccb;
+
+ shost = aha_host[irq - 9];
+ if (!shost)
+ panic("Splunge!");
+
+ mb = HOSTDATA(shost)->mb;
+ ccb = HOSTDATA(shost)->ccb;
#ifdef DEBUG
- {
- flag = inb(INTRFLAGS(shost->io_port));
- printk("aha1542_intr_handle: ");
- if (!(flag&ANYINTR)) printk("no interrupt?");
- if (flag&MBIF) printk("MBIF ");
- if (flag&MBOA) printk("MBOF ");
- if (flag&HACC) printk("HACC ");
- if (flag&SCRD) printk("SCRD ");
- printk("status %02x\n", inb(STATUS(shost->io_port)));
- };
+ {
+ flag = inb(INTRFLAGS(shost->io_port));
+ printk(KERN_DEBUG "aha1542_intr_handle: ");
+ if (!(flag & ANYINTR))
+ printk("no interrupt?");
+ if (flag & MBIF)
+ printk("MBIF ");
+ if (flag & MBOA)
+ printk("MBOF ");
+ if (flag & HACC)
+ printk("HACC ");
+ if (flag & SCRD)
+ printk("SCRD ");
+ printk("status %02x\n", inb(STATUS(shost->io_port)));
+ };
#endif
- number_serviced = 0;
- needs_restart = 0;
-
- while(1==1){
- flag = inb(INTRFLAGS(shost->io_port));
-
- /* Check for unusual interrupts. If any of these happen, we should
- probably do something special, but for now just printing a message
- is sufficient. A SCSI reset detected is something that we really
- need to deal with in some way. */
- if (flag & ~MBIF) {
- if (flag&MBOA) printk("MBOF ");
- if (flag&HACC) printk("HACC ");
- if (flag&SCRD) {
- needs_restart = 1;
- printk("SCRD ");
- }
- }
-
- aha1542_intr_reset(shost->io_port);
-
- save_flags(flags);
- cli();
- mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
- if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
-
- do{
- if(mb[mbi].status != 0) break;
- mbi++;
- if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
- } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
-
- if(mb[mbi].status == 0){
- restore_flags(flags);
- /* Hmm, no mail. Must have read it the last time around */
- if (!number_serviced && !needs_restart)
- printk("aha1542.c: interrupt received, but no mail.\n");
- /* We detected a reset. Restart all pending commands for
- devices that use the hard reset option */
- if(needs_restart) aha1542_restart(shost);
- return;
- };
-
- mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_PA(&ccb[0]))) / sizeof(struct ccb);
- mbistatus = mb[mbi].status;
- mb[mbi].status = 0;
- HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
- restore_flags(flags);
-
+ number_serviced = 0;
+ needs_restart = 0;
+
+ while (1 == 1) {
+ flag = inb(INTRFLAGS(shost->io_port));
+
+ /* Check for unusual interrupts. If any of these happen, we should
+ probably do something special, but for now just printing a message
+ is sufficient. A SCSI reset detected is something that we really
+ need to deal with in some way. */
+ if (flag & ~MBIF) {
+ if (flag & MBOA)
+ printk("MBOF ");
+ if (flag & HACC)
+ printk("HACC ");
+ if (flag & SCRD) {
+ needs_restart = 1;
+ printk("SCRD ");
+ }
+ }
+ aha1542_intr_reset(shost->io_port);
+
+ save_flags(flags);
+ cli();
+ mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
+ if (mbi >= 2 * AHA1542_MAILBOXES)
+ mbi = AHA1542_MAILBOXES;
+
+ do {
+ if (mb[mbi].status != 0)
+ break;
+ mbi++;
+ if (mbi >= 2 * AHA1542_MAILBOXES)
+ mbi = AHA1542_MAILBOXES;
+ } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
+
+ if (mb[mbi].status == 0) {
+ restore_flags(flags);
+ /* Hmm, no mail. Must have read it the last time around */
+ if (!number_serviced && !needs_restart)
+ printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n");
+ /* We detected a reset. Restart all pending commands for
+ devices that use the hard reset option */
+ if (needs_restart)
+ aha1542_restart(shost);
+ return;
+ };
+
+ mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_PA(&ccb[0]))) / sizeof(struct ccb);
+ mbistatus = mb[mbi].status;
+ mb[mbi].status = 0;
+ HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
+ restore_flags(flags);
+
#ifdef DEBUG
- {
- if (ccb[mbo].tarstat|ccb[mbo].hastat)
- printk("aha1542_command: returning %x (status %d)\n",
- ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
- };
+ {
+ if (ccb[mbo].tarstat | ccb[mbo].hastat)
+ printk(KERN_DEBUG "aha1542_command: returning %x (status %d)\n",
+ ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
+ };
#endif
- if(mbistatus == 3) continue; /* Aborted command not found */
+ if (mbistatus == 3)
+ continue; /* Aborted command not found */
#ifdef DEBUG
- printk("...done %d %d\n",mbo, mbi);
+ printk(KERN_DEBUG "...done %d %d\n", mbo, mbi);
#endif
-
- SCtmp = HOSTDATA(shost)->SCint[mbo];
-
- if (!SCtmp || !SCtmp->scsi_done) {
- printk("aha1542_intr_handle: Unexpected interrupt\n");
- printk("tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat,
- ccb[mbo].hastat, ccb[mbo].idlun, mbo);
- return;
- }
-
- my_done = SCtmp->scsi_done;
- if (SCtmp->host_scribble) {
- scsi_free(SCtmp->host_scribble, 512);
- SCtmp->host_scribble = 0;
- }
-
- /* Fetch the sense data, and tuck it away, in the required slot. The
- Adaptec automatically fetches it, and there is no guarantee that
- we will still have it in the cdb when we come back */
- if (ccb[mbo].tarstat == 2)
- memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
- sizeof(SCtmp->sense_buffer));
-
-
- /* is there mail :-) */
-
- /* more error checking left out here */
- if (mbistatus != 1)
- /* This is surely wrong, but I don't know what's right */
- errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
- else
- errstatus = 0;
-
+
+ SCtmp = HOSTDATA(shost)->SCint[mbo];
+
+ if (!SCtmp || !SCtmp->scsi_done) {
+ printk(KERN_WARNING "aha1542_intr_handle: Unexpected interrupt\n");
+ printk(KERN_WARNING "tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat,
+ ccb[mbo].hastat, ccb[mbo].idlun, mbo);
+ return;
+ }
+ my_done = SCtmp->scsi_done;
+ if (SCtmp->host_scribble) {
+ scsi_free(SCtmp->host_scribble, 512);
+ SCtmp->host_scribble = 0;
+ }
+ /* Fetch the sense data, and tuck it away, in the required slot. The
+ Adaptec automatically fetches it, and there is no guarantee that
+ we will still have it in the cdb when we come back */
+ if (ccb[mbo].tarstat == 2)
+ memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
+ sizeof(SCtmp->sense_buffer));
+
+
+ /* is there mail :-) */
+
+ /* more error checking left out here */
+ if (mbistatus != 1)
+ /* This is surely wrong, but I don't know what's right */
+ errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
+ else
+ errstatus = 0;
+
#ifdef DEBUG
- if(errstatus) printk("(aha1542 error:%x %x %x) ",errstatus,
- ccb[mbo].hastat, ccb[mbo].tarstat);
+ if (errstatus)
+ printk(KERN_DEBUG "(aha1542 error:%x %x %x) ", errstatus,
+ ccb[mbo].hastat, ccb[mbo].tarstat);
#endif
- if (ccb[mbo].tarstat == 2) {
+ if (ccb[mbo].tarstat == 2) {
#ifdef DEBUG
- int i;
+ int i;
#endif
- DEB(printk("aha1542_intr_handle: sense:"));
+ DEB(printk("aha1542_intr_handle: sense:"));
#ifdef DEBUG
- for (i = 0; i < 12; i++)
- printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen+i]);
- printk("\n");
+ for (i = 0; i < 12; i++)
+ printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]);
+ printk("\n");
#endif
- /*
- DEB(printk("aha1542_intr_handle: buf:"));
- for (i = 0; i < bufflen; i++)
- printk("%02x ", ((unchar *)buff)[i]);
- printk("\n");
- */
- }
- DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
- SCtmp->result = errstatus;
- HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as
- far as queuecommand is concerned */
- my_done(SCtmp);
- number_serviced++;
- };
+ /*
+ DEB(printk("aha1542_intr_handle: buf:"));
+ for (i = 0; i < bufflen; i++)
+ printk("%02x ", ((unchar *)buff)[i]);
+ printk("\n");
+ */
+ }
+ DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
+ SCtmp->result = errstatus;
+ HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as
+ far as queuecommand is concerned */
+ my_done(SCtmp);
+ number_serviced++;
+ };
}
-int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
- unchar ahacmd = CMD_START_SCSI;
- unchar direction;
- unchar *cmd = (unchar *) SCpnt->cmnd;
- unchar target = SCpnt->target;
- unchar lun = SCpnt->lun;
- unsigned long flags;
- void *buff = SCpnt->request_buffer;
- int bufflen = SCpnt->request_bufflen;
- int mbo;
- struct mailbox * mb;
- struct ccb *ccb;
-
- DEB(int i);
-
- mb = HOSTDATA(SCpnt->host)->mb;
- ccb = HOSTDATA(SCpnt->host)->ccb;
-
- DEB(if (target > 1) {
- SCpnt->result = DID_TIME_OUT << 16;
- done(SCpnt); return 0;});
-
- if(*cmd == REQUEST_SENSE){
- /* Don't do the command - we have the sense data already */
+ unchar ahacmd = CMD_START_SCSI;
+ unchar direction;
+ unchar *cmd = (unchar *) SCpnt->cmnd;
+ unchar target = SCpnt->target;
+ unchar lun = SCpnt->lun;
+ unsigned long flags;
+ void *buff = SCpnt->request_buffer;
+ int bufflen = SCpnt->request_bufflen;
+ int mbo;
+ struct mailbox *mb;
+ struct ccb *ccb;
+
+ DEB(int i);
+
+ mb = HOSTDATA(SCpnt->host)->mb;
+ ccb = HOSTDATA(SCpnt->host)->ccb;
+
+ DEB(if (target > 1) {
+ SCpnt->result = DID_TIME_OUT << 16;
+ done(SCpnt); return 0;
+ }
+ );
+
+ if (*cmd == REQUEST_SENSE) {
+ /* Don't do the command - we have the sense data already */
#if 0
- /* scsi_request_sense() provides a buffer of size 256,
- so there is no reason to expect equality */
- if (bufflen != sizeof(SCpnt->sense_buffer))
- printk("aha1542: Wrong buffer length supplied "
- "for request sense (%d)\n", bufflen);
+ /* scsi_request_sense() provides a buffer of size 256,
+ so there is no reason to expect equality */
+ if (bufflen != sizeof(SCpnt->sense_buffer))
+ printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
+ "for request sense (%d)\n", bufflen);
#endif
- SCpnt->result = 0;
- done(SCpnt);
- return 0;
- }
-
+ SCpnt->result = 0;
+ done(SCpnt);
+ return 0;
+ }
#ifdef DEBUG
- if (*cmd == READ_10 || *cmd == WRITE_10)
- i = xscsi2int(cmd+2);
- else if (*cmd == READ_6 || *cmd == WRITE_6)
- i = scsi2int(cmd+2);
- else
- i = -1;
- if (done)
- printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
- else
- printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
- aha1542_stat();
- printk("aha1542_queuecommand: dumping scsi cmd:");
- for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
- printk("\n");
- if (*cmd == WRITE_10 || *cmd == WRITE_6)
- return 0; /* we are still testing, so *don't* write */
+ if (*cmd == READ_10 || *cmd == WRITE_10)
+ i = xscsi2int(cmd + 2);
+ else if (*cmd == READ_6 || *cmd == WRITE_6)
+ i = scsi2int(cmd + 2);
+ else
+ i = -1;
+ if (done)
+ printk(KERN_DEBUG "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+ else
+ printk(KERN_DEBUG "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+ aha1542_stat();
+ printk(KERN_DEBUG "aha1542_queuecommand: dumping scsi cmd:");
+ for (i = 0; i < SCpnt->cmd_len; i++)
+ printk("%02x ", cmd[i]);
+ printk("\n");
+ if (*cmd == WRITE_10 || *cmd == WRITE_6)
+ return 0; /* we are still testing, so *don't* write */
#endif
-/* Use the outgoing mailboxes in a round-robin fashion, because this
- is how the host adapter will scan for them */
+ /* Use the outgoing mailboxes in a round-robin fashion, because this
+ is how the host adapter will scan for them */
- save_flags(flags);
- cli();
- mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
- if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+ save_flags(flags);
+ cli();
+ mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
+ if (mbo >= AHA1542_MAILBOXES)
+ mbo = 0;
- do{
- if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
- break;
- mbo++;
- if (mbo >= AHA1542_MAILBOXES) mbo = 0;
- } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
+ do {
+ if (mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+ break;
+ mbo++;
+ if (mbo >= AHA1542_MAILBOXES)
+ mbo = 0;
+ } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
- if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
- panic("Unable to find empty mailbox for aha1542.\n");
+ if (mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
+ panic("Unable to find empty mailbox for aha1542.\n");
- HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from
- screwing with this cdb. */
+ HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from
+ screwing with this cdb. */
- HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
- restore_flags(flags);
+ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
+ restore_flags(flags);
#ifdef DEBUG
- printk("Sending command (%d %x)...",mbo, done);
+ printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done);
#endif
- any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
+ any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason */
- memset(&ccb[mbo], 0, sizeof(struct ccb));
+ memset(&ccb[mbo], 0, sizeof(struct ccb));
- ccb[mbo].cdblen = SCpnt->cmd_len;
+ ccb[mbo].cdblen = SCpnt->cmd_len;
- direction = 0;
- if (*cmd == READ_10 || *cmd == READ_6)
- direction = 8;
- else if (*cmd == WRITE_10 || *cmd == WRITE_6)
- direction = 16;
+ direction = 0;
+ if (*cmd == READ_10 || *cmd == READ_6)
+ direction = 8;
+ else if (*cmd == WRITE_10 || *cmd == WRITE_6)
+ direction = 16;
- memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
+ memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
- if (SCpnt->use_sg) {
- struct scatterlist * sgpnt;
- struct chain * cptr;
+ if (SCpnt->use_sg) {
+ struct scatterlist *sgpnt;
+ struct chain *cptr;
#ifdef DEBUG
- unsigned char * ptr;
+ unsigned char *ptr;
#endif
- int i;
- ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather*/
- SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
- cptr = (struct chain *) SCpnt->host_scribble;
- if (cptr == NULL) panic("aha1542.c: unable to allocate DMA memory\n");
- for(i=0; i<SCpnt->use_sg; i++) {
- if(sgpnt[i].length == 0 || SCpnt->use_sg > 16 ||
- (((int)sgpnt[i].address) & 1) || (sgpnt[i].length & 1)){
- unsigned char * ptr;
- printk("Bad segment list supplied to aha1542.c (%d, %d)\n",SCpnt->use_sg,i);
- for(i=0;i<SCpnt->use_sg;i++){
- printk("%d: %x %x %d\n",i,(unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
- sgpnt[i].length);
- };
- printk("cptr %x: ",(unsigned int) cptr);
- ptr = (unsigned char *) &cptr[i];
- for(i=0;i<18;i++) printk("%02x ", ptr[i]);
- panic("Foooooooood fight!");
- };
- any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address));
- if(SCSI_PA(sgpnt[i].address+sgpnt[i].length-1) > ISA_DMA_THRESHOLD)
- BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
- any2scsi(cptr[i].datalen, sgpnt[i].length);
- };
- any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
- any2scsi(ccb[mbo].dataptr, SCSI_PA(cptr));
+ int i;
+ ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
+ SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
+ sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+ cptr = (struct chain *) SCpnt->host_scribble;
+ if (cptr == NULL)
+ panic("aha1542.c: unable to allocate DMA memory\n");
+ for (i = 0; i < SCpnt->use_sg; i++) {
+ if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 ||
+ (((int) sgpnt[i].address) & 1) || (sgpnt[i].length & 1)) {
+ unsigned char *ptr;
+ printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
+ for (i = 0; i < SCpnt->use_sg; i++) {
+ printk(KERN_CRIT "%d: %x %x %d\n", i, (unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
+ sgpnt[i].length);
+ };
+ printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
+ ptr = (unsigned char *) &cptr[i];
+ for (i = 0; i < 18; i++)
+ printk("%02x ", ptr[i]);
+ panic("Foooooooood fight!");
+ };
+ any2scsi(cptr[i].dataptr, SCSI_PA(sgpnt[i].address));
+ if (SCSI_PA(sgpnt[i].address + sgpnt[i].length - 1) > ISA_DMA_THRESHOLD)
+ BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
+ any2scsi(cptr[i].datalen, sgpnt[i].length);
+ };
+ any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
+ any2scsi(ccb[mbo].dataptr, SCSI_PA(cptr));
#ifdef DEBUG
- printk("cptr %x: ",cptr);
- ptr = (unsigned char *) cptr;
- for(i=0;i<18;i++) printk("%02x ", ptr[i]);
+ printk("cptr %x: ", cptr);
+ ptr = (unsigned char *) cptr;
+ for (i = 0; i < 18; i++)
+ printk("%02x ", ptr[i]);
#endif
- } else {
- ccb[mbo].op = 0; /* SCSI Initiator Command */
- SCpnt->host_scribble = NULL;
- any2scsi(ccb[mbo].datalen, bufflen);
- if(buff && SCSI_PA(buff+bufflen-1) > ISA_DMA_THRESHOLD)
- BAD_DMA(buff, bufflen);
- any2scsi(ccb[mbo].dataptr, SCSI_PA(buff));
- };
- ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/
- ccb[mbo].rsalen = 16;
- ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
- ccb[mbo].commlinkid = 0;
+ } else {
+ ccb[mbo].op = 0; /* SCSI Initiator Command */
+ SCpnt->host_scribble = NULL;
+ any2scsi(ccb[mbo].datalen, bufflen);
+ if (buff && SCSI_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
+ BAD_DMA(buff, bufflen);
+ any2scsi(ccb[mbo].dataptr, SCSI_PA(buff));
+ };
+ ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */
+ ccb[mbo].rsalen = 16;
+ ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+ ccb[mbo].commlinkid = 0;
#ifdef DEBUG
- { int i;
- printk("aha1542_command: sending.. ");
- for (i = 0; i < sizeof(ccb[mbo])-10; i++)
- printk("%02x ", ((unchar *)&ccb[mbo])[i]);
- };
+ {
+ int i;
+ printk(KERN_DEBUG "aha1542_command: sending.. ");
+ for (i = 0; i < sizeof(ccb[mbo]) - 10; i++)
+ printk("%02x ", ((unchar *) & ccb[mbo])[i]);
+ };
#endif
-
- if (done) {
- DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
- SCpnt->scsi_done = done;
- mb[mbo].status = 1;
- aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */
- DEB(aha1542_stat());
- }
- else
- printk("aha1542_queuecommand: done can't be NULL\n");
-
- return 0;
+
+ if (done) {
+ DEB(printk("aha1542_queuecommand: now waiting for interrupt ");
+ aha1542_stat());
+ SCpnt->scsi_done = done;
+ mb[mbo].status = 1;
+ aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */
+ DEB(aha1542_stat());
+ } else
+ printk("aha1542_queuecommand: done can't be NULL\n");
+
+ return 0;
}
static void internal_done(Scsi_Cmnd * SCpnt)
int aha1542_command(Scsi_Cmnd * SCpnt)
{
- DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
+ DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
- aha1542_queuecommand(SCpnt, internal_done);
+ aha1542_queuecommand(SCpnt, internal_done);
- SCpnt->SCp.Status = 0;
- while (!SCpnt->SCp.Status)
- barrier();
- return SCpnt->result;
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status)
+ barrier();
+ return SCpnt->result;
}
/* Initialize mailboxes */
-static void setup_mailboxes(int bse, struct Scsi_Host * shpnt)
+static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
{
- int i;
- struct mailbox * mb;
- struct ccb *ccb;
-
- unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
-
- mb = HOSTDATA(shpnt)->mb;
- ccb = HOSTDATA(shpnt)->ccb;
-
- for(i=0; i<AHA1542_MAILBOXES; i++){
- mb[i].status = mb[AHA1542_MAILBOXES+i].status = 0;
- any2scsi(mb[i].ccbptr, SCSI_PA(&ccb[i]));
- };
- aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
- any2scsi((cmd+2), SCSI_PA(mb));
- aha1542_out(bse, cmd, 5);
- WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
- while (0) {
- fail:
- printk("aha1542_detect: failed setting up mailboxes\n");
- }
- aha1542_intr_reset(bse);
+ int i;
+ struct mailbox *mb;
+ struct ccb *ccb;
+
+ unchar cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
+
+ mb = HOSTDATA(shpnt)->mb;
+ ccb = HOSTDATA(shpnt)->ccb;
+
+ for (i = 0; i < AHA1542_MAILBOXES; i++) {
+ mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
+ any2scsi(mb[i].ccbptr, SCSI_PA(&ccb[i]));
+ };
+ aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
+ any2scsi((cmd + 2), SCSI_PA(mb));
+ aha1542_out(bse, cmd, 5);
+ WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
+ while (0) {
+fail:
+ printk(KERN_ERR "aha1542_detect: failed setting up mailboxes\n");
+ }
+ aha1542_intr_reset(bse);
}
-static int aha1542_getconfig(int base_io, unsigned char * irq_level, unsigned char * dma_chan, unsigned char * scsi_id)
+static int aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id)
{
- unchar inquiry_cmd[] = {CMD_RETCONF };
- unchar inquiry_result[3];
- int i;
- i = inb(STATUS(base_io));
- if (i & DF) {
- i = inb(DATA(base_io));
- };
- aha1542_out(base_io, inquiry_cmd, 1);
- aha1542_in(base_io, inquiry_result, 3);
- WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
- while (0) {
- fail:
- printk("aha1542_detect: query board settings\n");
- }
- aha1542_intr_reset(base_io);
- switch(inquiry_result[0]){
- case 0x80:
- *dma_chan = 7;
- break;
- case 0x40:
- *dma_chan = 6;
- break;
- case 0x20:
- *dma_chan = 5;
- break;
- case 0x01:
- *dma_chan = 0;
- break;
- case 0:
- /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
- Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
- *dma_chan = 0xFF;
- break;
- default:
- printk("Unable to determine Adaptec DMA priority. Disabling board\n");
- return -1;
- };
- switch(inquiry_result[1]){
- case 0x40:
- *irq_level = 15;
- break;
- case 0x20:
- *irq_level = 14;
- break;
- case 0x8:
- *irq_level = 12;
- break;
- case 0x4:
- *irq_level = 11;
- break;
- case 0x2:
- *irq_level = 10;
- break;
- case 0x1:
- *irq_level = 9;
- break;
- default:
- printk("Unable to determine Adaptec IRQ level. Disabling board\n");
- return -1;
- };
- *scsi_id=inquiry_result[2] & 7;
- return 0;
+ unchar inquiry_cmd[] = {CMD_RETCONF};
+ unchar inquiry_result[3];
+ int i;
+ i = inb(STATUS(base_io));
+ if (i & DF) {
+ i = inb(DATA(base_io));
+ };
+ aha1542_out(base_io, inquiry_cmd, 1);
+ aha1542_in(base_io, inquiry_result, 3);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ while (0) {
+fail:
+ printk(KERN_ERR "aha1542_detect: query board settings\n");
+ }
+ aha1542_intr_reset(base_io);
+ switch (inquiry_result[0]) {
+ case 0x80:
+ *dma_chan = 7;
+ break;
+ case 0x40:
+ *dma_chan = 6;
+ break;
+ case 0x20:
+ *dma_chan = 5;
+ break;
+ case 0x01:
+ *dma_chan = 0;
+ break;
+ case 0:
+ /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
+ Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
+ *dma_chan = 0xFF;
+ break;
+ default:
+ printk(KERN_ERR "Unable to determine Adaptec DMA priority. Disabling board\n");
+ return -1;
+ };
+ switch (inquiry_result[1]) {
+ case 0x40:
+ *irq_level = 15;
+ break;
+ case 0x20:
+ *irq_level = 14;
+ break;
+ case 0x8:
+ *irq_level = 12;
+ break;
+ case 0x4:
+ *irq_level = 11;
+ break;
+ case 0x2:
+ *irq_level = 10;
+ break;
+ case 0x1:
+ *irq_level = 9;
+ break;
+ default:
+ printk(KERN_ERR "Unable to determine Adaptec IRQ level. Disabling board\n");
+ return -1;
+ };
+ *scsi_id = inquiry_result[2] & 7;
+ return 0;
}
/* This function should only be called for 1542C boards - we can detect
static int aha1542_mbenable(int base)
{
- static unchar mbenable_cmd[3];
- static unchar mbenable_result[2];
- int retval;
-
- retval = BIOS_TRANSLATION_6432;
-
- mbenable_cmd[0]=CMD_EXTBIOS;
- aha1542_out(base,mbenable_cmd,1);
- if(aha1542_in1(base,mbenable_result,2))
- return retval;
- WAITd(INTRFLAGS(base),INTRMASK,HACC,0,100);
- aha1542_intr_reset(base);
-
- if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
- mbenable_cmd[0]=CMD_MBENABLE;
- mbenable_cmd[1]=0;
- mbenable_cmd[2]=mbenable_result[1];
-
- if((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
- retval = BIOS_TRANSLATION_25563;
-
- aha1542_out(base,mbenable_cmd,3);
- WAIT(INTRFLAGS(base),INTRMASK,HACC,0);
- };
- while(0) {
+ static unchar mbenable_cmd[3];
+ static unchar mbenable_result[2];
+ int retval;
+
+ retval = BIOS_TRANSLATION_6432;
+
+ mbenable_cmd[0] = CMD_EXTBIOS;
+ aha1542_out(base, mbenable_cmd, 1);
+ if (aha1542_in1(base, mbenable_result, 2))
+ return retval;
+ WAITd(INTRFLAGS(base), INTRMASK, HACC, 0, 100);
+ aha1542_intr_reset(base);
+
+ if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
+ mbenable_cmd[0] = CMD_MBENABLE;
+ mbenable_cmd[1] = 0;
+ mbenable_cmd[2] = mbenable_result[1];
+
+ if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
+ retval = BIOS_TRANSLATION_25563;
+
+ aha1542_out(base, mbenable_cmd, 3);
+ WAIT(INTRFLAGS(base), INTRMASK, HACC, 0);
+ };
+ while (0) {
fail:
- printk("aha1542_mbenable: Mailbox init failed\n");
- }
-aha1542_intr_reset(base);
-return retval;
+ printk(KERN_ERR "aha1542_mbenable: Mailbox init failed\n");
+ }
+ aha1542_intr_reset(base);
+ return retval;
}
/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
-static int aha1542_query(int base_io, int * transl)
+static int aha1542_query(int base_io, int *transl)
{
- unchar inquiry_cmd[] = {CMD_INQUIRY };
- unchar inquiry_result[4];
- int i;
- i = inb(STATUS(base_io));
- if (i & DF) {
- i = inb(DATA(base_io));
- };
- aha1542_out(base_io, inquiry_cmd, 1);
- aha1542_in(base_io, inquiry_result, 4);
- WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
- while (0) {
- fail:
- printk("aha1542_detect: query card type\n");
- }
- aha1542_intr_reset(base_io);
-
- *transl = BIOS_TRANSLATION_6432; /* Default case */
-
-/* For an AHA1740 series board, we ignore the board since there is a
- hardware bug which can lead to wrong blocks being returned if the board
- is operating in the 1542 emulation mode. Since there is an extended mode
- driver, we simply ignore the board and let the 1740 driver pick it up.
-*/
-
- if (inquiry_result[0] == 0x43) {
- printk("aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
- return 1;
- };
-
- /* Always call this - boards that do not support extended bios translation
- will ignore the command, and we will set the proper default */
-
- *transl = aha1542_mbenable(base_io);
-
- return 0;
+ unchar inquiry_cmd[] = {CMD_INQUIRY};
+ unchar inquiry_result[4];
+ int i;
+ i = inb(STATUS(base_io));
+ if (i & DF) {
+ i = inb(DATA(base_io));
+ };
+ aha1542_out(base_io, inquiry_cmd, 1);
+ aha1542_in(base_io, inquiry_result, 4);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ while (0) {
+fail:
+ printk(KERN_ERR "aha1542_detect: query card type\n");
+ }
+ aha1542_intr_reset(base_io);
+
+ *transl = BIOS_TRANSLATION_6432; /* Default case */
+
+ /* For an AHA1740 series board, we ignore the board since there is a
+ hardware bug which can lead to wrong blocks being returned if the board
+ is operating in the 1542 emulation mode. Since there is an extended mode
+ driver, we simply ignore the board and let the 1740 driver pick it up.
+ */
+
+ if (inquiry_result[0] == 0x43) {
+ printk(KERN_INFO "aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
+ return 1;
+ };
+
+ /* Always call this - boards that do not support extended bios translation
+ will ignore the command, and we will set the proper default */
+
+ *transl = aha1542_mbenable(base_io);
+
+ return 0;
}
/* called from init/main.c */
-void __init aha1542_setup( char *str, int *ints)
+void __init aha1542_setup(char *str, int *ints)
{
- const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n";
- static int setup_idx = 0;
- int setup_portbase;
-
- if(setup_idx >= MAXBOARDS)
- {
- printk("aha1542: aha1542_setup called too many times! Bad LILO params ?\n");
- printk(" Entryline 1: %s\n",setup_str[0]);
- printk(" Entryline 2: %s\n",setup_str[1]);
- printk(" This line: %s\n",str);
- return;
- }
- if (ints[0] < 1 || ints[0] > 4)
- {
- printk("aha1542: %s\n", str );
- printk(ahausage);
- printk("aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n");
- }
-
- setup_called[setup_idx]=ints[0];
- setup_str[setup_idx]=str;
-
- setup_portbase = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */
- setup_buson [setup_idx] = ints[0] >= 2 ? ints[2] : 7;
- setup_busoff [setup_idx] = ints[0] >= 3 ? ints[3] : 5;
- if (ints[0] >= 4) {
- int atbt = -1;
- switch (ints[4]) {
- case 5:
- atbt = 0x00;
- break;
- case 6:
- atbt = 0x04;
- break;
- case 7:
- atbt = 0x01;
- break;
- case 8:
- atbt = 0x02;
- break;
- case 10:
- atbt = 0x03;
- break;
- default:
- printk("aha1542: %s\n", str );
- printk(ahausage);
- printk("aha1542: Valid values for DMASPEED are 5-8, 10 MB/s. Using jumper defaults.\n");
- break;
- }
- setup_dmaspeed[setup_idx] = atbt;
- }
-
- if (setup_portbase != 0)
- bases[setup_idx] = setup_portbase;
-
- ++setup_idx;
+ const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n";
+ static int setup_idx = 0;
+ int setup_portbase;
+
+ if (setup_idx >= MAXBOARDS) {
+ printk(KERN_ERR "aha1542: aha1542_setup called too many times! Bad LILO params ?\n");
+ printk(KERN_ERR " Entryline 1: %s\n", setup_str[0]);
+ printk(KERN_ERR " Entryline 2: %s\n", setup_str[1]);
+ printk(KERN_ERR " This line: %s\n", str);
+ return;
+ }
+ if (ints[0] < 1 || ints[0] > 4) {
+ printk(KERN_ERR "aha1542: %s\n", str);
+ printk(ahausage);
+ printk(KERN_ERR "aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n");
+ }
+ setup_called[setup_idx] = ints[0];
+ setup_str[setup_idx] = str;
+
+ setup_portbase = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */
+ setup_buson[setup_idx] = ints[0] >= 2 ? ints[2] : 7;
+ setup_busoff[setup_idx] = ints[0] >= 3 ? ints[3] : 5;
+ if (ints[0] >= 4)
+ {
+ int atbt = -1;
+ switch (ints[4]) {
+ case 5:
+ atbt = 0x00;
+ break;
+ case 6:
+ atbt = 0x04;
+ break;
+ case 7:
+ atbt = 0x01;
+ break;
+ case 8:
+ atbt = 0x02;
+ break;
+ case 10:
+ atbt = 0x03;
+ break;
+ default:
+ printk(KERN_ERR "aha1542: %s\n", str);
+ printk(ahausage);
+ printk(KERN_ERR "aha1542: Valid values for DMASPEED are 5-8, 10 MB/s. Using jumper defaults.\n");
+ break;
+ }
+ setup_dmaspeed[setup_idx] = atbt;
+ }
+ if (setup_portbase != 0)
+ bases[setup_idx] = setup_portbase;
+
+ ++setup_idx;
}
/* return non-zero on detection */
int aha1542_detect(Scsi_Host_Template * tpnt)
{
- unsigned char dma_chan;
- unsigned char irq_level;
- unsigned char scsi_id;
- unsigned long flags;
- unsigned int base_io;
- int trans;
- struct Scsi_Host * shpnt = NULL;
- int count = 0;
- int indx;
+ unsigned char dma_chan;
+ unsigned char irq_level;
+ unsigned char scsi_id;
+ unsigned long flags;
+ unsigned int base_io;
+ int trans;
+ struct Scsi_Host *shpnt = NULL;
+ int count = 0;
+ int indx;
- DEB(printk("aha1542_detect: \n"));
+ DEB(printk("aha1542_detect: \n"));
- tpnt->proc_name = "aha1542";
+ tpnt->proc_name = "aha1542";
#ifdef MODULE
- bases[0] = aha1542[0];
- setup_buson[0] = aha1542[1];
- setup_busoff[0] = aha1542[2];
- {
- int atbt = -1;
- switch (aha1542[3]) {
- case 5:
- atbt = 0x00;
- break;
- case 6:
- atbt = 0x04;
- break;
- case 7:
- atbt = 0x01;
- break;
- case 8:
- atbt = 0x02;
- break;
- case 10:
- atbt = 0x03;
- break;
- };
- setup_dmaspeed[0] = atbt;
- }
+ bases[0] = aha1542[0];
+ setup_buson[0]=aha1542[1];
+ setup_busoff[0] = aha1542[2];
+ {
+ int atbt = -1;
+ switch (aha1542[3]) {
+ case 5:
+ atbt = 0x00;
+ break;
+ case 6:
+ atbt = 0x04;
+ break;
+ case 7:
+ atbt = 0x01;
+ break;
+ case 8:
+ atbt = 0x02;
+ break;
+ case 10:
+ atbt = 0x03;
+ break;
+ };
+ setup_dmaspeed[0] = atbt;
+ }
#endif
-
- for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++)
- if(bases[indx] != 0 && !check_region(bases[indx], 4)) {
- shpnt = scsi_register(tpnt,
- sizeof(struct aha1542_hostdata));
-
- /* For now we do this - until kmalloc is more intelligent
- we are resigned to stupid hacks like this */
- if (SCSI_PA(shpnt) >= ISA_DMA_THRESHOLD) {
- printk("Invalid address for shpnt with 1542.\n");
- goto unregister;
- }
-
- if(!aha1542_test_port(bases[indx], shpnt)) goto unregister;
-
-
- base_io = bases[indx];
-
- /* Set the Bus on/off-times as not to ruin floppy performance */
- {
- unchar oncmd[] = {CMD_BUSON_TIME, 7};
- unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
-
- if(setup_called[indx])
- {
- oncmd[1] = setup_buson[indx];
- offcmd[1] = setup_busoff[indx];
- }
-
- aha1542_intr_reset(base_io);
- aha1542_out(base_io, oncmd, 2);
- WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
- aha1542_intr_reset(base_io);
- aha1542_out(base_io, offcmd, 2);
- WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
- if (setup_dmaspeed[indx] >= 0)
- {
- unchar dmacmd[] = {CMD_DMASPEED, 0};
- dmacmd[1] = setup_dmaspeed[indx];
- aha1542_intr_reset(base_io);
- aha1542_out(base_io, dmacmd, 2);
- WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
- }
- while (0) {
- fail:
- printk("aha1542_detect: setting bus on/off-time failed\n");
- }
- aha1542_intr_reset(base_io);
- }
- if(aha1542_query(base_io, &trans)) goto unregister;
-
- if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1) goto unregister;
-
- printk("Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level);
- if (dma_chan != 0xFF)
- printk(", DMA priority %d", dma_chan);
- printk("\n");
-
- DEB(aha1542_stat());
- setup_mailboxes(base_io, shpnt);
-
- DEB(aha1542_stat());
-
- DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
- save_flags(flags);
- cli();
- if (request_irq(irq_level,do_aha1542_intr_handle, 0, "aha1542", NULL)) {
- printk("Unable to allocate IRQ for adaptec controller.\n");
- restore_flags(flags);
- goto unregister;
- }
-
- if (dma_chan != 0xFF) {
- if (request_dma(dma_chan,"aha1542")) {
- printk("Unable to allocate DMA channel for Adaptec.\n");
- free_irq(irq_level, NULL);
- restore_flags(flags);
- goto unregister;
- }
-
- if (dma_chan == 0 || dma_chan >= 5) {
- set_dma_mode(dma_chan, DMA_MODE_CASCADE);
- enable_dma(dma_chan);
- }
- }
- aha_host[irq_level - 9] = shpnt;
- shpnt->this_id = scsi_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 4; /* Number of bytes of I/O space used */
- shpnt->dma_channel = dma_chan;
- shpnt->irq = irq_level;
- HOSTDATA(shpnt)->bios_translation = trans;
- if(trans == BIOS_TRANSLATION_25563)
- printk("aha1542.c: Using extended bios translation\n");
- HOSTDATA(shpnt)->aha1542_last_mbi_used = (2*AHA1542_MAILBOXES - 1);
- HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
- memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
- restore_flags(flags);
+ /*
+ * Hunt for ISA Plug'n'Pray Adaptecs (AHA1535)
+ */
+
+ if(isapnp)
+ {
+ struct pci_dev *pdev = NULL;
+ for(indx = 0; indx <sizeof(bases)/sizeof(bases[0]);indx++)
+ {
+ if(bases[indx])
+ continue;
+ pdev = isapnp_find_dev(NULL, ISAPNP_VENDOR('A', 'D', 'P'),
+ ISAPNP_FUNCTION(0x1542), pdev);
+ if(pdev==NULL)
+ break;
+ /*
+ * Activate the PnP card
+ */
+
+ if(pdev->prepare(pdev)<0)
+ continue;
+
+ if(!(pdev->resource[0].flags&IORESOURCE_IO))
+ continue;
+
+ pdev->resource[0].flags|=IORESOURCE_AUTO;
+
+ if(pdev->activate(pdev)<0)
+ continue;
+
+ bases[indx] = pdev->resource[0].start;
+
+ /* The card can be queried for its DMA, we have
+ the DMA set up that is enough */
+
+ printk(KERN_INFO "ISAPnP found an AHA1535 at I/O 0x%03X\n", bases[indx]);
+ }
+ }
+ for (indx = 0; indx < sizeof(bases) / sizeof(bases[0]); indx++)
+ if (bases[indx] != 0 && !check_region(bases[indx], 4)) {
+ shpnt = scsi_register(tpnt,
+ sizeof(struct aha1542_hostdata));
+
+ /* For now we do this - until kmalloc is more intelligent
+ we are resigned to stupid hacks like this */
+ if (SCSI_PA(shpnt) >= ISA_DMA_THRESHOLD) {
+ printk(KERN_ERR "Invalid address for shpnt with 1542.\n");
+ goto unregister;
+ }
+ if (!aha1542_test_port(bases[indx], shpnt))
+ goto unregister;
+
+
+ base_io = bases[indx];
+
+ /* Set the Bus on/off-times as not to ruin floppy performance */
+ {
+ unchar oncmd[] = {CMD_BUSON_TIME, 7};
+ unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
+
+ if (setup_called[indx]) {
+ oncmd[1] = setup_buson[indx];
+ offcmd[1] = setup_busoff[indx];
+ }
+ aha1542_intr_reset(base_io);
+ aha1542_out(base_io, oncmd, 2);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ aha1542_intr_reset(base_io);
+ aha1542_out(base_io, offcmd, 2);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ if (setup_dmaspeed[indx] >= 0) {
+ unchar dmacmd[] = {CMD_DMASPEED, 0};
+ dmacmd[1] = setup_dmaspeed[indx];
+ aha1542_intr_reset(base_io);
+ aha1542_out(base_io, dmacmd, 2);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ }
+ while (0) {
+fail:
+ printk(KERN_ERR "aha1542_detect: setting bus on/off-time failed\n");
+ }
+ aha1542_intr_reset(base_io);
+ }
+ if (aha1542_query(base_io, &trans))
+ goto unregister;
+
+ if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1)
+ goto unregister;
+
+ printk(KERN_INFO "Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level);
+ if (dma_chan != 0xFF)
+ printk(", DMA priority %d", dma_chan);
+ printk("\n");
+
+ DEB(aha1542_stat());
+ setup_mailboxes(base_io, shpnt);
+
+ DEB(aha1542_stat());
+
+ DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
+ save_flags(flags);
+ cli();
+ if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) {
+ printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
+ restore_flags(flags);
+ goto unregister;
+ }
+ if (dma_chan != 0xFF) {
+ if (request_dma(dma_chan, "aha1542")) {
+ printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
+ free_irq(irq_level, NULL);
+ restore_flags(flags);
+ goto unregister;
+ }
+ if (dma_chan == 0 || dma_chan >= 5) {
+ set_dma_mode(dma_chan, DMA_MODE_CASCADE);
+ enable_dma(dma_chan);
+ }
+ }
+ aha_host[irq_level - 9] = shpnt;
+ shpnt->this_id = scsi_id;
+ shpnt->unique_id = base_io;
+ shpnt->io_port = base_io;
+ shpnt->n_io_port = 4; /* Number of bytes of I/O space used */
+ shpnt->dma_channel = dma_chan;
+ shpnt->irq = irq_level;
+ HOSTDATA(shpnt)->bios_translation = trans;
+ if (trans == BIOS_TRANSLATION_25563)
+ printk(KERN_INFO "aha1542.c: Using extended bios translation\n");
+ HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1);
+ HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
+ memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
+ restore_flags(flags);
#if 0
- DEB(printk(" *** READ CAPACITY ***\n"));
-
- {
- unchar buf[8];
- static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- int i;
-
- for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
- for (i = 0; i < 2; ++i)
- if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
- printk("aha_detect: LU %d sector_size %d device_size %d\n",
- i, xscsi2int(buf+4), xscsi2int(buf));
- }
- }
-
- DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
-
- for (i = 0; i < 4; ++i)
- {
- unsigned char cmd[10];
- static buffer[512];
-
- cmd[0] = READ_10;
- cmd[1] = 0;
- xany2scsi(cmd+2, i);
- cmd[6] = 0;
- cmd[7] = 0;
- cmd[8] = 1;
- cmd[9] = 0;
- aha1542_command(0, cmd, buffer, 512);
- }
-#endif
- request_region(bases[indx], 4,"aha1542"); /* Register the IO ports that we use */
- count++;
- continue;
- unregister:
- scsi_unregister(shpnt);
- continue;
-
- };
-
- return count;
+ DEB(printk(" *** READ CAPACITY ***\n"));
+
+ {
+ unchar buf[8];
+ static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int i;
+
+ for (i = 0; i < sizeof(buf); ++i)
+ buf[i] = 0x87;
+ for (i = 0; i < 2; ++i)
+ if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
+ printk(KERN_DEBUG "aha_detect: LU %d sector_size %d device_size %d\n",
+ i, xscsi2int(buf + 4), xscsi2int(buf));
+ }
+ }
+
+ DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
+
+ for (i = 0; i < 4; ++i) {
+ unsigned char cmd[10];
+ static buffer[512];
+
+ cmd[0] = READ_10;
+ cmd[1] = 0;
+ xany2scsi(cmd + 2, i);
+ cmd[6] = 0;
+ cmd[7] = 0;
+ cmd[8] = 1;
+ cmd[9] = 0;
+ aha1542_command(0, cmd, buffer, 512);
+ }
+#endif
+ request_region(bases[indx], 4, "aha1542"); /* Register the IO ports that we use */
+ count++;
+ continue;
+unregister:
+ scsi_unregister(shpnt);
+ continue;
+
+ };
+
+ return count;
}
-static int aha1542_restart(struct Scsi_Host * shost)
+static int aha1542_restart(struct Scsi_Host *shost)
{
- int i;
- int count = 0;
+ int i;
+ int count = 0;
#if 0
- unchar ahacmd = CMD_START_SCSI;
+ unchar ahacmd = CMD_START_SCSI;
#endif
- for(i=0; i< AHA1542_MAILBOXES; i++)
- if(HOSTDATA(shost)->SCint[i] &&
- !(HOSTDATA(shost)->SCint[i]->device->soft_reset))
- {
+ for (i = 0; i < AHA1542_MAILBOXES; i++)
+ if (HOSTDATA(shost)->SCint[i] &&
+ !(HOSTDATA(shost)->SCint[i]->device->soft_reset)) {
#if 0
- HOSTDATA(shost)->mb[i].status = 1; /* Indicate ready to restart... */
+ HOSTDATA(shost)->mb[i].status = 1; /* Indicate ready to restart... */
#endif
- count++;
- }
-
- printk("Potential to restart %d stalled commands...\n", count);
+ count++;
+ }
+ printk(KERN_DEBUG "Potential to restart %d stalled commands...\n", count);
#if 0
- /* start scsi command */
- if (count) aha1542_out(shost->io_port, &ahacmd, 1);
+ /* start scsi command */
+ if (count)
+ aha1542_out(shost->io_port, &ahacmd, 1);
#endif
- return 0;
+ return 0;
}
int aha1542_abort(Scsi_Cmnd * SCpnt)
{
-
- /*
- * The abort command does not leave the device in a clean state where
- * it is available to be used again. Until this gets worked out, we
- * will leave it commented out.
- */
-
- printk("aha1542.c: Unable to abort command for target %d\n",
- SCpnt->target);
- return FAILED;
+
+ /*
+ * The abort command does not leave the device in a clean state where
+ * it is available to be used again. Until this gets worked out, we
+ * will leave it commented out.
+ */
+
+ printk(KERN_ERR "aha1542.c: Unable to abort command for target %d\n",
+ SCpnt->target);
+ return FAILED;
}
/*
*/
int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
{
- unsigned long flags;
- struct mailbox * mb;
- unchar target = SCpnt->target;
- unchar lun = SCpnt->lun;
- int mbo;
- struct ccb *ccb;
- unchar ahacmd = CMD_START_SCSI;
-
- ccb = HOSTDATA(SCpnt->host)->ccb;
- mb = HOSTDATA(SCpnt->host)->mb;
-
- save_flags(flags);
- cli();
- mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
- if (mbo >= AHA1542_MAILBOXES) mbo = 0;
-
- do{
- if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
- break;
- mbo++;
- if (mbo >= AHA1542_MAILBOXES) mbo = 0;
- } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
-
- if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
- panic("Unable to find empty mailbox for aha1542.\n");
-
- HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively
- prevent someone else from
- screwing with this cdb. */
-
- HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
- restore_flags(flags);
-
- any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
-
- memset(&ccb[mbo], 0, sizeof(struct ccb));
-
- ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
-
- ccb[mbo].idlun = (target&7)<<5 | (lun & 7); /*SCSI Target Id*/
-
- ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
- ccb[mbo].commlinkid = 0;
-
- /*
- * Now tell the 1542 to flush all pending commands for this
- * target
- */
- aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
-
- printk("aha1542.c: Trying device reset for target %d\n", SCpnt->target);
-
- return SUCCESS;
-
+ unsigned long flags;
+ struct mailbox *mb;
+ unchar target = SCpnt->target;
+ unchar lun = SCpnt->lun;
+ int mbo;
+ struct ccb *ccb;
+ unchar ahacmd = CMD_START_SCSI;
+
+ ccb = HOSTDATA(SCpnt->host)->ccb;
+ mb = HOSTDATA(SCpnt->host)->mb;
+
+ save_flags(flags);
+ cli();
+ mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
+ if (mbo >= AHA1542_MAILBOXES)
+ mbo = 0;
+
+ do {
+ if (mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+ break;
+ mbo++;
+ if (mbo >= AHA1542_MAILBOXES)
+ mbo = 0;
+ } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
+
+ if (mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
+ panic("Unable to find empty mailbox for aha1542.\n");
+
+ HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively
+ prevent someone else from
+ screwing with this cdb. */
+
+ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
+ restore_flags(flags);
+
+ any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason */
+
+ memset(&ccb[mbo], 0, sizeof(struct ccb));
+
+ ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
+
+ ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */
+
+ ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+ ccb[mbo].commlinkid = 0;
+
+ /*
+ * Now tell the 1542 to flush all pending commands for this
+ * target
+ */
+ aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+ printk(KERN_WARNING "aha1542.c: Trying device reset for target %d\n", SCpnt->target);
+
+ return SUCCESS;
+
#ifdef ERIC_neverdef
- /*
- * With the 1542 we apparently never get an interrupt to
- * acknowledge a device reset being sent. Then again, Leonard
- * says we are doing this wrong in the first place...
- *
- * Take a wait and see attitude. If we get spurious interrupts,
- * then the device reset is doing something sane and useful, and
- * we will wait for the interrupt to post completion.
- */
- printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
-
- /*
- * Free the command block for all commands running on this
- * target...
- */
- for(i=0; i< AHA1542_MAILBOXES; i++)
- {
- if(HOSTDATA(SCpnt->host)->SCint[i] &&
- HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
- {
- Scsi_Cmnd * SCtmp;
- SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
- if (SCtmp->host_scribble)
- {
- scsi_free(SCtmp->host_scribble, 512);
- }
-
- HOSTDATA(SCpnt->host)->SCint[i] = NULL;
- HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ /*
+ * With the 1542 we apparently never get an interrupt to
+ * acknowledge a device reset being sent. Then again, Leonard
+ * says we are doing this wrong in the first place...
+ *
+ * Take a wait and see attitude. If we get spurious interrupts,
+ * then the device reset is doing something sane and useful, and
+ * we will wait for the interrupt to post completion.
+ */
+ printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+ /*
+ * Free the command block for all commands running on this
+ * target...
+ */
+ for (i = 0; i < AHA1542_MAILBOXES; i++) {
+ if (HOSTDATA(SCpnt->host)->SCint[i] &&
+ HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+ Scsi_Cmnd *SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ if (SCtmp->host_scribble) {
+ scsi_free(SCtmp->host_scribble, 512);
+ }
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
}
- }
- return SUCCESS;
+ return SUCCESS;
- return FAILED;
-#endif /* ERIC_neverdef */
+ return FAILED;
+#endif /* ERIC_neverdef */
}
int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
{
- int i;
-
- /*
- * This does a scsi reset for all devices on the bus.
- * In principle, we could also reset the 1542 - should
- * we do this? Try this first, and we can add that later
- * if it turns out to be useful.
- */
- outb(SCRST, CONTROL(SCpnt->host->io_port));
-
- /*
- * Wait for the thing to settle down a bit. Unfortunately
- * this is going to basically lock up the machine while we
- * wait for this to complete. To be 100% correct, we need to
- * check for timeout, and if we are doing something like this
- * we are pretty desperate anyways.
- */
- spin_unlock_irq(&io_request_lock);
- scsi_sleep(4*HZ);
- spin_lock_irq(&io_request_lock);
-
- WAIT(STATUS(SCpnt->host->io_port),
- STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
-
- /*
- * Now try to pick up the pieces. For all pending commands,
- * free any internal data structures, and basically clear things
- * out. We do not try and restart any commands or anything -
- * the strategy handler takes care of that crap.
- */
- printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
-
- for(i=0; i< AHA1542_MAILBOXES; i++)
- {
- if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
- {
- Scsi_Cmnd * SCtmp;
- SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ int i;
-
- if( SCtmp->device->soft_reset )
- {
- /*
- * If this device implements the soft reset option,
- * then it is still holding onto the command, and
- * may yet complete it. In this case, we don't
- * flush the data.
- */
- continue;
- }
+ /*
+ * This does a scsi reset for all devices on the bus.
+ * In principle, we could also reset the 1542 - should
+ * we do this? Try this first, and we can add that later
+ * if it turns out to be useful.
+ */
+ outb(SCRST, CONTROL(SCpnt->host->io_port));
- if (SCtmp->host_scribble)
- {
- scsi_free(SCtmp->host_scribble, 512);
- }
-
- HOSTDATA(SCpnt->host)->SCint[i] = NULL;
- HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ /*
+ * Wait for the thing to settle down a bit. Unfortunately
+ * this is going to basically lock up the machine while we
+ * wait for this to complete. To be 100% correct, we need to
+ * check for timeout, and if we are doing something like this
+ * we are pretty desperate anyways.
+ */
+ spin_unlock_irq(&io_request_lock);
+ scsi_sleep(4 * HZ);
+ spin_lock_irq(&io_request_lock);
+
+ WAIT(STATUS(SCpnt->host->io_port),
+ STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+ /*
+ * Now try to pick up the pieces. For all pending commands,
+ * free any internal data structures, and basically clear things
+ * out. We do not try and restart any commands or anything -
+ * the strategy handler takes care of that crap.
+ */
+ printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+ for (i = 0; i < AHA1542_MAILBOXES; i++) {
+ if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+ Scsi_Cmnd *SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+
+ if (SCtmp->device->soft_reset) {
+ /*
+ * If this device implements the soft reset option,
+ * then it is still holding onto the command, and
+ * may yet complete it. In this case, we don't
+ * flush the data.
+ */
+ continue;
+ }
+ if (SCtmp->host_scribble) {
+ scsi_free(SCtmp->host_scribble, 512);
+ }
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
}
- }
- return SUCCESS;
+ return SUCCESS;
fail:
- return FAILED;
+ return FAILED;
}
int aha1542_host_reset(Scsi_Cmnd * SCpnt)
{
- int i;
-
- /*
- * This does a scsi reset for all devices on the bus.
- * In principle, we could also reset the 1542 - should
- * we do this? Try this first, and we can add that later
- * if it turns out to be useful.
- */
- outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
-
- /*
- * Wait for the thing to settle down a bit. Unfortunately
- * this is going to basically lock up the machine while we
- * wait for this to complete. To be 100% correct, we need to
- * check for timeout, and if we are doing something like this
- * we are pretty desperate anyways.
- */
- spin_unlock_irq(&io_request_lock);
- scsi_sleep(4*HZ);
- spin_lock_irq(&io_request_lock);
-
- WAIT(STATUS(SCpnt->host->io_port),
- STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
-
- /*
- * We need to do this too before the 1542 can interact with
- * us again.
- */
- setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
-
- /*
- * Now try to pick up the pieces. For all pending commands,
- * free any internal data structures, and basically clear things
- * out. We do not try and restart any commands or anything -
- * the strategy handler takes care of that crap.
- */
- printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
-
- for(i=0; i< AHA1542_MAILBOXES; i++)
- {
- if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
- {
- Scsi_Cmnd * SCtmp;
- SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ int i;
- if( SCtmp->device->soft_reset )
- {
- /*
- * If this device implements the soft reset option,
- * then it is still holding onto the command, and
- * may yet complete it. In this case, we don't
- * flush the data.
- */
- continue;
- }
+ /*
+ * This does a scsi reset for all devices on the bus.
+ * In principle, we could also reset the 1542 - should
+ * we do this? Try this first, and we can add that later
+ * if it turns out to be useful.
+ */
+ outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
- if (SCtmp->host_scribble)
- {
- scsi_free(SCtmp->host_scribble, 512);
- }
-
- HOSTDATA(SCpnt->host)->SCint[i] = NULL;
- HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ /*
+ * Wait for the thing to settle down a bit. Unfortunately
+ * this is going to basically lock up the machine while we
+ * wait for this to complete. To be 100% correct, we need to
+ * check for timeout, and if we are doing something like this
+ * we are pretty desperate anyways.
+ */
+ spin_unlock_irq(&io_request_lock);
+ scsi_sleep(4 * HZ);
+ spin_lock_irq(&io_request_lock);
+
+ WAIT(STATUS(SCpnt->host->io_port),
+ STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+ /*
+ * We need to do this too before the 1542 can interact with
+ * us again.
+ */
+ setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
+ /*
+ * Now try to pick up the pieces. For all pending commands,
+ * free any internal data structures, and basically clear things
+ * out. We do not try and restart any commands or anything -
+ * the strategy handler takes care of that crap.
+ */
+ printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+ for (i = 0; i < AHA1542_MAILBOXES; i++) {
+ if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+ Scsi_Cmnd *SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+ if (SCtmp->device->soft_reset) {
+ /*
+ * If this device implements the soft reset option,
+ * then it is still holding onto the command, and
+ * may yet complete it. In this case, we don't
+ * flush the data.
+ */
+ continue;
+ }
+ if (SCtmp->host_scribble) {
+ scsi_free(SCtmp->host_scribble, 512);
+ }
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
}
- }
- return SUCCESS;
+ return SUCCESS;
fail:
- return FAILED;
+ return FAILED;
}
/*
int aha1542_old_abort(Scsi_Cmnd * SCpnt)
{
#if 0
- unchar ahacmd = CMD_START_SCSI;
- unsigned long flags;
- struct mailbox * mb;
- int mbi, mbo, i;
-
- printk("In aha1542_abort: %x %x\n",
- inb(STATUS(SCpnt->host->io_port)),
- inb(INTRFLAGS(SCpnt->host->io_port)));
-
- save_flags(flags);
- cli();
- mb = HOSTDATA(SCpnt->host)->mb;
- mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
- if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
-
- do{
- if(mb[mbi].status != 0) break;
- mbi++;
- if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
- } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
- restore_flags(flags);
-
- if(mb[mbi].status) {
- printk("Lost interrupt discovered on irq %d - attempting to recover\n",
- SCpnt->host->irq);
- aha1542_intr_handle(SCpnt->host->irq, NULL);
- return 0;
- }
-
- /* OK, no lost interrupt. Try looking to see how many pending commands
- we think we have. */
-
- for(i=0; i< AHA1542_MAILBOXES; i++)
- if(HOSTDATA(SCpnt->host)->SCint[i])
- {
- if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
- printk("Timed out command pending for %s\n",
- kdevname(SCpnt->request.rq_dev));
- if (HOSTDATA(SCpnt->host)->mb[i].status) {
- printk("OGMB still full - restarting\n");
- aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
- };
- } else
- printk("Other pending command %s\n",
- kdevname(SCpnt->request.rq_dev));
- }
+ unchar ahacmd = CMD_START_SCSI;
+ unsigned long flags;
+ struct mailbox *mb;
+ int mbi, mbo, i;
+
+ printk(KERN_DEBUG "In aha1542_abort: %x %x\n",
+ inb(STATUS(SCpnt->host->io_port)),
+ inb(INTRFLAGS(SCpnt->host->io_port)));
+
+ save_flags(flags);
+ cli();
+ mb = HOSTDATA(SCpnt->host)->mb;
+ mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
+ if (mbi >= 2 * AHA1542_MAILBOXES)
+ mbi = AHA1542_MAILBOXES;
+
+ do {
+ if (mb[mbi].status != 0)
+ break;
+ mbi++;
+ if (mbi >= 2 * AHA1542_MAILBOXES)
+ mbi = AHA1542_MAILBOXES;
+ } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
+ restore_flags(flags);
+ if (mb[mbi].status) {
+ printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n",
+ SCpnt->host->irq);
+ aha1542_intr_handle(SCpnt->host->irq, NULL);
+ return 0;
+ }
+ /* OK, no lost interrupt. Try looking to see how many pending commands
+ we think we have. */
+
+ for (i = 0; i < AHA1542_MAILBOXES; i++)
+ if (HOSTDATA(SCpnt->host)->SCint[i]) {
+ if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+ printk(KERN_ERR "Timed out command pending for %s\n",
+ kdevname(SCpnt->request.rq_dev));
+ if (HOSTDATA(SCpnt->host)->mb[i].status) {
+ printk(KERN_ERR "OGMB still full - restarting\n");
+ aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+ };
+ } else
+ printk(KERN_ERR "Other pending command %s\n",
+ kdevname(SCpnt->request.rq_dev));
+ }
#endif
- DEB(printk("aha1542_abort\n"));
+ DEB(printk("aha1542_abort\n"));
#if 0
- save_flags(flags);
- cli();
- for(mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
- if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]){
- mb[mbo].status = 2; /* Abort command */
- aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */
- restore_flags(flags);
- break;
- };
+ save_flags(flags);
+ cli();
+ for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
+ if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) {
+ mb[mbo].status = 2; /* Abort command */
+ aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */
+ restore_flags(flags);
+ break;
+ };
#endif
- return SCSI_ABORT_SNOOZE;
+ return SCSI_ABORT_SNOOZE;
}
/* We do not implement a reset function here, but the upper level code
int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
{
- unchar ahacmd = CMD_START_SCSI;
- int i;
-
- /*
- * See if a bus reset was suggested.
- */
- if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET )
- {
- /*
- * This does a scsi reset for all devices on the bus.
- * In principle, we could also reset the 1542 - should
- * we do this? Try this first, and we can add that later
- * if it turns out to be useful.
- */
- outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+ unchar ahacmd = CMD_START_SCSI;
+ int i;
/*
- * Wait for the thing to settle down a bit. Unfortunately
- * this is going to basically lock up the machine while we
- * wait for this to complete. To be 100% correct, we need to
- * check for timeout, and if we are doing something like this
- * we are pretty desperate anyways.
+ * See if a bus reset was suggested.
*/
- WAIT(STATUS(SCpnt->host->io_port),
- STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+ if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) {
+ /*
+ * This does a scsi reset for all devices on the bus.
+ * In principle, we could also reset the 1542 - should
+ * we do this? Try this first, and we can add that later
+ * if it turns out to be useful.
+ */
+ outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
- /*
- * We need to do this too before the 1542 can interact with
- * us again.
- */
- setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+ /*
+ * Wait for the thing to settle down a bit. Unfortunately
+ * this is going to basically lock up the machine while we
+ * wait for this to complete. To be 100% correct, we need to
+ * check for timeout, and if we are doing something like this
+ * we are pretty desperate anyways.
+ */
+ WAIT(STATUS(SCpnt->host->io_port),
+ STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
- /*
- * Now try to pick up the pieces. Restart all commands
- * that are currently active on the bus, and reset all of
- * the datastructures. We have some time to kill while
- * things settle down, so print a nice message.
- */
- printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
-
- for(i=0; i< AHA1542_MAILBOXES; i++)
- if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
- {
- Scsi_Cmnd * SCtmp;
- SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
- SCtmp->result = DID_RESET << 16;
- if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512);
- printk("Sending DID_RESET for target %d\n", SCpnt->target);
- SCtmp->scsi_done(SCpnt);
-
- HOSTDATA(SCpnt->host)->SCint[i] = NULL;
- HOSTDATA(SCpnt->host)->mb[i].status = 0;
- }
- /*
- * Now tell the mid-level code what we did here. Since
- * we have restarted all of the outstanding commands,
- * then report SUCCESS.
- */
- return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+ /*
+ * We need to do this too before the 1542 can interact with
+ * us again.
+ */
+ setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
+ /*
+ * Now try to pick up the pieces. Restart all commands
+ * that are currently active on the bus, and reset all of
+ * the datastructures. We have some time to kill while
+ * things settle down, so print a nice message.
+ */
+ printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+ for (i = 0; i < AHA1542_MAILBOXES; i++)
+ if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+ Scsi_Cmnd *SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ SCtmp->result = DID_RESET << 16;
+ if (SCtmp->host_scribble)
+ scsi_free(SCtmp->host_scribble, 512);
+ printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+ SCtmp->scsi_done(SCpnt);
+
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
+ /*
+ * Now tell the mid-level code what we did here. Since
+ * we have restarted all of the outstanding commands,
+ * then report SUCCESS.
+ */
+ return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
fail:
- printk("aha1542.c: Unable to perform hard reset.\n");
- printk("Power cycle machine to reset\n");
- return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET);
-
-
- }
- else
- {
- /* This does a selective reset of just the one device */
- /* First locate the ccb for this command */
- for(i=0; i< AHA1542_MAILBOXES; i++)
- if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt)
- {
- HOSTDATA(SCpnt->host)->ccb[i].op = 0x81; /* BUS DEVICE RESET */
- /* Now tell the 1542 to flush all pending commands for this target */
- aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
-
- /* Here is the tricky part. What to do next. Do we get an interrupt
- for the commands that we aborted with the specified target, or
- do we generate this on our own? Try it without first and see
- what happens */
- printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
-
- /* If the first does not work, then try the second. I think the
- first option is more likely to be correct. Free the command
- block for all commands running on this target... */
- for(i=0; i< AHA1542_MAILBOXES; i++)
- if(HOSTDATA(SCpnt->host)->SCint[i] &&
- HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
- {
- Scsi_Cmnd * SCtmp;
- SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
- SCtmp->result = DID_RESET << 16;
- if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512);
- printk("Sending DID_RESET for target %d\n", SCpnt->target);
- SCtmp->scsi_done(SCpnt);
-
- HOSTDATA(SCpnt->host)->SCint[i] = NULL;
- HOSTDATA(SCpnt->host)->mb[i].status = 0;
- }
- return SCSI_RESET_SUCCESS;
- }
- }
- /* No active command at this time, so this means that each time we got
- some kind of response the last time through. Tell the mid-level code
- to request sense information in order to decide what to do next. */
- return SCSI_RESET_PUNT;
+ printk(KERN_CRIT "aha1542.c: Unable to perform hard reset.\n");
+ printk(KERN_CRIT "Power cycle machine to reset\n");
+ return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET);
+
+
+ } else {
+ /* This does a selective reset of just the one device */
+ /* First locate the ccb for this command */
+ for (i = 0; i < AHA1542_MAILBOXES; i++)
+ if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+ HOSTDATA(SCpnt->host)->ccb[i].op = 0x81; /* BUS DEVICE RESET */
+ /* Now tell the 1542 to flush all pending commands for this target */
+ aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+ /* Here is the tricky part. What to do next. Do we get an interrupt
+ for the commands that we aborted with the specified target, or
+ do we generate this on our own? Try it without first and see
+ what happens */
+ printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+ /* If the first does not work, then try the second. I think the
+ first option is more likely to be correct. Free the command
+ block for all commands running on this target... */
+ for (i = 0; i < AHA1542_MAILBOXES; i++)
+ if (HOSTDATA(SCpnt->host)->SCint[i] &&
+ HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+ Scsi_Cmnd *SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ SCtmp->result = DID_RESET << 16;
+ if (SCtmp->host_scribble)
+ scsi_free(SCtmp->host_scribble, 512);
+ printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+ SCtmp->scsi_done(SCpnt);
+
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
+ return SCSI_RESET_SUCCESS;
+ }
+ }
+ /* No active command at this time, so this means that each time we got
+ some kind of response the last time through. Tell the mid-level code
+ to request sense information in order to decide what to do next. */
+ return SCSI_RESET_PUNT;
}
#include "sd.h"
-int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip)
+int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
{
- int translation_algorithm;
- int size = disk->capacity;
-
- translation_algorithm = HOSTDATA(disk->device->host)->bios_translation;
-
- if((size>>11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) {
- /* Please verify that this is the same as what DOS returns */
- ip[0] = 255;
- ip[1] = 63;
- ip[2] = size /255/63;
- } else {
- ip[0] = 64;
- ip[1] = 32;
- ip[2] = size >> 11;
- }
-
- return 0;
+ int translation_algorithm;
+ int size = disk->capacity;
+
+ translation_algorithm = HOSTDATA(disk->device->host)->bios_translation;
+
+ if ((size >> 11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) {
+ /* Please verify that this is the same as what DOS returns */
+ ip[0] = 255;
+ ip[1] = 63;
+ ip[2] = size / 255 / 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = size >> 11;
+ }
+
+ return 0;
}
#include "scsi_module.c"
#endif
-
MODULE_DESCRIPTION ("AMI MegaRAID driver");
#endif
+#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
*
*================================================================
*/
+static int __init megaraid_setup(char *);
+
static int megaIssueCmd (mega_host_config * megaCfg,
u_char * mboxData,
mega_scb * scb,
/* Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE
processor id cannot be scanned */
-static char *megaraid;
#ifdef MODULE
+static char *megaraid = NULL;
MODULE_PARM(megaraid, "s");
#endif
static int skip_id;
{
int count = 0;
- pHostTmpl->proc_name = "megaraid";
+#ifdef MODULE
+ if (megaraid)
+ megaraid_setup(megaraid);
+#endif
- skip_id = -1;
- if (megaraid && !strncmp(megaraid,"skip",strlen("skip"))) {
- if (megaraid[4] != '\0') {
- skip_id = megaraid[4] - '0';
- if (megaraid[5] != '\0') {
- skip_id = (skip_id * 10) + (megaraid[5] - '0');
- }
- }
- skip_id = (skip_id > 15) ? -1 : skip_id;
- }
+ pHostTmpl->proc_name = "megaraid";
printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
return 0;
}
+static int __init megaraid_setup(char *str)
+{
+ skip_id = -1;
+ if (str && !strncmp(str, "skip", strlen("skip"))) {
+ if (str[4] != '\0') {
+ skip_id = str[4] - '0';
+ if (str[5] != '\0') {
+ skip_id = (skip_id * 10) + (str[5] - '0');
+ }
+ }
+ skip_id = (skip_id > 15) ? -1 : skip_id;
+ }
+ return 1;
+}
+
+__setup("megaraid=", megaraid_setup);
+
#ifdef MODULE
Scsi_Host_Template driver_template = MEGARAID;
{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0
* extra reset */
{"RELISYS", "Scorpio", "*", BLIST_NOLUN}, /* responds to all LUN */
+ {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all LUN */
/*
* Other types of devices that have special flags.
typedef u16 USHORT;
typedef u16 WORD;
typedef u32 DWORD;
-typedef volatile BYTE * LPDAQD;
+typedef unsigned long LPDAQD;
/* Generic FIFO */
typedef struct {
int memid, irqid;
int irq, irq_ref;
unsigned char info;
- volatile BYTE *base;
+ unsigned long base;
/* Motorola 56k DSP SMA */
- volatile BYTE *SMA;
- volatile BYTE *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ;
- volatile WORD *pwDSPQData, *pwMIDQData, *pwMODQData;
+ unsigned long SMA;
+ unsigned long DAPQ, DARQ, MODQ, MIDQ, DSPQ;
+ unsigned long pwDSPQData, pwMIDQData, pwMODQData;
/* State variables */
enum { msndClassic, msndPinnacle } type;
LPDAQD lpDAQ;
dev.last_playbank = -1;
- writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
- writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
+ isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
+ isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
- writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
- writew(0, lpDAQ + DAQDS_wSize);
- writew(1, lpDAQ + DAQDS_wFormat);
- writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
- writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
- writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
- writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
- writew(n, lpDAQ + DAQDS_wFlags);
+ isa_writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
+ isa_writew(0, lpDAQ + DAQDS_wSize);
+ isa_writew(1, lpDAQ + DAQDS_wFormat);
+ isa_writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
+ isa_writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
+ isa_writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
+ isa_writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+ isa_writew(n, lpDAQ + DAQDS_wFlags);
}
}
unsigned long flags;
dev.last_recbank = 2;
- writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
- writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
+ isa_writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
+ isa_writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
/* Critical section: bank 1 access */
spin_lock_irqsave(&dev.lock, flags);
outb(HPBLKSEL_1, dev.io + HP_BLKS);
- memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+ isa_memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
outb(HPBLKSEL_0, dev.io + HP_BLKS);
spin_unlock_irqrestore(&dev.lock, flags);
for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
- writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
- writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
- writew(1, lpDAQ + DAQDS_wFormat);
- writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
- writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
- writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
- writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
- writew(n, lpDAQ + DAQDS_wFlags);
+ isa_writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
+ isa_writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
+ isa_writew(1, lpDAQ + DAQDS_wFormat);
+ isa_writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
+ isa_writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
+ isa_writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
+ isa_writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
+ isa_writew(n, lpDAQ + DAQDS_wFlags);
}
}
for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
if (file->f_mode & FMODE_WRITE)
- writew(data, lpDAQ + DAQDS_wSampleSize);
+ isa_writew(data, lpDAQ + DAQDS_wSampleSize);
if (file->f_mode & FMODE_READ)
- writew(data, lpDARQ + DAQDS_wSampleSize);
+ isa_writew(data, lpDARQ + DAQDS_wSampleSize);
}
if (file->f_mode & FMODE_WRITE)
dev.play_sample_size = data;
for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
if (file->f_mode & FMODE_WRITE)
- writew(data, lpDAQ + DAQDS_wSampleRate);
+ isa_writew(data, lpDAQ + DAQDS_wSampleRate);
if (file->f_mode & FMODE_READ)
- writew(data, lpDARQ + DAQDS_wSampleRate);
+ isa_writew(data, lpDARQ + DAQDS_wSampleRate);
}
if (file->f_mode & FMODE_WRITE)
dev.play_sample_rate = data;
for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
if (file->f_mode & FMODE_WRITE)
- writew(data, lpDAQ + DAQDS_wChannels);
+ isa_writew(data, lpDAQ + DAQDS_wChannels);
if (file->f_mode & FMODE_READ)
- writew(data, lpDARQ + DAQDS_wChannels);
+ isa_writew(data, lpDARQ + DAQDS_wChannels);
}
if (file->f_mode & FMODE_WRITE)
dev.play_channels = data;
}
}
-#define update_volm(a,b) \
- writew((dev.left_levels[a] >> 1) * \
- readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \
- dev.SMA + SMA_##b##Left); \
- writew((dev.right_levels[a] >> 1) * \
- readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
+#define update_volm(a,b) \
+ isa_writew((dev.left_levels[a] >> 1) * \
+ isa_readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev.SMA + SMA_##b##Left); \
+ isa_writew((dev.right_levels[a] >> 1) * \
+ isa_readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
dev.SMA + SMA_##b##Right);
-#define update_potm(d,s,ar) \
- writeb((dev.left_levels[d] >> 8) * \
- readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \
- dev.SMA + SMA_##s##Left); \
- writeb((dev.right_levels[d] >> 8) * \
- readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
- dev.SMA + SMA_##s##Right); \
- if (msnd_send_word(&dev, 0, 0, ar) == 0) \
+#define update_potm(d,s,ar) \
+ isa_writeb((dev.left_levels[d] >> 8) * \
+ isa_readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \
+ dev.SMA + SMA_##s##Left); \
+ isa_writeb((dev.right_levels[d] >> 8) * \
+ isa_readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \
+ dev.SMA + SMA_##s##Right); \
+ if (msnd_send_word(&dev, 0, 0, ar) == 0) \
chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
#define update_pot(d,s,ar) \
- writeb(dev.left_levels[d] >> 8, \
+ isa_writeb(dev.left_levels[d] >> 8, \
dev.SMA + SMA_##s##Left); \
- writeb(dev.right_levels[d] >> 8, \
+ isa_writeb(dev.right_levels[d] >> 8, \
dev.SMA + SMA_##s##Right); \
if (msnd_send_word(&dev, 0, 0, ar) == 0) \
chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
/* master volume unscaled controls */
case SOUND_MIXER_LINE: /* line pot control */
/* scaled by IMIX in digital mix */
- writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
- writeb(bRight, dev.SMA + SMA_bInPotPosRight);
+ isa_writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
+ isa_writeb(bRight, dev.SMA + SMA_bInPotPosRight);
if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
break;
#ifndef MSND_CLASSIC
case SOUND_MIXER_MIC: /* mic pot control */
/* scaled by IMIX in digital mix */
- writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
- writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
+ isa_writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
+ isa_writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
break;
#endif
case SOUND_MIXER_VOLUME: /* master volume */
- writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft);
- writew(wRight, dev.SMA + SMA_wCurrMastVolRight);
+ isa_writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft);
+ isa_writew(wRight, dev.SMA + SMA_wCurrMastVolRight);
/* fall through */
case SOUND_MIXER_LINE1: /* aux pot control */
LPDAQD DAQD;
/* Increment the tail and check for queue wrap */
- wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
- if (wTmp > readw(dev.DARQ + JQS_wSize))
+ wTmp = isa_readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+ if (wTmp > isa_readw(dev.DARQ + JQS_wSize))
wTmp = 0;
- while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--)
+ while (wTmp == isa_readw(dev.DARQ + JQS_wHead) && timeout--)
udelay(1);
- writew(wTmp, dev.DARQ + JQS_wTail);
+ isa_writew(wTmp, dev.DARQ + JQS_wTail);
/* Get our digital audio queue struct */
DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF;
/* Get length of data */
- size = readw(DAQD + DAQDS_wSize);
+ size = isa_readw(DAQD + DAQDS_wSize);
/* Read data from the head (unprotected bank 1 access okay
since this is only called inside an interrupt) */
register int protect = start, nbanks = 0;
LPDAQD DAQD;
- DAPQ_tail = readw(dev.DAPQ + JQS_wTail);
- while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) {
+ DAPQ_tail = isa_readw(dev.DAPQ + JQS_wTail);
+ while (DAPQ_tail != isa_readw(dev.DAPQ + JQS_wHead) || start) {
register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
register int n;
unsigned long flags;
DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF;
/* Write size of this bank */
- writew(n, DAQD + DAQDS_wSize);
+ isa_writew(n, DAQD + DAQDS_wSize);
++nbanks;
/* Then advance the tail */
DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
- writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
+ isa_writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
/* Tell the DSP to play the bank */
msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
inb(dev.io + HP_RXL);
/* Evaluate queued DSP messages */
- while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) {
+ while (isa_readw(dev.DSPQ + JQS_wTail) != isa_readw(dev.DSPQ + JQS_wHead)) {
register WORD wTmp;
- eval_dsp_msg(readw(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead)));
+ eval_dsp_msg(isa_readw(dev.pwDSPQData + 2*isa_readw(dev.DSPQ + JQS_wHead)));
- if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize))
- writew(0, dev.DSPQ + JQS_wHead);
+ if ((wTmp = isa_readw(dev.DSPQ + JQS_wHead) + 1) > isa_readw(dev.DSPQ + JQS_wSize))
+ isa_writew(0, dev.DSPQ + JQS_wHead);
else
- writew(wTmp, dev.DSPQ + JQS_wHead);
+ isa_writew(wTmp, dev.DSPQ + JQS_wHead);
}
}
}
printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
#endif /* MSND_CLASSIC */
- "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+ "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
dev.name,
#ifndef MSND_CLASSIC
rev, xv,
return 0;
}
-static void msnd_init_queue(volatile BYTE *base, int start, int size)
+static void msnd_init_queue(unsigned long base, int start, int size)
{
- writew(PCTODSP_BASED(start), base + JQS_wStart);
- writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
- writew(0, base + JQS_wHead);
- writew(0, base + JQS_wTail);
+ isa_writew(PCTODSP_BASED(start), base + JQS_wStart);
+ isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+ isa_writew(0, base + JQS_wHead);
+ isa_writew(0, base + JQS_wTail);
}
static int init_sma(void)
#endif
outb(HPBLKSEL_0, dev.io + HP_BLKS);
if (initted) {
- mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft);
- mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight);
+ mastVolLeft = isa_readw(dev.SMA + SMA_wCurrMastVolLeft);
+ mastVolRight = isa_readw(dev.SMA + SMA_wCurrMastVolRight);
} else
mastVolLeft = mastVolRight = 0;
- memset_io(dev.base, 0, 0x8000);
+ isa_memset_io(dev.base, 0, 0x8000);
/* Critical section: bank 1 access */
spin_lock_irqsave(&dev.lock, flags);
outb(HPBLKSEL_1, dev.io + HP_BLKS);
- memset_io(dev.base, 0, 0x8000);
+ isa_memset_io(dev.base, 0, 0x8000);
outb(HPBLKSEL_0, dev.io + HP_BLKS);
spin_unlock_irqrestore(&dev.lock, flags);
- dev.pwDSPQData = (volatile WORD *)(dev.base + DSPQ_DATA_BUFF);
- dev.pwMODQData = (volatile WORD *)(dev.base + MODQ_DATA_BUFF);
- dev.pwMIDQData = (volatile WORD *)(dev.base + MIDQ_DATA_BUFF);
+ dev.pwDSPQData = (dev.base + DSPQ_DATA_BUFF);
+ dev.pwMODQData = (dev.base + MODQ_DATA_BUFF);
+ dev.pwMIDQData = (dev.base + MIDQ_DATA_BUFF);
/* Motorola 56k shared memory base */
dev.SMA = dev.base + SMA_STRUCT_START;
/* Setup some DSP values */
#ifndef MSND_CLASSIC
- writew(1, dev.SMA + SMA_wCurrPlayFormat);
- writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
- writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
- writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
+ isa_writew(1, dev.SMA + SMA_wCurrPlayFormat);
+ isa_writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
+ isa_writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
+ isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
#endif
- writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
- writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
- writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
+ isa_writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
+ isa_writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
+ isa_writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
#ifndef MSND_CLASSIC
- writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
- writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
+ isa_writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
+ isa_writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
#endif
- writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
+ isa_writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
initted = 1;
static int __init calibrate_adc(WORD srate)
{
- writew(srate, dev.SMA + SMA_wCalFreqAtoD);
+ isa_writew(srate, dev.SMA + SMA_wCalFreqAtoD);
if (dev.calibrate_signal == 0)
- writew(readw(dev.SMA + SMA_wCurrHostStatusFlags)
+ isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags)
| 0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
else
- writew(readw(dev.SMA + SMA_wCurrHostStatusFlags)
+ isa_writew(isa_readw(dev.SMA + SMA_wCurrHostStatusFlags)
& ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
return -EBUSY;
}
#endif
- memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+ isa_memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
return -ENODEV;
}
timeout = 200;
- while (readw(dev.base)) {
+ while (isa_readw(dev.base)) {
mdelay(1);
if (!timeout--) {
printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n");
dev.io = io;
dev.numio = DSP_NUMIO;
dev.irq = irq;
- dev.base = phys_to_virt(mem);
+ dev.base = mem;
dev.fifosize = fifosize * 1024;
dev.calibrate_signal = calibrate_signal ? 1 : 0;
dev.recsrc = 0;
-/*****************************************************************************
+/*
*
- * Trident 4D-Wave OSS driver for Linux 2.2.x
+ * Trident 4D-Wave/SiS 7018 OSS driver for Linux 2.2.x
*
* Driver: Alan Cox <alan@redhat.com>
*
* Built from:
- * Low level code: <audio@tridentmicro.com> from ALSA
- * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- * Extended by: Zach Brown <zab@redhat.com>
+ * Low level code: <audio@tridentmicro.com> from ALSA
+ * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Extended by: Zach Brown <zab@redhat.com>
*
- * Hacked up by:
- * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ * Hacked up by:
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ * Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core 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 of the License, or
- * (at your option) any later version.
+ * 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.
+ * 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.
+ * 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.
*
+ * History
+ * v0.03 Dec 24 1999 Ollie Lho
+ * mem leak in prog_dmabuf and dealloc_dmabuf removed
+ * v0.02 Dec 15 1999 Ollie Lho
+ * SiS 7018 support added, playback O.K.
+ * v0.01 Alan Cox et. al.
+ * Initial Release in kernel 2.3.30, does not work
*/
-
-/*****************************************************************************/
-
#include <linux/config.h>
#include <linux/module.h>
/* --------------------------------------------------------------------- */
-#define M_DEBUG 1
-
-#ifdef M_DEBUG
-static int debug=0;
-#define M_printk(args...) {if (debug) printk(args);}
-#else
-#define M_printk(x)
-#endif
+#undef DEBUG
/* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.01"
+#define DRIVER_VERSION "0.03"
#define TRIDENT_FMT_STEREO 0x01
#define TRIDENT_FMT_16BIT 0x02
#define TRIDENT_DAC_SHIFT 0
#define TRIDENT_ADC_SHIFT 4
-#define TRIDENT_ENABLE_PE 1
-#define TRIDENT_ENABLE_RE 2
+#define TRIDENT_ENABLE_PE 1
+#define TRIDENT_ENABLE_RE 2
+#define DAC_RUNNING 1
+#define ADC_RUNNING 2
-#define TRIDENT_CARD_MAGIC 0x5072696E
-#define TRIDENT_STATE_MAGIC 0x63657373
+#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
+#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
#define NR_DSPS 8
-#define SND_DEV_DSP16 5
+#define SND_DEV_DSP16 5
static const unsigned sample_size[] = { 1, 2, 2, 4 };
static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
-enum card_types_t {
- TYPE_4DWAVE_DX,
- TYPE_4DWAVE_NX
+struct pci_audio_info {
+ u16 vendor;
+ u16 device;
+ char *name;
};
-static const char *card_names[]={
- [TYPE_4DWAVE_DX] = "Trident 4DWave DX",
- [TYPE_4DWAVE_NX] = "Trident 4DWave NX",
+static struct pci_audio_info pci_audio_devices[] = {
+ {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, "Trident 4DWave DX"},
+ {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, "Trident 4DWave NX"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"}
};
+static struct {
+ unsigned int id;
+ char *name;
+} snd_ac97_codec_ids[] = {
+ {0x414B4D00, "Asahi Kasei AK4540" },
+ {0x41445340, "Analog Devices AD1881" },
+ {0x43525900, "Cirrus Logic CS4297" },
+ {0x43525913, "Cirrus Logic CS4297A" },
+ {0x43525931, "Cirrus Logic CS4299" },
+ {0x4e534331, "National Semiconductor LM4549"},
+ {0x83847600, "SigmaTel STAC????" },
+ {0x83847604, "SigmaTel STAC9701/3/4/5"},
+ {0x83847605, "SigmaTel STAC9704" },
+ {0x83847608, "SigmaTel STAC9708" },
+ {0x83847609, "SigmaTel STAC9721/23" },
+ {0x00000000, NULL}
+};
typedef struct tChannelControl
{
unsigned fragshift;
int chan[2]; /* Hardware channel */
/* XXX zab - swptr only in here so that it can be referenced by
- clear_advance, as far as I can tell :( */
+ clear_advance, as far as I can tell :( */
unsigned hwptr, swptr;
unsigned total_bytes;
int count;
u8 bDMAStart;
};
-
+
+struct trident_pcm_bank {
+ /* registers to control bank operations */
+ u32 start;
+ u32 stop;
+ u32 aint;
+ u32 aint_en;
+ /* each bank has 32 channels */
+ u32 bitmap; /* channel allocation bitmap */
+ //struct trident_channel channels[32];
+};
+
+struct trident_mixer {
+ int modcnt;
+ int supported_mixers;
+ int stereo_mixers;
+ int record_sources;
+ /* the caller must guarantee arg sanity before calling these */
+ /* int (*read_mixer)(struct trident_card *card, int index);*/
+ void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,
+ unsigned int right);
+ int (*recmask_io)(struct trident_card *card,int rw,int mask);
+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
struct trident_card {
unsigned int magic;
struct trident_card *next;
/* The trident has a certain amount of cross channel interaction
- so we use a single per card lock */
-
+ so we use a single per card lock */
spinlock_t lock;
- int dev_mixer;
-
- int card_type;
+ struct pci_audio_info *pci_info;
+ struct pci_dev * pci_dev;
+ u16 pci_id;
/* as most of this is static,
- perhaps it should be a pointer to a global struct */
+ perhaps it should be a pointer to a global struct */
+ int dev_mixer;
struct mixer_goo {
int modcnt;
int supported_mixers;
int stereo_mixers;
int record_sources;
/* the caller must guarantee arg sanity before calling these */
-/* int (*read_mixer)(struct trident_card *card, int index);*/
+ /* int (*read_mixer)(struct trident_card *card, int index);*/
void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,unsigned int right);
int (*recmask_io)(struct trident_card *card,int rw,int mask);
unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
unsigned long iobase;
u32 irq;
- u32 ChanMap[2];
- int ChanPCMcnt;
- int ChanPCM;
+ u32 bitmap[2];
CHANNELCONTROL ChRegs;
int ChanDwordCount;
};
-static struct timer_list debug_timer;
-
-#define IWriteAinten( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define IReadAinten( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define ReadAint( x ) \
- IReadAint( x )
-
-#define WriteAint( x ) \
- IWriteAint( x )
-
-#define IWriteAint( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));}
-
-#define IReadAint( x ) \
- {int i; \
- for( i= 0; i < ChanDwordCount; i++) \
- (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));}
-
+static struct trident_card *devs = NULL;
/*
* Trident support library routines
void ResetAinten( struct trident_state *trident, int ChannelNum)
Description: This routine will disable interrupts and ack any
- existing interrupts for specified channel.
+ existing interrupts for specified channel.
- Parameters: trident - pointer to target device class for 4DWave.
- ChannelNum - channel number
+ Parameters: trident - pointer to target device class for 4DWave.
+ ChannelNum - channel number
- returns: TRUE if everything went ok, else FALSE.
+ returns: TRUE if everything went ok, else FALSE.
---------------------------------------------------------------------------*/
void EnableEndInterrupts( struct trident_card *trident)
Description: This routine will enable end of loop interrupts.
- End of loop interrupts will occur when a running
- channel reaches ESO.
+ End of loop interrupts will occur when a running
+ channel reaches ESO.
- Parameters: trident - pointer to target device class for 4DWave.
+ Parameters: trident - pointer to target device class for 4DWave.
- returns: TRUE if everything went ok, else FALSE.
+ returns: TRUE if everything went ok, else FALSE.
---------------------------------------------------------------------------*/
-static int EnableEndInterrupts(struct trident_card * trident)
+static int trident_enable_end_interrupts(struct trident_card * trident)
{
- unsigned int GlobalControl;
+ u32 GlobalControl;
+
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+
+ switch (trident->pci_id)
+ {
+ case PCI_DEVICE_ID_SI_7018:
+ GlobalControl |= (ENDLP_IE | BANK_B_EN);
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ GlobalControl |= ENDLP_IE;
+ break;
+ default:
+ return FALSE;
+ }
- GlobalControl = inb(TRID_REG(trident, T4D_LFO_GC_CIR + 1));
- GlobalControl |= 0x10;
- outb(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR + 1));
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
- M_printk("(trident) globctl=%02X\n", GlobalControl);
- M_printk("(trident) enabled end interrupts\n");
+#ifdef DEBUG
+ printk("trident: Enable End Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
return (TRUE);
}
+static int trident_enable_middle_interrupts(struct trident_card * trident)
+{
+ u32 GlobalControl;
+
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+
+ switch (trident->pci_id)
+ {
+ case PCI_DEVICE_ID_SI_7018:
+ GlobalControl |= (MIDLP_IE | BANK_B_EN);
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ default:
+ GlobalControl |= MIDLP_IE;
+ break;
+ }
+
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+ printk("trident: Enable Middle Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
+ return (TRUE);
+}
/*---------------------------------------------------------------------------
-e void DisableEndInterrupts( struct trident_card *trident)
+ void DisableEndInterrupts( struct trident_card *trident)
Description: This routine will disable end of loop interrupts.
- End of loop interrupts will occur when a running
- channel reaches ESO.
+ End of loop interrupts will occur when a running
+ channel reaches ESO.
- Parameters:
- trident - pointer to target device class for 4DWave.
+ Parameters:
+ trident - pointer to target device class for 4DWave.
- returns: TRUE if everything went ok, else FALSE.
+ returns: TRUE if everything went ok, else FALSE.
---------------------------------------------------------------------------*/
-static int DisableEndInterrupts(struct trident_card * trident)
+static int trident_disable_end_interrupts(struct trident_card * trident)
{
- unsigned int GlobalControl;
+ u32 GlobalControl;
- GlobalControl = inb(TRID_REG(trident, T4D_LFO_GC_CIR + 1));
- GlobalControl &= ~0x10;
- outb(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR + 1));
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+ GlobalControl &= ~ENDLP_IE;
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
- M_printk("(trident) disabled end interrupts\n");
- M_printk("(trident) globctl=%02X\n", GlobalControl);
+#ifdef DEBUG
+ printk("trident: Disabled End Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
return (TRUE);
}
+static int trident_disable_middle_interrupts(struct trident_card * trident)
+{
+ u32 GlobalControl;
+
+ GlobalControl = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+ GlobalControl &= ~MIDLP_IE;
+ outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+ printk("trident: Disabled Middle Interrupts, globctl = 0x%08X\n", GlobalControl);
+#endif
+ return (TRUE);
+}
/*---------------------------------------------------------------------------
void trident_enable_voice_irq( unsigned int HwChannel )
Description: Enable an interrupt channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_enable_voice_irq(struct trident_card * trident, unsigned int HwChannel)
+void trident_enable_voice_irq(struct trident_card * trident, unsigned int channel)
{
- unsigned int x, Data, ChanDwordCount;
+ unsigned int bank, mask, ChanDwordCount;
+ u32 reg;
+
+ bank = channel >> 5;
+ mask = 1 << (channel & 0x1f);
- x = HwChannel >> 5;
- Data = 1 << (HwChannel & 0x1f);
ChanDwordCount = trident->ChanDwordCount;
+
IReadAinten(&trident->ChRegs);
- trident->ChRegs.lpChAinten[x] |= Data;
+ trident->ChRegs.lpChAinten[bank] |= mask;
IWriteAinten(&trident->ChRegs);
- M_printk("(trident) enabled voice IRQ %d\n", HwChannel);
+
+#ifdef DEBUG
+ reg = inl(TRID_REG(trident, T4D_AINTEN_B));
+ printk("trident: enabled IRQ on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
void trident_disable_voice_irq( unsigned int HwChannel )
Description: Disable an interrupt channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_disable_voice_irq(struct trident_card * trident, unsigned int HwChannel)
+void trident_disable_voice_irq(struct trident_card * trident, unsigned int channel)
{
- unsigned int x, Data, ChanDwordCount;
+ unsigned int bank, mask, ChanDwordCount;
+ u32 reg;
+
+ bank = channel >> 5;
+ mask = 1 << (channel & 0x1f);
- x = HwChannel >> 5;
- Data = 1 << (HwChannel & 0x1f);
ChanDwordCount = trident->ChanDwordCount;
IReadAinten(&trident->ChRegs);
- trident->ChRegs.lpChAinten[x] &= ~Data;
+ trident->ChRegs.lpChAinten[bank] &= ~mask;
IWriteAinten(&trident->ChRegs);
- M_printk("(trident) disabled voice IRQ %d\n", HwChannel);
+
+#ifdef DEBUG
+ reg = inl(TRID_REG(trident, T4D_AINTEN_B));
+ printk("trident: disabled IRQ on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
---------------------------------------------------------------------------*/
-static int AllocateChannelPCM(struct trident_card *trident)
+static int trident_alloc_pcm_channel(struct trident_card *trident)
{
int idx;
- if (trident->ChanPCMcnt >= trident->ChanPCM)
- {
- M_printk(KERN_DEBUG "(trident) no channels available.\n");
+ if (trident->bitmap[BANK_B] == ~0UL) {
+ /* not more free channels avaliable */
+ printk(KERN_ERR "trident: no more channels available on Bank B.\n");
return -1;
}
for (idx = 31; idx >= 0; idx--) {
- if (!(trident->ChanMap[1] & (1 << idx))) {
- trident->ChanMap[1] |= 1 << idx;
- trident->ChanPCMcnt++;
+ if (!(trident->bitmap[BANK_B] & (1 << idx))) {
+ trident->bitmap[BANK_B] |= 1 << idx;
return idx + 32;
}
}
+
+#ifdef ABUSE_BANK_A
+ /* channels in Bank A should be reserved for synthesizer
+ not for normal use (channels in Bank A can't record) */
+ if (trident->bitmap[BANK_A] == ~0UL) {
+ /* not more free channels avaliable */
+ printk(KERN_ERR "trident: no channels available on Bank A.\n");
+ return -1;
+ }
for (idx = 31; idx >= 0; idx--) {
- if (!(trident->ChanMap[0] & (1 << idx))) {
- trident->ChanMap[0] |= 1 << idx;
- trident->ChanPCMcnt++;
+ if (!(trident->bitmap[BANK_A] & (1 << idx))) {
+ trident->bitmap[BANK_A] |= 1 << idx;
return idx;
}
}
+#endif
+
return -1;
}
Description: Free hardware channel.
Parameters : trident - pointer to target device class for 4DWave.
- channel - hardware channel number 0-63
+ channel - hardware channel number 0-63
Return Value: none
---------------------------------------------------------------------------*/
-static void FreeChannelPCM(struct trident_card *trident, int channel)
+static void trident_free_pcm_channel(struct trident_card *trident, int channel)
{
+ int bank;
+
+#ifdef ABUSE_BANK_A
if (channel < 0 || channel > 63)
return;
- if (trident->ChanMap[channel>>5] & (1 << (channel & 0x1f))) {
- trident->ChanMap[channel>>5] &= ~(1 << (channel & 0x1f));
- trident->ChanPCMcnt--;
+#else
+ if (channel < 31 || channel > 63)
+ return;
+#endif
+
+ bank = channel >> 5;
+ channel = channel & 0x1f;
+
+ if (trident->bitmap[bank] & (1 << (channel))) {
+ trident->bitmap[bank] &= ~(1 << (channel));
}
}
void trident_start_voice( ULONG HwChannel )
Description: Start a channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_start_voice(struct trident_card * trident, unsigned int HwChannel)
+void trident_start_voice(struct trident_card * trident, unsigned int channel)
{
- unsigned int x = HwChannel >> 5;
- unsigned int Data = 1 << (HwChannel & 0x1f);
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
- outl(Data, TRID_REG(trident, trident->ChRegs.lpAChStart[x]));
- M_printk("(trident) start voice %d\n", HwChannel);
+ outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStart[bank]));
+#ifdef DEBUG
+ printk("trident: start voice on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
void trident_stop_voice( ULONG HwChannel )
Description: Stop a channel, any channel 0 thru n.
- This routine automatically handles the fact that there are
- more than 32 channels available.
+ This routine automatically handles the fact that there are
+ more than 32 channels available.
Parameters : HwChannel - Channel number 0 thru n.
- trident - pointer to target device class for 4DWave.
+ trident - pointer to target device class for 4DWave.
Return Value: None.
---------------------------------------------------------------------------*/
-void trident_stop_voice(struct trident_card * trident, unsigned int HwChannel)
+void trident_stop_voice(struct trident_card * trident, unsigned int channel)
{
- unsigned int x = HwChannel >> 5;
- unsigned int Data = 1 << (HwChannel & 0x1f);
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
- outl(Data, TRID_REG(trident, trident->ChRegs.lpAChStop[x]));
- M_printk("(trident) stop voice %d\n", HwChannel);
+ outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStop[bank]));
+#ifdef DEBUG
+ printk("trident: stop voice on channel %d\n", channel);
+#endif
}
/*---------------------------------------------------------------------------
int DidChannelInterrupt( )
- Description: Check if interrupt channel occurred.
+ Description: Check if interrupt channel occurred.
- Parameters : trident - pointer to target device class for 4DWave.
+ Parameters : trident - pointer to target device class for 4DWave.
Return Value: TRUE if interrupt occurred, else FALSE.
---------------------------------------------------------------------------*/
-static int DidChannelInterrupt(struct trident_card * trident, int channel)
+static int trident_check_channel_interrupt(struct trident_card * trident, int channel)
{
- unsigned int ChanDwordCount = trident->ChanDwordCount;
- unsigned int x = channel >> 5;
- unsigned int dwMask = 1 << (channel & 0x1f);
+ unsigned int ChanDwordCount = NUM_BANKS;
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
ReadAint(&trident->ChRegs);
- return (trident->ChRegs.lpChAint[x] & dwMask) ? TRUE : FALSE;
+
+#ifdef DEBUG
+ if (trident->ChRegs.lpChAint[bank] & mask)
+ printk("trident: channel %d has interrupt\n", channel);
+#endif
+ return (trident->ChRegs.lpChAint[bank] & mask) ? TRUE : FALSE;
}
/*---------------------------------------------------------------------------
void AckChannelInterrupt( )
- Description: Acknowledge the interrupt bit for channel intrs.
+ Description: Acknowledge the interrupt bit for channel intrs.
- Parameters : trident - pointer to target device class for 4DWave.
+ Parameters : trident - pointer to target device class for 4DWave.
Return Value: None
---------------------------------------------------------------------------*/
-static void AckChannelInterrupt(struct trident_card * trident, int channel)
+static void trident_ack_channel_interrupt(struct trident_card * trident, int channel)
{
- unsigned int ChanDwordCount = trident->ChanDwordCount;
- unsigned int x = channel >> 5;
- unsigned int dwMask = 1 << (channel & 0x1f);
+ unsigned int ChanDwordCount = NUM_BANKS;
+ unsigned int bank = channel >> 5;
+ unsigned int mask = 1 << (channel & 0x1f);
ReadAint(&trident->ChRegs);
- trident->ChRegs.lpChAint[x] &= dwMask;
+ trident->ChRegs.lpChAint[bank] &= mask;
IWriteAint(&trident->ChRegs);
}
/*---------------------------------------------------------------------------
- int LoadDeltaHw( unsigned int HwChannel, unsigned int Delta )
+ int trident_load_hw_delta( unsigned int HwChannel, unsigned int Delta )
Description: This routine writes Delta to the hardware.
- Parameters: Delta - data to write (2 Bytes only)
- HwChannel - Hardware channel to write to.
- trident - pointer to target device class for 4DWave.
+ Parameters: Delta - data to write (2 Bytes only)
+ HwChannel - Hardware channel to write to.
+ trident - pointer to target device class for 4DWave.
- Returns: TRUE if all goes well, else FALSE.
+ Returns: TRUE if all goes well, else FALSE.
---------------------------------------------------------------------------*/
-static int LoadDeltaHw(struct trident_card * trident, unsigned int HwChannel, unsigned int Delta)
+static int trident_load_hw_delta (struct trident_card * trident, unsigned int channel,
+ unsigned short delta)
{
+ /* select a channel for output */
+ outb(channel, TRID_REG(trident, T4D_LFO_GC_CIR));
- outb(HwChannel, TRID_REG(trident, T4D_LFO_GC_CIR));
-
- if (trident->card_type != TYPE_4DWAVE_NX) {
- outw((unsigned short) Delta, TRID_REG(trident, CH_DX_ESO_DELTA));
- }
- else // ID_4DWAVE_NX
+ switch (trident->pci_id)
{
- outb((unsigned char) Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
- outb((unsigned char) (Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3));
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ outw((u16) delta, TRID_REG(trident, CH_DX_ESO_DELTA));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ outb(delta & 0xff, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
+ outb((delta >> 8)& 0xff, TRID_REG(trident, CH_NX_DELTA_ESO + 3));
+ break;
+ default:
+ return FALSE;
}
-
return TRUE;
}
Description: This routine writes all required channel registers to hardware.
- Parameters: *Data - a pointer to the data to write (5 ULONGS always).
- HwChannel - Hardware channel to write to.
- trident - pointer to target device class for 4DWave.
+ Parameters: *Data - a pointer to the data to write (5 ULONGS always).
+ HwChannel - Hardware channel to write to.
+ trident - pointer to target device class for 4DWave.
- Returns: TRUE if all goes well, else FALSE.
+ Returns: TRUE if all goes well, else FALSE.
---------------------------------------------------------------------------*/
static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data, unsigned int HwChannel)
for (i = 0; i < ULONGSToDo; i++, Address += 4)
outl(ChanData[i], TRID_REG(trident, Address));
-
- M_printk("(trident) load virtual channel %d\n", HwChannel);
+#ifdef DEBUG
+ printk("(trident) load virtual channel %d\n", HwChannel);
+#endif
return TRUE;
}
trident_write_voice_regs
Description: This routine will write the 5 hardware channel registers
- to hardware.
+ to hardware.
- Paramters: trident - pointer to target device class for 4DWave.
- Channel - Real or Virtual channel number.
- Each register field.
+ Paramters: trident - pointer to target device class for 4DWave.
+ Channel - Real or Virtual channel number.
+ Each register field.
- Returns: TRUE if all goes well, else FALSE.
+ Returns: TRUE if all goes well, else FALSE.
---------------------------------------------------------------------------*/
int trident_write_voice_regs(struct trident_card * trident,
FmcRvolCvol = FMC_RVOL_CVOL & 0x0000ffff;
- if (trident->card_type != TYPE_4DWAVE_NX)
+ switch (trident->pci_id)
{
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
ChanData[0] = (CSO << 16) | (ALPHA_FMS & 0x0000ffff);
- ChanData[2] = (ESO << 16) | (DELTA & 0x0ffff);
+ ChanData[2] = (ESO << 16) | (DELTA & 0x0000ffff);
ChanData[3] = FmcRvolCvol;
- }
- else // ID_4DWAVE_NX
- {
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
ChanData[0] = (DELTA << 24) | (CSO & 0x00ffffff);
ChanData[2] = ((DELTA << 16) & 0xff000000) | (ESO & 0x00ffffff);
ChanData[3] = (ALPHA_FMS << 16) | FmcRvolCvol;
+ break;
}
LoadVirtualChannel(trident, ChanData, Channel);
Description: This routine will set the sample rate for playback.
- Paramters: trident - pointer to target device class for 4DWave.
- rate - desired sample rate
- set - actually write hardware if set is true.
+ Paramters: trident - pointer to target device class for 4DWave.
+ rate - desired sample rate
+ set - actually write hardware if set is true.
- Returns: The rate allowed by device.
+ Returns: The rate allowed by device.
---------------------------------------------------------------------------*/
static unsigned int trident_set_dac_rate(struct trident_state * trident,
- unsigned int rate, int set)
+ unsigned int rate, int set)
{
- unsigned int delta;
-
+ u16 delta;
if (rate > 48000)
rate = 48000;
rate = 4000;
delta = compute_rate(rate);
+ trident->ratedac = rate;
- if(set)
- {
- //Select channel window
- outb(trident->dma_dac.chan[1], TRID_REG(trident->card, T4D_LFO_GC_CIR));
-
- if (trident->card->card_type != TYPE_4DWAVE_NX)
- outw(delta,TRID_REG(trident->card,CH_DX_ESO_DELTA+2));
- else // ID_4DWAVE_NX
- {
- outb( delta & 0xff,TRID_REG(trident->card,CH_NX_DELTA_CSO));
- outb((delta>>8) & 0xff,TRID_REG(trident->card,CH_NX_DELTA_ESO));
- }
- }
-
- M_printk("(trident) called trident_set_dac_rate : rate = %d, set = %d delta = %4x\n",
- rate, set,delta);
+ if (set)
+ trident_load_hw_delta(trident->card, trident->dma_dac.chan[1],
+ delta);
+#ifdef DEBUG
+ printk("trident: called trident_set_dac_rate : rate = %d, "
+ "set = %d, delta = 0x%04x\n", rate, set, delta);
+#endif
- trident->ratedac = rate;
return rate;
}
Description: This routine will set the sample rate for capture.
- Paramters: trident - pointer to target device class for 4DWave.
- rate - desired sample rate
- set - actually write hardware if set is true.
+ Paramters: trident - pointer to target device class for 4DWave.
+ rate - desired sample rate
+ set - actually write hardware if set is true.
- Returns: The rate allowed by device.
+ Returns: The rate allowed by device.
---------------------------------------------------------------------------*/
static unsigned int trident_set_adc_rate(struct trident_state * trident,
- unsigned int rate,
- int set)
+ unsigned int rate, int set)
{
- //snd_printk("trid: called trident_set_adc_rate\n");
+ u16 delta;
+
if (rate > 48000)
rate = 48000;
if (rate < 4000)
rate = 4000;
- trident->rateadc = rate;
- /*
- * FIXME: hit the hardware
- */
+ delta = compute_rate(rate);
+ trident->ratedac = rate;
+#if 0 /* It seems that 4D-Wave can not use wave tables channels for recording */
+ if (set)
+ trident_load_hw_delta(trident->card, trident->dma_dac.chan[0],
+ delta);
+#endif
+#ifdef DEBUG
+ printk("trident: called trident_set_adc_rate : rate = %d, "
+ "set = %d, delta = 0x%04x\n", rate, set, delta);
+#endif
return rate;
}
return r;
}
-
-/* --------------------------------------------------------------------- */
-
-static struct trident_card *devs = NULL;
-
-/* --------------------------------------------------------------------- */
-
-
-/*
- * Trident AC97 codec programming interface.
- */
-
+/* Write AC97 mixer registers */
static void trident_ac97_set(struct trident_card *trident, u8 cmd, u16 val)
{
- unsigned int address, data;
- unsigned short count = 0xffff;
+ unsigned int address, mask, busy;
+ unsigned short count = 0xffff;
+ u32 data;
- data = ((unsigned long)val) << 16;
+ data = ((u32) val) << 16;
- if (trident->card_type != TYPE_4DWAVE_NX)
+ switch (trident->pci_id)
{
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ address = SI_AC97_WRITE;
+ mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
+ busy = SI_AC97_BUSY_WRITE;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
address = DX_ACR0_AC97_W;
- /* read AC-97 write register status */
- do
- {
- if ((inw(TRID_REG(trident,address))&0x8000) == 0)
- break;
- }
- while(count--);
-
- data |= (0x8000 | (cmd & 0x000000ff));
- }
- else // ID_4DWAVE_NX
- {
+ mask = busy = DX_AC97_BUSY_WRITE;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
address = NX_ACR1_AC97_W;
- /* read AC-97 write register status */
- do
- {
- if ((inw(TRID_REG(trident, address )) & 0x0800) == 0)
- break;
- }
- while (count--);
- data |= (0x0800 | (cmd & 0x000000ff));
+ mask = busy = NX_AC97_BUSY_WRITE;
+ break;
}
- if (count == 0)
- {
+
+ do {
+ if ((inw(TRID_REG(trident, address)) & busy) == 0)
+ break;
+ } while (count--);
+
+ data |= (mask | (cmd & AC97_REG_ADDR));
+
+ if (count == 0) {
printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
return;
}
-
outl(data, TRID_REG(trident, address));
}
+/* Read AC97 codec registers */
static u16 trident_ac97_get(struct trident_card *trident, u8 cmd)
{
- unsigned int data = 0;
+ unsigned int address, mask, busy;
unsigned short count = 0xffff;
+ u32 data;
- if (trident->card_type != TYPE_4DWAVE_NX)
- {
- data = (0x00008000L | (cmd & 0x000000ff));
- outl(data, TRID_REG(trident, DX_ACR1_AC97_R));
- do
- {
- data = inl(TRID_REG(trident, DX_ACR1_AC97_R));
- if ( ( data & 0x0008000 ) == 0 )
- break;
- }
- while(count--);
- }
- else // ID_4DWAVE_NX
- {
- data = (0x00000800L | (cmd & 0x000000ff));
- outl(data, TRID_REG(trident, NX_ACR2_AC97_R_PRIMARY));
- do
- {
- data = inl(TRID_REG(trident, NX_ACR2_AC97_R_PRIMARY));
- if ( ( data & 0x00000C00 ) == 0 )
- break;
- }
- while(count--);
- }
- if ( count == 0 )
+ switch (trident->pci_id)
{
- printk("trident: AC97 CODEC read timed out.\n");
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ address = SI_AC97_READ;
+ mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
+ busy = SI_AC97_BUSY_READ;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ address = DX_ACR1_AC97_R;
+ mask = busy = DX_AC97_BUSY_READ;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ address = NX_ACR2_AC97_R_PRIMARY;
+ mask = NX_AC97_BUSY_READ;
+ busy = 0x0c00;
+ break;
+ }
+
+ data = (mask | (cmd & AC97_REG_ADDR));
+ outl(data, TRID_REG(trident, address));
+
+ do {
+ data = inl(TRID_REG(trident, address));
+ if ((data & busy) == 0)
+ break;
+ } while (count--);
+
+ if (count == 0) {
+ printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
data = 0;
}
- return ((unsigned short)(data >> 16));
+ return ((u16) (data >> 16));
}
/* OSS interface to the ac97s.. */
int mixer;
unsigned int value;
} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
- /* all values 0 -> 100 in bytes */
+ /* all values 0 -> 100 in bytes */
{SOUND_MIXER_VOLUME, 0x3232},
{SOUND_MIXER_BASS, 0x3232},
{SOUND_MIXER_TREBLE, 0x3232},
unsigned char offset;
int scale;
} ac97_hw[SOUND_MIXER_NRDEVICES]= {
- [SOUND_MIXER_VOLUME] = {0x02,63},
- [SOUND_MIXER_BASS] = {0x08,15},
- [SOUND_MIXER_TREBLE] = {0x08,15},
- [SOUND_MIXER_SPEAKER] = {0x0a,15},
- [SOUND_MIXER_MIC] = {0x0e,31},
- [SOUND_MIXER_LINE] = {0x10,31},
- [SOUND_MIXER_CD] = {0x12,31},
- [SOUND_MIXER_VIDEO] = {0x14,31},
- [SOUND_MIXER_LINE1] = {0x16,31},
- [SOUND_MIXER_PCM] = {0x18,31},
- [SOUND_MIXER_IGAIN] = {0x1c,31}
+ [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63},
+ [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
+ [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31},
+ [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31},
+ [SOUND_MIXER_CD] = {AC97_CD_VOL, 31},
+ [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31},
+ [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31},
+ [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31},
+ [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31}
};
#if 0 /* *shrug* removed simply because we never used it.
- feel free to implement again if needed */
+ feel free to implement again if needed */
/* reads the given OSS mixer from the ac97
- the caller must have insured that the ac97 knows
- about that given mixer, and should be holding a
- spinlock for the card */
+ the caller must have insured that the ac97 knows
+ about that given mixer, and should be holding a
+ spinlock for the card */
static int ac97_read_mixer(struct trident_card *card, int mixer)
{
u16 val;
- int ret=0;
+ int ret = 0;
struct ac97_mixer_hw *mh = &ac97_hw[mixer];
val = trident_ac97_get(card , mh->offset);
- if(AC97_STEREO_MASK & (1<<mixer)) {
+ if (AC97_STEREO_MASK & (1<<mixer)) {
/* nice stereo mixers .. */
int left,right;
} else if (mixer == SOUND_MIXER_MIC) {
ret = 100 - (((val & 0x1f) * 100) / mh->scale);
/* the low bit is optional in the tone sliders and masking
- it lets is avoid the 0xf 'bypass'.. */
+ it lets us avoid the 0xf 'bypass'.. */
} else if (mixer == SOUND_MIXER_BASS) {
ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
} else if (mixer == SOUND_MIXER_TREBLE) {
ret = 100 - (((val & 0xe) * 100) / mh->scale);
}
- printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
+#ifdef DEBUG
+ printk("trident: read OSS mixer %2d (ac97 register 0x%02x), "
+ "0x%04x -> 0x%04x\n", mixer, mh->offset, val, ret);
+#endif
return ret;
}
#endif
/* write the OSS encoded volume to the given OSS encoded mixer,
- again caller's job to make sure all is well in arg land,
- call with spinlock held */
-static void ac97_write_mixer(struct trident_card *card, int mixer, unsigned int left, unsigned int right)
+ again caller's job to make sure all is well in arg land,
+ call with spinlock held */
+static void ac97_write_mixer(struct trident_card *card, int mixer,
+ unsigned int left, unsigned int right)
{
- u16 val=0;
+ u16 val = 0;
struct ac97_mixer_hw *mh = &ac97_hw[mixer];
- printk("(trident) wrote ac97 mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
+#ifdef DEBUG
+ printk("trident: wrote OSS mixer %2d (ac97 register 0x%02x), "
+ "left vol:%2d, right vol:%2d:",
+ mixer, mh->offset, left, right);
+#endif
- if(AC97_STEREO_MASK & (1<<mixer)) {
+ if (AC97_STEREO_MASK & (1 << mixer)) {
/* stereo mixers */
-
-
if (mixer == SOUND_MIXER_IGAIN) {
right = (right * mh->scale) / 100;
left = (left * mh->scale) / 100;
}
val = (left << 8) | right;
-
} else if (mixer == SOUND_MIXER_SPEAKER) {
val = (((100 - left) * mh->scale) / 100) << 1;
} else if (mixer == SOUND_MIXER_MIC) {
val = trident_ac97_get(card , mh->offset) & ~0x801f;
val |= (((100 - left) * mh->scale) / 100);
- /* the low bit is optional in the tone sliders and masking
- it lets us avoid the 0xf 'bypass'.. */
+ /* the low bit is optional in the tone sliders and masking
+ it lets us avoid the 0xf 'bypass'.. */
} else if (mixer == SOUND_MIXER_BASS) {
val = trident_ac97_get(card , mh->offset) & ~0x0f00;
val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (mixer == SOUND_MIXER_TREBLE) {
+ } else if (mixer == SOUND_MIXER_TREBLE) {
val = trident_ac97_get(card , mh->offset) & ~0x000f;
val |= (((100 - left) * mh->scale) / 100) & 0x000e;
}
+#ifdef DEBUG
+ printk(" 0x%04x", val);
+#endif
+
trident_ac97_set(card, mh->offset, val);
-
- printk(" -> %x\n",val);
+
+#ifdef DEBUG
+ val = trident_ac97_get(card, mh->offset);
+ printk(" -> 0x%04x\n", val);
+#endif
}
/* the following tables allow us to go from
AC97_REC_AUX,
AC97_REC_LINE,
AC97_REC_STEREO, /* combination of all enabled outputs.. */
- AC97_REC_MONO, /*.. or the mono equivalent */
- AC97_REC_PHONE
+ AC97_REC_MONO, /*.. or the mono equivalent */
+ AC97_REC_PHONE
};
static unsigned int ac97_rm2oss[] = {
};
/* read or write the recmask
- the ac97 can really have left and right recording
- inputs independantly set, but OSS doesn't seem to
- want us to express that to the user.
- the caller guarantees that we have a supported bit set,
- and they must be holding the card's spinlock */
-
+ the ac97 can really have left and right recording
+ inputs independantly set, but OSS doesn't seem to
+ want us to express that to the user.
+ the caller guarantees that we have a supported bit set,
+ and they must be holding the card's spinlock */
static int ac97_recmask_io(struct trident_card *card, int rw, int mask)
{
unsigned int val;
}
/* else, write the first set in the mask as the
- output */
+ output */
val = ffs(mask);
val = ac97_oss_rm[val-1];
val |= val << 8; /* set both channels */
-
- printk("trident: setting ac97 recmask to 0x%x\n",val);
-
- trident_ac97_set(card,0x1a,val);
+#ifdef DEBUG
+ printk("trident: setting ac97 recmask to 0x%x\n", val);
+#endif
+ trident_ac97_set(card, 0x1a, val);
return 0;
};
-/*
- * Generic AC97 codec initialisation. Need to check there are no
- * quirks for the Trident cards.
- */
-
+/* AC97 codec initialisation. */
static u16 trident_ac97_init(struct trident_card *trident)
{
- trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
- trident->mix.stereo_mixers = AC97_STEREO_MASK;
- trident->mix.record_sources = AC97_RECORD_MASK;
-/* trident->mix.read_mixer = ac97_read_mixer;*/
- trident->mix.write_mixer = ac97_write_mixer;
- trident->mix.recmask_io = ac97_recmask_io;
+ u16 id1, id2;
+ char *ac97_name = NULL;
+ int i;
- if(trident->card_type == TYPE_4DWAVE_NX)
+ /* initialize controller side of AC link */
+ switch (trident->pci_id)
{
- unsigned short VendorID1, VendorID2;
-
+ case PCI_DEVICE_ID_SI_7018:
+ /* disable AC97 GPIO interrupt */
+ outl(0x00, TRID_REG(trident, SI_AC97_GPIO));
+ /* stop AC97 cold reset process */
+ outl(0x00014000, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ /* playback on */
+ outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ /* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
outl(0x02, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
+ break;
+ }
- // 4 Speaker Codec initialization
- VendorID1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
- VendorID2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
-
- if( (VendorID1 == 0x8384) && (VendorID2 == 0x7608) )
- {
- // Sigmatel 9708.
-
- unsigned short TestReg;
- unsigned int DTemp;
-
- trident_ac97_set(trident, AC97_SIGMATEL_CIC1, 0xABBAL);
- trident_ac97_set(trident, AC97_SIGMATEL_CIC2, 0x1000L);
-
- TestReg = trident_ac97_get(trident, AC97_SIGMATEL_BIAS2);
-
- if( TestReg != 0x8000 ) // Errata Notice.
- {
- trident_ac97_set(trident, AC97_SIGMATEL_BIAS1, 0xABBAL );
- trident_ac97_set(trident, AC97_SIGMATEL_BIAS2, 0x0007L );
- }
- else // Newer version
- {
- trident_ac97_set(trident, AC97_SIGMATEL_CIC2, 0x1001L ); // recommended
- trident_ac97_set(trident, AC97_SIGMATEL_DAC2INVERT, 0x0008L );
- }
-
- trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
- trident_ac97_set( trident, AC97_HEADPHONE_VOL, 0x8000L );
-
- DTemp = (unsigned int)trident_ac97_get( trident, AC97_GENERAL_PURPOSE );
- trident_ac97_set( trident, AC97_GENERAL_PURPOSE, DTemp & 0x0000FDFFL ); // bit9 = 0.
-
- DTemp = (unsigned int)trident_ac97_get( trident, AC97_MIC_VOL );
- trident_ac97_set( trident, AC97_MIC_VOL, DTemp | 0x00008000L ); // bit15 = 1.
+ /* get some information about our AC97 codec */
+ id1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
+ id2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
+ for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
+ if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+ ac97_name = snd_ac97_codec_ids[i].name;
+ break;
+ }
+ }
+ if (ac97_name == NULL)
+ ac97_name = "Unknown";
+ printk(KERN_INFO "trident: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
+ id1, id2, ac97_name);
- DTemp = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
- outl(DTemp | 0x0010, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
+ /* initialize volume level */
+ trident_ac97_set(trident, AC97_RESET, 0L);
+ trident_ac97_set(trident, AC97_MASTER_VOL_STEREO, 0L);
+ trident_ac97_set(trident, AC97_PCMOUT_VOL, 0L);
- }
- else if((VendorID1 == 0x5452) && (VendorID2 == 0x4108) )
- { // TriTech TR28028
- trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
- trident_ac97_set( trident, AC97_EXTENDED_STATUS, 0x0000L );
- }
- else if((VendorID1 == 0x574D) &&
- (VendorID2 >= 0x4C00) && (VendorID2 <= 0x4C0f))
- { // Wolfson WM9704
- trident_ac97_set( trident, AC97_SURROUND_MASTER, 0x0000L );
- }
- else
- {
-#if 0
- printk("trident: No four Speaker Support with on board CODEC\n") ;
-#endif
- }
+ /* set appropriate masks and function pointers */
+ trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
+ trident->mix.stereo_mixers = AC97_STEREO_MASK;
+ trident->mix.record_sources = AC97_RECORD_MASK;
+ /* FIXME: trident->mix.read_mixer = ac97_read_mixer; */
+ trident->mix.write_mixer = ac97_write_mixer;
+ trident->mix.recmask_io = ac97_recmask_io;
- // S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled
- outl(0x200004, TRID_REG(trident, NX_SPCSTATUS));
- // Enable S/PDIF out, 48khz only from ac97 fifo
- outb(0x28, TRID_REG(trident, NX_SPCTRL_SPCSO+3));
- }
- else
- {
- outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
- }
return 0;
}
-
/* this only fixes the output apu mode to be later set by start_dac and
- company. output apu modes are set in trident_rec_setup */
+ company. output apu modes are set in trident_rec_setup */
static void set_fmt(struct trident_state *s, unsigned char mask, unsigned char data)
{
s->fmt = (s->fmt & mask) | data;
/* Set the chip ? */
}
-
-/*
- * Native play back driver
- */
-
/* the mode passed should be already shifted and masked */
+/* trident_play_setup: initialize channel for play back, mode specify the format of samples to
+ be played.
+ default values:
+*/
-static void trident_play_setup(struct trident_state *trident, int mode, u32 rate, void *buffer, int size)
+static void trident_play_setup(struct trident_state *trident, int mode, u32 rate,
+ void *buffer, int size)
{
unsigned int LBA;
unsigned int Delta;
unsigned int VOL;
unsigned int EC;
-
-
- /* set Loop Back Address */
+ /* set Loop Begin Address */
LBA = virt_to_bus(buffer);
-
Delta = compute_rate(rate);
- M_printk("(trident) rate, delta = %d %d\n", rate, Delta);
-
/* set ESO */
ESO = size;
if (mode & TRIDENT_FMT_16BIT)
ESO /= 2;
if (mode & TRIDENT_FMT_STEREO)
ESO /= 2;
-
ESO = ESO - 1;
- //snd_printk("trid: ESO = %d\n", ESO);
- /* set ctrl mode
- CTRL default: 8-bit (unsigned) mono, loop mode enabled
- */
CTRL = 0x00000001;
- if (mode & TRIDENT_FMT_16BIT)
- {
+ if (mode & TRIDENT_FMT_16BIT) {
CTRL |= 0x00000008; // 16-bit data
CTRL |= 0x00000002; // signed data
}
- if (mode&TRIDENT_FMT_STEREO)
+ if (mode & TRIDENT_FMT_STEREO)
CTRL |= 0x00000004; // stereo data
-
- //FMC_RVOL_CVOL = 0x0000c000;
+
+ /* FIXME: some difference between 4D and 7018 in FMC_RVOL_CVOL */
+ /* right vol: mute, ledt vol: mute */
FMC_RVOL_CVOL = 0x0000ffff;
GVSEL = 1;
PAN = 0;
EC = 0;
trident_write_voice_regs(trident->card,
- trident->dma_dac.chan[1],
- LBA,
- 0, /* cso */
- ESO,
- Delta,
- 0, /* alpha */
- FMC_RVOL_CVOL,
- GVSEL,
- PAN,
- VOL,
- CTRL,
- EC);
+ trident->dma_dac.chan[1],
+ LBA,
+ 0, /* cso */
+ ESO,
+ Delta,
+ 0, /* alpha */
+ FMC_RVOL_CVOL,
+ GVSEL,
+ PAN,
+ VOL,
+ CTRL,
+ EC);
}
/*
* Native record driver
*/
-
+/* FIXME: Not exammed yet */
/* again, passed mode is alrady shifted/masked */
static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate, void *buffer, int size)
unsigned int dwChanFlags;
struct trident_card *card = trident->card;
+#ifdef DEBUG
+ printk("trident: trident_rec_setup called\n");
+#endif
+
// Enable AC-97 ADC (capture), disable capture interrupt
- if (trident->card->card_type != TYPE_4DWAVE_NX)
+ switch (card->pci_id)
{
+ case PCI_DEVICE_ID_SI_7018:
+ /* for 7018, the ac97 is always in playback/record (duplex) mode */
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
bValue = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
outb(bValue | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- }
- else
- {
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
wValue = inw(TRID_REG(card, T4D_MISCINT));
outw(wValue | 0x1000, TRID_REG(card, T4D_MISCINT));
+ break;
}
// Initilize the channel and set channel Mode
}
-/* Playback pointer */
+/* get current playback pointer */
__inline__ unsigned int get_dmaa(struct trident_state *trident)
{
- unsigned int cso;
- unsigned int eso;
-
+ u32 cso;
+ u32 eso;
#if 0
+ /* FIXME: does this mean that FULL duplex is not supported ? */
if (!(trident->enable & ADC_RUNNING))
return 0;
#endif
-
outb(trident->dma_dac.chan[1], TRID_REG(trident->card, T4D_LFO_GC_CIR));
- if (trident->card->card_type != TYPE_4DWAVE_NX)
+ switch (trident->card->pci_id)
{
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ /* 16 bits ESO, CSO for 7018 and DX */
cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
eso = inw(TRID_REG(trident->card, CH_DX_ESO_DELTA + 2));
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ /* 24 bits ESO, CSO for NX */
+ cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+ eso = inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
+ break;
+ default:
+ return 0;
}
- else // ID_4DWAVE_NX
- {
- cso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
- eso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
- }
- M_printk("(trident) get_dmaa: chip reported %d.%d\n", cso, eso);
- cso++;
+#ifdef DEBUG
+ printk("trident: get_dmaa: chip reported esc = %d, cso = %d\n", cso, eso);
+#endif
+ cso++;
+ /* ESO and CSO are in units of Samples, convert to byte offset */
if (cso > eso)
cso = eso;
-
if (trident->fmt & TRIDENT_FMT_16BIT)
cso *= 2;
if (trident->fmt & TRIDENT_FMT_STEREO)
return cso;
}
-/* Record pointer */
+/* get current recording pointer */
extern __inline__ unsigned get_dmac(struct trident_state *trident)
{
- unsigned int cso;
-
+ u32 cso;
+#if 0
+ /* FIXME: does this mean that FULL duplex is not supported ? */
if (!(trident->enable&DAC_RUNNING))
return 0;
-
+#endif
outb(trident->dma_adc.chan[0], TRID_REG(trident->card, T4D_LFO_GC_CIR));
- if (trident->card->card_type != TYPE_4DWAVE_NX) {
+ switch (trident->card->pci_id)
+ {
+ default:
+ case PCI_DEVICE_ID_SI_7018:
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+ /* 16 bits ESO, CSO for 7018 and DX */
cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
- } else { // ID_4DWAVE_NX
- cso = (unsigned int) inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+ break;
+ case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+ /* 24 bits ESO, CSO for NX */
+ cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+ break;
}
- printk("(trident) get_dmac: chip reported %d\n", cso);
-
+#ifdef DEBUG
+ printk("(trident) get_dmac: chip reported cso = %d\n", cso);
+#endif
cso++;
-
+ /* ESO and CSO are in units of Samples, convert to byte offset */
if (trident->fmt & TRIDENT_FMT_16BIT)
cso *= 2;
if (trident->fmt & TRIDENT_FMT_STEREO)
return cso;
}
-static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-static void trident_kick(unsigned long plop)
-{
- trident_interrupt(5, (void *)plop, NULL);
- debug_timer.expires=jiffies+1;
- add_timer(&debug_timer);
-}
-
/* Stop recording (lock held) */
-
extern inline void __stop_adc(struct trident_state *s)
{
struct trident_card *trident = s->card;
-
- M_printk("(trident) stopping ADC\n");
-
-
+#ifdef DEBUG
+ printk("(trident) stopping ADC\n");
+#endif
s->enable &= ~ADC_RUNNING;
trident_disable_voice_irq(trident, s->dma_adc.chan[0]);
outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
extern inline void __stop_dac(struct trident_state *s)
{
struct trident_card *trident = s->card;
-
- M_printk("(trident) stopping DAC\n");
-
+#ifdef DEBUG
+ printk("(trident) stopping DAC\n");
+#endif
//trident_stop_voice(trident, s->dma_dac.chan[0]);
//trident_disable_voice_irq(trident, s->dma_dac.chan[0]);
trident_stop_voice(trident, s->dma_dac.chan[1]);
trident_enable_voice_irq(trident, s->dma_dac.chan[1]);
trident_start_voice(trident, s->dma_dac.chan[1]);
//trident_start_voice(trident, s->dma_dac.chan[0]);
- M_printk("(trident) starting DAC\n");
-
+#ifdef DEBUG
+ printk("(trident) starting DAC\n");
+#endif
}
spin_unlock_irqrestore(&s->card->lock, flags);
}
trident_enable_voice_irq(s->card, s->dma_adc.chan[0]);
outb(s->bDMAStart, TRID_REG(s->card, T4D_SBCTRL_SBE2R_SBDD));
trident_start_voice(s->card, s->dma_adc.chan[0]);
- M_printk("(trident) starting ADC\n");
-
+#ifdef DEBUG
+ printk("(trident) starting ADC\n");
+#endif
}
spin_unlock_irqrestore(&s->card->lock, flags);
}
-/* --------------------------------------------------------------------- */
-
-/* we allocate both buffers at once */
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 2
+/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
+static int alloc_dmabuf(struct trident_state *state, unsigned rec)
+{
+ void *rawbuf;
+ int order;
+ unsigned long map, mapend;
+
+ /* alloc as big a chunk as we can, FIXME: is this necessary ?? */
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+ if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+ break;
+ if (!rawbuf)
+ return -ENOMEM;
+
+ /* for 4DWave and 7018, there are only 30 (31) siginifcan bits for Loop Begin Address
+ (LBA) which limits the address space to 1 (2) GB, bad T^2 design */
+ if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~0x3fffffff) {
+ printk(KERN_ERR "trident: DMA buffer beyond 1 GB; "
+ "bus address = 0x%lx, size = %ld\n",
+ virt_to_bus(rawbuf), PAGE_SIZE << order);
+ free_pages((unsigned long)rawbuf, order);
+ return -ENOMEM;
+ }
+
+ if (rec) {
+ state->dma_adc.ready = state->dma_adc.mapped = 0;
+ state->dma_adc.rawbuf = rawbuf;
+ state->dma_adc.buforder = order;
+ }
+ else {
+ state->dma_dac.ready = state->dma_dac.mapped = 0;
+ state->dma_dac.rawbuf = rawbuf;
+ state->dma_dac.buforder = order;
+ }
+
+ /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+ mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+ for (map = MAP_NR(rawbuf); map <= mapend; map++)
+ set_bit(PG_reserved, &mem_map[map].flags);
+
+ return 0;
+}
+
+/* free DMA buffer */
static void dealloc_dmabuf(struct dmabuf *db)
{
unsigned long map, mapend;
- if (db->rawbuf)
- {
- M_printk("(trident) freeing %p\n",db->rawbuf);
+ if (db->rawbuf) {
/* undo marking the pages as reserved */
mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
db->mapped = db->ready = 0;
}
-static int prog_dmabuf(struct trident_state *s, unsigned rec)
+static int prog_dmabuf(struct trident_state *state, unsigned rec)
{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- int order;
+ struct dmabuf *db = rec ? &state->dma_adc : &state->dma_dac;
+ unsigned rate = rec ? state->rateadc : state->ratedac;
unsigned bytepersec;
unsigned bufs;
- unsigned long map, mapend;
unsigned char fmt;
unsigned long flags;
+ int ret;
- spin_lock_irqsave(&s->card->lock, flags);
- fmt = s->fmt;
+ spin_lock_irqsave(&state->card->lock, flags);
+ fmt = state->fmt;
if (rec) {
- s->enable &= ~TRIDENT_ENABLE_RE;
+ state->enable &= ~TRIDENT_ENABLE_RE;
fmt >>= TRIDENT_ADC_SHIFT;
} else {
- s->enable &= ~TRIDENT_ENABLE_PE;
+ state->enable &= ~TRIDENT_ENABLE_PE;
fmt >>= TRIDENT_DAC_SHIFT;
}
- spin_unlock_irqrestore(&s->card->lock, flags);
- fmt &= TRIDENT_FMT_MASK;
+ spin_unlock_irqrestore(&state->card->lock, flags);
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
- if (!db->rawbuf) {
- void *rawbuf;
- /* haha, this thing is hacked to hell and back.
- this is so ugly. */
- s->dma_dac.ready = s->dma_dac.mapped = 0;
- s->dma_adc.ready = s->dma_adc.mapped = 0;
-
- /* alloc as big a chunk as we can */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
-
- break;
-
- if (!rawbuf)
- return -ENOMEM;
-
-
- /* we allocated both buffers */
- s->dma_adc.rawbuf = rawbuf;
- s->dma_dac.rawbuf = rawbuf + ( PAGE_SIZE << (order - 1) );
-
- M_printk("(trident) allocated %ld bytes at %p\n",PAGE_SIZE<<order, db->rawbuf);
-
- s->dma_adc.buforder = s->dma_dac.buforder = order - 1;
+ fmt &= TRIDENT_FMT_MASK;
- /* XXX these checks are silly now */
-#if 0
- if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << order) - 1)) & ~0xffff)
- printk(KERN_DEBUG "trident: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << order);
+ db->hwptr = db->swptr = db->total_bytes = 0;
+ db->count = db->error = db->endcleared = 0;
-#endif
- if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << order) - 1) & ~0xffffff)
- M_printk(KERN_DEBUG "(trident) DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << order);
+ /* allocate DMA buffer if not allocated yet */
+ if (!db->rawbuf)
+ if ((ret = alloc_dmabuf(state, rec)))
+ return ret;
- /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
- mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << order) - 1);
- for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
- set_bit(PG_reserved, &mem_map[map].flags);
- }
bytepersec = rate << sample_shift[fmt];
bufs = PAGE_SIZE << db->buforder;
if (db->ossfragshift) {
else
db->fragshift = db->ossfragshift;
} else {
- /* lets hand out reasonable big ass buffers by default */
+ /* lets hand out reasonable big ass buffers by default */
db->fragshift = (db->buforder + PAGE_SHIFT -2);
-#if 0
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
-#endif
}
db->numfrag = bufs >> db->fragshift;
while (db->numfrag < 4 && db->fragshift > 3) {
memset(db->rawbuf, (fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, db->dmasize);
- spin_lock_irqsave(&s->card->lock, flags);
+ spin_lock_irqsave(&state->card->lock, flags);
if (rec) {
- trident_rec_setup(s, fmt, s->rateadc,
- db->rawbuf, db->numfrag << db->fragshift);
+ trident_rec_setup(state, fmt, state->rateadc,
+ db->rawbuf, db->numfrag << db->fragshift);
} else {
- trident_play_setup(s, fmt, s->ratedac,
- db->rawbuf, db->numfrag << db->fragshift);
+ trident_play_setup(state, fmt, state->ratedac,
+ db->rawbuf, db->numfrag << db->fragshift);
}
- spin_unlock_irqrestore(&s->card->lock, flags);
+ spin_unlock_irqrestore(&state->card->lock, flags);
+
+ /* set the ready flag for the dma buffer */
db->ready = 1;
return 0;
}
/* only called by trident_write */
-
extern __inline__ void clear_advance(struct trident_state *s)
{
unsigned char c = ((s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_16BIT) ? 0 : 0x80;
}
}
}
+
/* update DAC pointer */
if (s->dma_dac.ready)
{
/* this is so gross. */
hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize;
diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- M_printk("(trident) updating dac: hwptr: %d diff: %d\n",hwptr,diff);
+#ifdef DEBUG
+ printk("(trident) updating dac: hwptr: %d diff: %d\n",hwptr,diff);
+#endif
s->dma_dac.hwptr = hwptr;
s->dma_dac.total_bytes += diff;
if (s->dma_dac.mapped)
else
{
s->dma_dac.count -= diff;
- M_printk("(trident) trident_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count);
+#ifdef DEBUG
+ printk("(trident) trident_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count);
+#endif
if (s->dma_dac.count <= 0)
{
s->enable &= ~TRIDENT_ENABLE_PE;
/*
* Trident interrupt handlers.
*/
-
static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct trident_state *s;
- struct trident_card *c = (struct trident_card *)dev_id;
+ struct trident_state *state;
+ struct trident_card *card = (struct trident_card *)dev_id;
int i;
u32 event;
- spin_lock(&c->lock);
-
- event = inl(TRID_REG(c, T4D_MISCINT));
-
-// if(event & 0x28)
-// printk("IRQ %04X (%08lX, %08lX)\n", event, c->iobase, TRID_REG(c, T4D_MISCINT));
-
- if(event & 8)
- {
- /* Midi - TODO */
- }
-
- if(event & 0x20)
- {
- /*
- * Update the pointers for all channels we are running.
- */
-
- for(i=0;i<NR_DSPS;i++)
- {
- s=&c->channels[i];
- if(DidChannelInterrupt(c, i))
- {
- AckChannelInterrupt(c,i);
- if(s->dev_audio != -1)
- trident_update_ptr(s);
- else
- {
+ spin_lock(&card->lock);
+ event = inl(TRID_REG(card, T4D_MISCINT));
+
+#ifdef DEBUG
+ printk("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
+#endif
+
+ if (event & ADDRESS_IRQ) {
+ /* Update the pointers for all channels we are running. */
+ /* the index variable i is the main bug make the original driver crash,
+ the code mix "software" channel with "hardware" channel */
+ for (i = 0; i < NR_DSPS; i++) {
+ state = &card->channels[i];
+ if (trident_check_channel_interrupt(card, 63 - i)) {
+ trident_ack_channel_interrupt(card, 63 - i);
+ if (state->dev_audio != -1)
+ trident_update_ptr(state);
+ else {
/* Spurious ? */
- M_printk("(trident) spurious channel irq %d.\n", i);
- trident_stop_voice(c, i);
- trident_disable_voice_irq(c,i);
+ printk("trident: spurious channel irq %d.\n",
+ 63 - i);
+ trident_stop_voice(card, i);
+ trident_disable_voice_irq(card, i);
}
}
}
-
- }
- spin_unlock(&c->lock);
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
+ }
-#define VALIDATE_MAGIC(FOO,MAG) \
-({ \
- if (!(FOO) || (FOO)->magic != MAG) { \
- printk(invalid_magic,__FUNCTION__); \
- return -ENXIO; \
- } \
-})
+ if (event & SB_IRQ){
+ /* Midi - TODO */
+ }
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+ /* manually clear interrupt status, bad hardware design, balme T^2 */
+ outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
+ TRID_REG(card, T4D_MISCINT));
+ spin_unlock(&card->lock);
+}
static void set_mixer(struct trident_card *card,unsigned int mixer, unsigned int val )
{
unsigned int left,right;
+
/* cleanse input a little */
right = ((val >> 8) & 0xff) ;
left = (val & 0xff) ;
- if(right > 100) right = 100;
- if(left > 100) left = 100;
+ if (right > 100) right = 100;
+ if (left > 100) left = 100;
- card->mix.mixer_state[mixer]=(right << 8) | left;
- card->mix.write_mixer(card,mixer,left,right);
+ card->mix.mixer_state[mixer] = (right << 8) | left;
+ card->mix.write_mixer(card, mixer, left, right);
}
static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned long arg)
{
unsigned long flags;
- int i, val=0;
+ int i, val = 0;
VALIDATE_CARD(card);
- if (cmd == SOUND_MIXER_INFO) {
+ if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, card_names[card->card_type], sizeof(info.id));
- strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+ strncpy(info.id, card->pci_info->name, sizeof(info.id));
+ strncpy(info.name, card->pci_info->name, sizeof(info.name));
info.modify_counter = card->mix.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, card_names[card->card_type], sizeof(info.id));
- strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+ strncpy(info.id, card->pci_info->name, sizeof(info.id));
+ strncpy(info.name, card->pci_info->name, sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
}
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
+ return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* give them the current record source */
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
- if(!card->mix.recmask_io) {
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* give them the current record source */
+ if (!card->mix.recmask_io) {
val = 0;
} else {
spin_lock_irqsave(&card->lock, flags);
spin_unlock_irqrestore(&card->lock, flags);
}
break;
-
- case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
+
+ case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
val = card->mix.supported_mixers;
break;
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+ case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
val = card->mix.record_sources;
break;
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+
+ case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
val = card->mix.stereo_mixers;
break;
-
- case SOUND_MIXER_CAPS:
+
+ case SOUND_MIXER_CAPS:
val = SOUND_CAP_EXCL_INPUT;
break;
default: /* read a specific mixer */
i = _IOC_NR(cmd);
- if ( ! supported_mixer(card,i))
+ if (!supported_mixer(card,i))
return -EINVAL;
/* do we ever want to touch the hardware? */
-/* spin_lock_irqsave(&s->lock, flags);
+ /* spin_lock_irqsave(&s->lock, flags);
val = card->mix.read_mixer(card,i);
spin_unlock_irqrestore(&s->lock, flags);*/
val = card->mix.mixer_state[i];
-/* printk("returned 0x%x for mixer %d\n",val,i);*/
-
+ /* printk("returned 0x%x for mixer %d\n",val,i);*/
break;
}
return put_user(val,(int *)arg);
}
-
- if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
- return -EINVAL;
-
- card->mix.modcnt++;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
+ card->mix.modcnt++;
+ get_user_ret(val, (int *)arg, -EFAULT);
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ if (!card->mix.recmask_io) return -EINVAL;
+ if (!(val &= card->mix.record_sources)) return -EINVAL;
- if (!card->mix.recmask_io) return -EINVAL;
- if(! (val &= card->mix.record_sources)) return -EINVAL;
+ spin_lock_irqsave(&card->lock, flags);
+ card->mix.recmask_io(card, 0, val);
+ spin_unlock_irqrestore(&card->lock, flags);
- spin_lock_irqsave(&card->lock, flags);
- card->mix.recmask_io(card,0,val);
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
+ return 0;
+ default: /* write a specific mixer */
+ i = _IOC_NR(cmd);
- if ( ! supported_mixer(card,i))
- return -EINVAL;
+ if (!supported_mixer(card, i))
+ return -EINVAL;
- spin_lock_irqsave(&card->lock, flags);
- set_mixer(card,i,val);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
+ set_mixer(card, i, val);
+ spin_unlock_irqrestore(&card->lock, flags);
- return 0;
+ return 0;
+ }
}
+ return -EINVAL;
}
-/* --------------------------------------------------------------------- */
-
-static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
-/* --------------------------------------------------------------------- */
-
static int trident_open_mixdev(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
return -ENODEV;
file->private_data = card;
+
//FIXME put back in
//MOD_INC_USE_COUNT;
return 0;
return 0;
}
-static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
{
struct trident_card *card = (struct trident_card *)file->private_data;
return mixer_ioctl(card, cmd, arg);
}
+static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
static /*const*/ struct file_operations trident_mixer_fops = {
&trident_llseek,
NULL, /* read */
NULL, /* lock */
};
-/* --------------------------------------------------------------------- */
-
+/* drain the DAC buffer
+ FIXME: This function will block (forever ??) when using
+ XMMS Qsound plugin and direct cat sample.wav > /dev/dsp
+ This behavior is when drain_dac is called by trident_release. */
static int drain_dac(struct trident_state *s, int nonblock)
{
- DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int count;
signed long tmo;
current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;)
- {
+ for (;;) {
spin_lock_irqsave(&s->card->lock, flags);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->card->lock, flags);
if (signal_pending(current))
break;
- if (nonblock)
- {
+ if (nonblock) {
remove_wait_queue(&s->dma_dac.wait, &wait);
current->state = TASK_RUNNING;
return -EBUSY;
}
-
+
tmo = (count * HZ) / s->ratedac;
tmo >>= sample_shift[(s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK];
- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
- or something. who cares. - zach */
+ /* XXX this is just broken. someone is waking us up alot,
+ or schedule_timeout is broken.
+ or something. who cares. - zach */
if (!schedule_timeout(tmo ? tmo : 1) && tmo)
- printk(KERN_DEBUG "trident: dma timed out?? %ld\n",jiffies);
+ printk(KERN_ERR "trident: dma timed out?? %ld\n", jiffies);
}
remove_wait_queue(&s->dma_dac.wait, &wait);
current->state = TASK_RUNNING;
return 0;
}
-/* --------------------------------------------------------------------- */
-
/* in this loop, dma_adc.count signifies the amount of data thats waiting
- to be copied to the user's buffer. it is filled by the interrupt
- handler and drained by this loop. */
+ to be copied to the user's buffer. it is filled by the interrupt
+ handler and drained by this loop. */
static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
+ struct trident_state *state = (struct trident_state *)file->private_data;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
- VALIDATE_STATE(s);
+ VALIDATE_STATE(state);
if (ppos != &file->f_pos)
return -ESPIPE;
- if (s->dma_adc.mapped)
+ if (state->dma_adc.mapped)
return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
return ret;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
ret = 0;
while (count > 0) {
- spin_lock_irqsave(&s->card->lock, flags);
+ spin_lock_irqsave(&state->card->lock, flags);
/* remember, all these things are expressed in bytes to be
- sent to the user.. hence the evil / 2 down below */
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ sent to the user.. hence the evil / 2 down below */
+ swptr = state->dma_adc.swptr;
+ cnt = state->dma_adc.dmasize - swptr;
+ if (state->dma_adc.count < cnt)
+ cnt = state->dma_adc.count;
+ spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- {
+ start_adc(state);
+ if (file->f_flags & O_NONBLOCK) {
ret = ret ? ret : -EAGAIN;
return ret;
}
- if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
- M_printk(KERN_DEBUG "(trident) read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- spin_lock_irqsave(&s->card->lock, flags);
-// set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ if (!interruptible_sleep_on_timeout(&state->dma_adc.wait, HZ)) {
+ printk(KERN_DEBUG "(trident) read: chip lockup? "
+ "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ state->dma_adc.dmasize,
+ state->dma_adc.fragsize,
+ state->dma_adc.count,
+ state->dma_adc.hwptr,
+ state->dma_adc.swptr);
+ stop_adc(state);
+
+ spin_lock_irqsave(&state->card->lock, flags);
+ /*set_dmac(s, virt_to_bus(s->dma_adc.rawbuf),
+ s->dma_adc.numfrag << s->dma_adc.fragshift); */
+ state->dma_adc.count = 0;
+ state->dma_adc.hwptr = 0;
+ state->dma_adc.swptr = 0;
+ spin_unlock_irqrestore(&state->card->lock, flags);
}
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
ret = ret ? ret : -ERESTARTSYS;
return ret;
}
continue;
}
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+ if (copy_to_user(buffer, state->dma_adc.rawbuf + swptr, cnt)) {
ret = ret ? ret : -EFAULT;
return ret;
}
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->card->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ swptr = (swptr + cnt) % state->dma_adc.dmasize;
+ spin_lock_irqsave(&state->card->lock, flags);
+ state->dma_adc.swptr = swptr;
+ state->dma_adc.count -= cnt;
+ spin_unlock_irqrestore(&state->card->lock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
- start_adc(s);
+ start_adc(state);
}
return ret;
static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
+ struct trident_state *state = (struct trident_state *)file->private_data;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
- int mode = (s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
+ int mode = (state->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
- M_printk("(trident) trident_write: count %d\n", count);
-
- VALIDATE_STATE(s);
+#ifdef DEBUG
+ printk("(trident) trident_write: count %d\n", count);
+#endif
+
+ VALIDATE_STATE(state);
if (ppos != &file->f_pos)
return -ESPIPE;
- if (s->dma_dac.mapped)
+ if (state->dma_dac.mapped)
return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
ret = 0;
while (count > 0) {
- spin_lock_irqsave(&s->card->lock, flags);
-
- if (s->dma_dac.count < 0)
- {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
+ spin_lock_irqsave(&state->card->lock, flags);
+ if (state->dma_dac.count < 0) {
+ state->dma_dac.count = 0;
+ state->dma_dac.swptr = state->dma_dac.hwptr;
}
- swptr = s->dma_dac.swptr;
-
- cnt = s->dma_dac.dmasize-swptr;
-
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
- spin_unlock_irqrestore(&s->card->lock, flags);
+ swptr = state->dma_dac.swptr;
+ cnt = state->dma_dac.dmasize - swptr;
+ if (state->dma_dac.count + cnt > state->dma_dac.dmasize)
+ cnt = state->dma_dac.dmasize - state->dma_dac.count;
+ spin_unlock_irqrestore(&state->card->lock, flags);
if (cnt > count)
cnt = count;
-
- if (cnt <= 0)
- {
+ if (cnt <= 0) {
/* buffer is full, wait for it to be played */
- start_dac(s);
- if (file->f_flags & O_NONBLOCK)
- {
- if(!ret) ret = -EAGAIN;
+ start_dac(state);
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret) ret = -EAGAIN;
return ret;
}
- if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ))
- {
- M_printk(KERN_DEBUG
- "trident: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr,
- s->dma_dac.swptr);
- stop_dac(s);
- spin_lock_irqsave(&s->card->lock, flags);
-// set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ if (!interruptible_sleep_on_timeout(&state->dma_dac.wait, HZ)) {
+ printk(KERN_DEBUG
+ "trident: write: chip lockup? "
+ "dmasz %u fragsz %u count %i "
+ "hwptr %u swptr %u\n",
+ state->dma_dac.dmasize,
+ state->dma_dac.fragsize,
+ state->dma_dac.count,
+ state->dma_dac.hwptr,
+ state->dma_dac.swptr);
+ stop_dac(state);
+ spin_lock_irqsave(&state->card->lock, flags);
+ /* set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf),
+ s->dma_dac.numfrag << s->dma_dac.fragshift); */
+ state->dma_dac.count = 0;
+ state->dma_dac.hwptr = 0;
+ state->dma_dac.swptr = 0;
+ spin_unlock_irqrestore(&state->card->lock, flags);
}
- if (signal_pending(current))
- {
+ if (signal_pending(current)) {
if (!ret) ret = -ERESTARTSYS;
return ret;
}
continue;
}
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
- {
+ if (copy_from_user(state->dma_dac.rawbuf + swptr, buffer, cnt)) {
if (!ret)
ret = -EFAULT;
return ret;
}
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
+ swptr = (swptr + cnt) % state->dma_dac.dmasize;
+
+ spin_lock_irqsave(&state->card->lock, flags);
+ state->dma_dac.swptr = swptr;
+ state->dma_dac.count += cnt;
+ state->dma_dac.endcleared = 0;
+ spin_unlock_irqrestore(&state->card->lock, flags);
- spin_lock_irqsave(&s->card->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->card->lock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
- start_dac(s);
+ start_dac(state);
}
return ret;
}
VALIDATE_STATE(s);
if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
+ if ((ret = prog_dmabuf(s, 0)) != 0)
return ret;
db = &s->dma_dac;
} else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
+ if ((ret = prog_dmabuf(s, 1)) != 0)
return ret;
db = &s->dma_adc;
} else
{
struct trident_state *s = (struct trident_state *)file->private_data;
unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
+ audio_buf_info abinfo;
+ count_info cinfo;
int val, mapped, ret;
unsigned char fmtm, fmtd;
-/* printk("trident: trident_ioctl: cmd %d\n", cmd);*/
-
VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+ mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
switch (cmd)
{
- case OSS_GETVERSION:
+ case OSS_GETVERSION:
return put_user(SOUND_VERSION, (int *)arg);
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, file->f_flags & O_NONBLOCK);
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ synchronize_irq();
+ s->dma_dac.swptr = s->dma_dac.hwptr = 0;
+ s->dma_dac.count = s->dma_dac.total_bytes = 0;
+ }
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ synchronize_irq();
+ s->dma_adc.swptr = s->dma_adc.hwptr = 0;
+ s->dma_adc.count = s->dma_adc.total_bytes = 0;
+ }
return 0;
- case SNDCTL_DSP_SETDUPLEX:
- /* XXX fix */
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_dac(s, file->f_flags & O_NONBLOCK);
return 0;
- case SNDCTL_DSP_GETCAPS:
- return put_user(0/*DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP*/, (int *)arg);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- synchronize_irq();
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ)
- {
+ case SNDCTL_DSP_SPEED:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val >= 0) {
+ if (file->f_mode & FMODE_READ) {
stop_adc(s);
- synchronize_irq();
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+ s->dma_adc.ready = 0;
+ trident_set_adc_rate(s, val, 1);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ trident_set_dac_rate(s, val, 1);
}
+ }
+ return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac,
+ (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ fmtd = 0;
+ fmtm = ~0;
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ if (val)
+ fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+ else
+ fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val)
+ fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ else
+ fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+ }
+ set_fmt(s, fmtm, fmtd);
return 0;
- case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val >= 0)
- {
- if (file->f_mode & FMODE_READ)
- {
- stop_adc(s);
- s->dma_adc.ready = 0;
- trident_set_adc_rate(s, val, 1);
- }
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- s->dma_dac.ready = 0;
- trident_set_dac_rate(s, val, 1);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE) {
+ if ((val = prog_dmabuf(s, 0)))
+ return val;
+ return put_user(s->dma_dac.fragsize, (int *)arg);
+ }
+ if ((val = prog_dmabuf(s, 1)))
+ return val;
+ return put_user(s->dma_adc.fragsize, (int *)arg);
- case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != AFMT_QUERY) {
fmtd = 0;
fmtm = ~0;
- if (file->f_mode & FMODE_READ)
- {
+ if (file->f_mode & FMODE_READ) {
stop_adc(s);
s->dma_adc.ready = 0;
- if (val)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+ /* fixed at 16bit for now */
+ fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
+#if 0
+ if (val == AFMT_S16_LE)
+ fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+ fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
+#endif
}
- if (file->f_mode & FMODE_WRITE)
- {
+ if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
s->dma_dac.ready = 0;
- if (val)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ if (val == AFMT_S16_LE)
+ fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+ fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
}
set_fmt(s, fmtm, fmtd);
+ }
+ return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
+ (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ?
+ AFMT_S16_LE : AFMT_S8, (int *)arg);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val != 0)
- {
- fmtd = 0;
- fmtm = ~0;
+ case SNDCTL_DSP_CHANNELS:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 0) {
+ fmtd = 0;
+ fmtm = ~0;
- if (file->f_mode & FMODE_READ)
- {
+ if (file->f_mode & FMODE_READ) {
stop_adc(s);
s->dma_adc.ready = 0;
if (val >= 2)
fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
else
fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
- }
+ }
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
- else
- fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val >= 2)
+ fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+ else
+ fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
}
+ set_fmt(s, fmtm, fmtd);
+ }
return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+ (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+ case SNDCTL_DSP_POST:
+ return 0;
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SUBDIVIDE:
+ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+ (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+ return -EINVAL;
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 1 && val != 2 && val != 4)
+ return -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ s->dma_adc.subdivision = val;
+ if (file->f_mode & FMODE_WRITE)
+ s->dma_dac.subdivision = val;
+ return 0;
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val != AFMT_QUERY)
- {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ)
- {
- stop_adc(s);
- s->dma_adc.ready = 0;
- /* fixed at 16bit for now */
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
-#if 0
- if (val == AFMT_S16_LE)
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
- else
- fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
-#endif
- }
- if (file->f_mode & FMODE_WRITE)
- {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
- else
- fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ?
- AFMT_S16_LE : AFMT_S8, (int *)arg);
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ s->dma_adc.ossfragshift = val & 0xffff;
+ s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_adc.ossfragshift < 4)
+ s->dma_adc.ossfragshift = 4;
+ if (s->dma_adc.ossfragshift > 15)
+ s->dma_adc.ossfragshift = 15;
+ if (s->dma_adc.ossmaxfrags < 4)
+ s->dma_adc.ossmaxfrags = 4;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ s->dma_dac.ossfragshift = val & 0xffff;
+ s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+ if (s->dma_dac.ossfragshift < 4)
+ s->dma_dac.ossfragshift = 4;
+ if (s->dma_dac.ossfragshift > 15)
+ s->dma_dac.ossfragshift = 15;
+ if (s->dma_dac.ossmaxfrags < 4)
+ s->dma_dac.ossmaxfrags = 4;
+ }
+ return 0;
- case SNDCTL_DSP_POST:
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(0/* DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP */,
+ (int *)arg);
+
+ case SNDCTL_DSP_SETDUPLEX:
+ /* XXX fix */
return 0;
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE)
- val |= PCM_ENABLE_OUTPUT;
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE)
+ val |= PCM_ENABLE_OUTPUT;
return put_user(val, (int *)arg);
- case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (file->f_mode & FMODE_READ)
- {
- if (val & PCM_ENABLE_INPUT)
- {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- start_adc(s);
- }
- else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE)
- {
- if (val & PCM_ENABLE_OUTPUT)
- {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- start_dac(s);
- }
- else
- stop_dac(s);
- }
+ case SNDCTL_DSP_SETTRIGGER:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
+ start_adc(s);
+ }
+ else
+ stop_adc(s);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
+ start_dac(s);
+ }
+ else
+ stop_dac(s);
+ }
return 0;
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
+ return val;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ abinfo.fragsize = s->dma_dac.fragsize;
+ abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ abinfo.fragstotal = s->dma_dac.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
+ if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
return val;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ abinfo.fragsize = s->dma_adc.fragsize;
+ abinfo.bytes = s->dma_adc.count;
+ abinfo.fragstotal = s->dma_adc.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
return 0;
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ val = s->dma_dac.count;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return put_user(val, (int *)arg);
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->card->lock, flags);
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ cinfo.bytes = s->dma_adc.total_bytes;
+ cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ cinfo.ptr = s->dma_adc.hwptr;
+ if (s->dma_adc.mapped)
+ s->dma_adc.count &= s->dma_adc.fragsize-1;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->card->lock, flags);
- trident_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->card->lock, flags);
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&s->card->lock, flags);
+ trident_update_ptr(s);
+ cinfo.bytes = s->dma_dac.total_bytes;
+ cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ cinfo.ptr = s->dma_dac.hwptr;
+ if (s->dma_dac.mapped)
+ s->dma_dac.count &= s->dma_dac.fragsize-1;
+ spin_unlock_irqrestore(&s->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE)
- {
- if ((val = prog_dmabuf(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, (int *)arg);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, (int *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
- if (file->f_mode & FMODE_READ)
- {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE)
- {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
+ case SOUND_PCM_READ_RATE:
return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
- case SOUND_PCM_READ_CHANNELS:
+ case SOUND_PCM_READ_CHANNELS:
return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
-
- case SOUND_PCM_READ_BITS:
+ (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
- (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
+ (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) :
+ (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_FILTER:
return -EINVAL;
-
+
}
return -EINVAL;
}
static int trident_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
- struct trident_card *c = devs;
- struct trident_state *s = NULL, *sp;
+ struct trident_card *card = devs;
+ struct trident_state *state = NULL, *sp;
int i;
unsigned char fmtm = ~0, fmts = 0;
- /*
- * Scan the cards and find the channel. We only
- * do this at open time so it is ok
- */
-
- while (c!=NULL)
- {
- for(i=0;i<NR_DSPS;i++)
- {
- sp=&c->channels[i];
- if(sp->dev_audio < 0)
+ /* Scan the cards and find the channel.
+ We only do this at open time so it is ok */
+ while (card != NULL) {
+ for (i = 0; i < NR_DSPS; i++) {
+ sp = &card->channels[i];
+ if (sp->dev_audio < 0)
continue;
- if((sp->dev_audio ^ minor) & ~0xf)
+ if ((sp->dev_audio ^ minor) & ~0xf)
continue;
- s=sp;
+ state = sp;
}
- c=c->next;
+ card = card->next;
}
-
- if (!s)
+
+ if (!state)
return -ENODEV;
-
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- down(&s->open_sem);
- while (s->open_mode & file->f_mode)
- {
- if (file->f_flags & O_NONBLOCK)
- {
- up(&s->open_sem);
+
+ VALIDATE_STATE(state);
+ file->private_data = state;
+
+ down(&state->open_sem);
+
+ while (state->open_mode & file->f_mode) {
+ /* the channel has been open for the same mode before */
+ if (file->f_flags & O_NONBLOCK) {
+ /* Non-blocking mode, return immediately */
+ up(&state->open_sem);
return -EWOULDBLOCK;
}
- up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ up(&state->open_sem);
+ /* blocking, wait for device to become free */
+ interruptible_sleep_on(&state->open_wait);
if (signal_pending(current))
return -ERESTARTSYS;
- down(&s->open_sem);
+ down(&state->open_sem);
}
- if (file->f_mode & FMODE_READ)
- {
-/*
- fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
+
+ if (file->f_mode & FMODE_READ) {
+ /* fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
if ((minor & 0xf) == SND_DEV_DSP16)
fmts |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; */
fmtm = (TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- trident_set_adc_rate(s, 8000, 0);
+ state->dma_adc.ossfragshift = 0;
+ state->dma_adc.ossmaxfrags = 0;
+ state->dma_adc.subdivision = 0;
+ trident_set_adc_rate(state, 8000, 0);
}
- if (file->f_mode & FMODE_WRITE)
- {
+ if (file->f_mode & FMODE_WRITE) {
fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_DAC_SHIFT);
if ((minor & 0xf) == SND_DEV_DSP16)
fmts |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- trident_set_dac_rate(s, 8000, 1);
+ state->dma_dac.ossfragshift = 0;
+ state->dma_dac.ossmaxfrags = 0;
+ state->dma_dac.subdivision = 0;
+ trident_set_dac_rate(state, 8000, 1);
}
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ set_fmt(state, fmtm, fmts);
+ state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+
+ up(&state->open_sem);
- up(&s->open_sem);
//FIXME put back in
//MOD_INC_USE_COUNT;
return 0;
static int trident_release(struct inode *inode, struct file *file)
{
- struct trident_state *s = (struct trident_state *)file->private_data;
+ struct trident_state *state = (struct trident_state *)file->private_data;
- VALIDATE_STATE(s);
+ VALIDATE_STATE(state);
if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- down(&s->open_sem);
+ drain_dac(state, file->f_flags & O_NONBLOCK);
+
+ /* stop DMA state machine and free DMA buffers */
+ down(&state->open_sem);
if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
+ stop_dac(state);
+ dealloc_dmabuf(&state->dma_dac);
}
if (file->f_mode & FMODE_READ) {
- stop_adc(s);
+ stop_adc(state);
+ dealloc_dmabuf(&state->dma_adc);
}
-
- /* free our shared dma buffers */
- dealloc_dmabuf(&s->dma_adc);
- dealloc_dmabuf(&s->dma_dac);
-
- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+ state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
/* we're covered by the open_sem */
- up(&s->open_sem);
- wake_up(&s->open_wait);
+ up(&state->open_sem);
+
+ wake_up(&state->open_wait);
+
//FIXME put back in
//MOD_DEC_USE_COUNT;
return 0;
&trident_llseek,
&trident_read,
&trident_write,
- NULL, /* readdir */
+ NULL, /* readdir */
&trident_poll,
&trident_ioctl,
NULL, /* XXX &trident_mmap, */
&trident_open,
NULL, /* flush */
&trident_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* check_media_change */
- NULL, /* revalidate */
- NULL, /* lock */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL, /* lock */
};
#ifdef CONFIG_APM
int trident_apm_callback(apm_event_t ae) {
+ return 0;
}
#endif
/* --------------------------------------------------------------------- */
-static int trident_install(struct pci_dev *pcidev, int card_type)
+static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
{
u16 w;
- u32 l;
unsigned long iobase;
int i;
struct trident_card *card;
iobase = pcidev->resource[0].start;
- if(check_region(iobase, 256))
- {
- M_printk(KERN_WARNING "(trident) can't allocate 256 bytes I/O at 0x%4.4lx\n", iobase);
+ if(check_region(iobase, 256)) {
+ printk(KERN_WARNING "trident: can't allocate I/O space at 0x%4.4lx\n",
+ iobase);
return 0;
}
/* this was tripping up some machines */
- if(pcidev->irq == 0)
- {
- printk(KERN_WARNING "(trident) pci subsystem reports irq 0, this might not be correct.\n");
+ if (pcidev->irq == 0) {
+ printk(KERN_WARNING "trident: pci subsystem reports irq 0,"
+ " this might not be correct.\n");
}
/* just to be sure */
pci_read_config_word(pcidev, PCI_COMMAND, &w);
if((w&(PCI_COMMAND_IO|PCI_COMMAND_MASTER)) != (PCI_COMMAND_IO|PCI_COMMAND_MASTER))
{
- printk("(trident) BIOS did not enable I/O access.\n");
+ printk(KERN_WARNING "trident: BIOS did not enable I/O access.\n");
w|=PCI_COMMAND_IO|PCI_COMMAND_MASTER;
- pci_write_config_word(pcidev, PCI_COMMAND,w);
+ pci_write_config_word(pcidev, PCI_COMMAND, w);
}
-
+
card = kmalloc(sizeof(struct trident_card), GFP_KERNEL);
- if(card == NULL)
- {
- printk(KERN_WARNING "(trident) out of memory\n");
+ if (card == NULL) {
+ printk(KERN_WARNING "trident: out of memory\n");
return 0;
}
memset(card, 0, sizeof(*card));
#ifdef CONFIG_APM
- printk("(trident) apm_reg_callback: %d\n",apm_register_callback(trident_apm_callback));
+ printk("trident: apm_reg_callback: %d\n",
+ apm_register_callback(trident_apm_callback));
#endif
card->iobase = iobase;
- card->card_type = card_type;
+ card->pci_info = pci_info;
+ card->pci_id = pci_info->device;
card->irq = pcidev->irq;
card->next = devs;
card->magic = TRIDENT_CARD_MAGIC;
devs = card;
ChanDwordCount = card->ChanDwordCount = 2;
- card->ChanPCM = 32;
card->ChRegs.lpChStart = card->ChRegs.data;
card->ChRegs.lpChStop = card->ChRegs.lpChStart + ChanDwordCount;
card->ChRegs.lpChAint = card->ChRegs.lpChStop + ChanDwordCount;
card->ChRegs.lpChAinten = card->ChRegs.lpChAint + ChanDwordCount;
+
card->ChRegs.lpAChStart = card->ChRegs.lpChAinten + ChanDwordCount;
card->ChRegs.lpAChStop = card->ChRegs.lpAChStart + ChanDwordCount;
card->ChRegs.lpAChAint = card->ChRegs.lpAChStop + ChanDwordCount;
card->ChRegs.lpAChAinten = card->ChRegs.lpAChAint + ChanDwordCount;
- // Assign addresses.
+
+ // Assign Bank A addresses.
card->ChRegs.lpAChStart[0] = T4D_START_A;
card->ChRegs.lpAChStop[0] = T4D_STOP_A;
card->ChRegs.lpAChAint[0] = T4D_AINT_A;
card->ChRegs.lpAChAinten[0] = T4D_AINTEN_A;
-
-
+ /* Assign Bank B addresses */
card->ChRegs.lpAChStart[1] = T4D_START_B;
card->ChRegs.lpAChStop[1] = T4D_STOP_B;
card->ChRegs.lpAChAint[1] = T4D_AINT_B;
card->ChRegs.lpAChAinten[1] = T4D_AINTEN_B;
-
outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
- trident_ac97_set(card, 0x0L , 0L);
- trident_ac97_set(card, 0x02L , 0L);
- trident_ac97_set(card, 0x18L , 0L);
+
- if(card->card_type == TYPE_4DWAVE_NX)
- {
- // Enable rear channels
- outl(0x12, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
- // ...or not, since they sound ugly. :)
- // outl(0x02, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
- // S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled
- // outl(0x200004, TRID_REG(card, NX_SPCSTATUS));
- // Disable S/PDIF out, 48khz only from ac97 fifo
- // outb(0x00, TRID_REG(card, NX_SPCTRL_SPCSO + 3));
- }
- else
- {
- outl(0x02, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
- }
-
- for(i=0;i<NR_DSPS;i++)
- {
+ spin_lock_init(&card->lock);
+
+ for (i = 0; i < NR_DSPS; i++) {
struct trident_state *s=&card->channels[i];
s->card = card;
init_waitqueue_head(&s->open_wait);
init_MUTEX(&s->open_sem);
s->magic = TRIDENT_STATE_MAGIC;
- s->channel = i;
+ s->channel = i;
if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
- printk("(trident) BOTCH!\n");
-
+ printk(KERN_ERR "trident: BOTCH!\n");
+
/*
* Now allocate the hardware resources
*/
-
+
//s->dma_dac.chan[0] = AllocateChannelPCM(card);
- s->dma_dac.chan[1] = AllocateChannelPCM(card);
//s->dma_adc.chan[0] = AllocateChannelPCM(card);
-
+ s->dma_dac.chan[1] = trident_alloc_pcm_channel(card);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0)
break;
}
-
+
num = i;
-
+
/* clear the rest if we ran out of slots to register */
- for(;i<NR_DSPS;i++)
- {
+ for (;i < NR_DSPS; i++){
struct trident_state *s=&card->channels[i];
s->dev_audio = -1;
}
-
+
trident = &card->channels[0];
/*
* Ok card ready. Begin setup proper
*/
- printk(KERN_INFO "(trident) Configuring %s found at IO 0x%04lX IRQ %d\n",
- card_names[card_type],card->iobase,card->irq);
+ printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
+ card->pci_info->name, card->iobase, card->irq);
/* stake our claim on the iospace */
- request_region(iobase, 256, card_names[card_type]);
-
- /*
- * Reset the CODEC
- */
-
+ request_region(iobase, 256, card->pci_info->name);
+
trident_ac97_init(card);
- if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0)
- {
- printk("(trident) couldn't register mixer!\n");
+ if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "trident: couldn't register mixer!\n");
}
- else
- {
+ else {
int i;
- for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)
- {
+ for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
struct mixer_defaults *md = &mixer_defaults[i];
- if(md->mixer == -1)
+ if (md->mixer == -1)
break;
- if(!supported_mixer(card,md->mixer))
+ if (!supported_mixer(card, md->mixer))
continue;
- set_mixer(card,md->mixer,md->value);
+ set_mixer(card, md->mixer, md->value);
}
}
-
- if(request_irq(card->irq, trident_interrupt, SA_SHIRQ, card_names[card_type], card))
- {
- printk(KERN_ERR "(trident) unable to allocate irq %d,\n", card->irq);
+
+ if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) {
+ printk(KERN_ERR "trident: unable to allocate irq %d,\n", card->irq);
unregister_sound_mixer(card->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
+ for (i = 0; i < NR_DSPS; i++) {
struct trident_state *s = &card->channels[i];
if(s->dev_audio != -1)
unregister_sound_dsp(s->dev_audio);
}
- release_region(card->iobase, 256);
+ release_region(card->iobase, 256);
kfree(card);
return 0;
}
- init_timer(&debug_timer);
- debug_timer.function = trident_kick;
- debug_timer.data = (unsigned long)card;
- debug_timer.expires = jiffies+1;
-
-// add_timer(&debug_timer);
-
- printk("(trident) %d channels configured.\n", num);
-
- EnableEndInterrupts(card);
+ trident_enable_end_interrupts(card);
return 1;
}
+
#ifdef MODULE
int init_module(void)
#else
{
struct pci_dev *pcidev = NULL;
int foundone = 0;
+ int i;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "(trident) version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n");
-
- pcidev = NULL;
- /*
- * Find the 4DWave DX
- */
-
- while( (pcidev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, pcidev))!=NULL
- &&
- ( trident_install(pcidev, TYPE_4DWAVE_DX) )) {
- foundone=1;
- }
-
- /*
- * Find the 4DWave NX
- */
+ printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
+ DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
- while((pcidev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, pcidev))!=NULL
- &&
- ( trident_install(pcidev, TYPE_4DWAVE_NX) )) {
- foundone=1;
+ for (i = 0; i < sizeof (pci_audio_devices); i++) {
+ pcidev = NULL;
+ while ((pcidev = pci_find_device(pci_audio_devices[i].vendor,
+ pci_audio_devices[i].device,
+ pcidev)) != NULL) {
+ foundone += trident_install(pcidev, pci_audio_devices + i);
+ }
}
- if( ! foundone )
+ if (!foundone)
return -ENODEV;
return 0;
}
#ifdef MODULE
MODULE_AUTHOR("Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("Trident 4DWave Driver");
-#ifdef M_DEBUG
+MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
+#ifdef DEBUG
MODULE_PARM(debug,"i");
#endif
void cleanup_module(void)
{
- struct trident_card *s;
-
#ifdef CONFIG_APM
apm_unregister_callback(trident_apm_callback);
#endif
- del_timer(&debug_timer);
-
- while ((s = devs)) {
+ while (devs != NULL) {
int i;
- devs = devs->next;
-
-
+
/* Kill interrupts, and SP/DIF */
-
- DisableEndInterrupts(s);
- if(s->card_type == TYPE_4DWAVE_NX)
- outb(0x00, TRID_REG(s, NX_SPCTRL_SPCSO+3));
-
- free_irq(s->irq, s);
- unregister_sound_mixer(s->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
- struct trident_state *trident = &s->channels[i];
- if(trident->dev_audio != -1)
+ trident_disable_end_interrupts(devs);
+ free_irq(devs->irq, devs);
+ unregister_sound_mixer(devs->dev_mixer);
+ for (i = 0; i < NR_DSPS; i++) {
+ struct trident_state *trident = &devs->channels[i];
+ if (trident->dev_audio != -1)
unregister_sound_dsp(trident->dev_audio);
}
- release_region(s->iobase, 256);
- kfree(s);
+ release_region(devs->iobase, 256);
+ kfree(devs);
+ devs = devs->next;
}
- printk("(trident) unloading\n");
}
#endif /* MODULE */
*/
#ifndef PCI_VENDOR_ID_TRIDENT
-#define PCI_VENDOR_ID_TRIDENT 0x1023
+#define PCI_VENDOR_ID_TRIDENT 0x1023
#endif
-#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX
-#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
+
+#ifndef PCI_VENDOR_ID_SI
+#define PCI_VENDOR_ID_SI 0x0139
#endif
-#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_NX
-#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
+
+#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
+#endif
+
+#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_NX
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
+#endif
+
+#ifndef PCI_DEVICE_ID_SI_7018
+#define PCI_DEVICE_ID_SI_7018 0x7018
#endif
/*
#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
-#define CHANNEL_REGS 5
-#define CHANNEL_START 0xe0 // The first bytes of the contiguous register space.
+#define CHANNEL_REGS 5
+#define CHANNEL_START 0xe0 // The first bytes of the contiguous register space.
-#define ID_4DWAVE_DX 0x2000
-#define ID_4DWAVE_NX 0x2001
+#define BANK_A 0
+#define BANK_B 1
+#define NUM_BANKS 2
+#define ID_4DWAVE_DX 0x2000
+#define ID_4DWAVE_NX 0x2001
+#define ID_SI_7018 0x7018
// Register definitions
// Global registers
// T2 legacy dma control registers.
-#define LEGACY_DMAR0 0x00 // ADR0
-#define LEGACY_DMAR4 0x04 // CNT0
-#define LEGACY_DMAR11 0x0b // MOD
-#define LEGACY_DMAR15 0x0f // MMR
-
-#define T4D_START_A 0x80
-#define T4D_STOP_A 0x84
-#define T4D_DLY_A 0x88
-#define T4D_SIGN_CSO_A 0x8c
-#define T4D_CSPF_A 0x90
-#define T4D_CEBC_A 0x94
-#define T4D_AINT_A 0x98
-#define T4D_AINTEN_A 0x9c
-#define T4D_LFO_GC_CIR 0xa0
-#define T4D_MUSICVOL_WAVEVOL 0xa8
-#define T4D_SBDELTA_DELTA_R 0xac
-#define T4D_MISCINT 0xb0
-#define T4D_START_B 0xb4
-#define T4D_STOP_B 0xb8
-#define T4D_SBBL_SBCL 0xc0
-#define T4D_SBCTRL_SBE2R_SBDD 0xc4
-#define T4D_AINT_B 0xd8
-#define T4D_AINTEN_B 0xdc
+#define LEGACY_DMAR0 0x00 // ADR0
+#define LEGACY_DMAR4 0x04 // CNT0
+#define LEGACY_DMAR11 0x0b // MOD
+#define LEGACY_DMAR15 0x0f // MMR
+
+#define T4D_START_A 0x80
+#define T4D_STOP_A 0x84
+#define T4D_DLY_A 0x88
+#define T4D_SIGN_CSO_A 0x8c
+#define T4D_CSPF_A 0x90
+#define T4D_CEBC_A 0x94
+#define T4D_AINT_A 0x98
+#define T4D_EINT_A 0x9c
+#define T4D_LFO_GC_CIR 0xa0
+#define T4D_AINTEN_A 0xa4
+#define T4D_MUSICVOL_WAVEVOL 0xa8
+#define T4D_SBDELTA_DELTA_R 0xac
+#define T4D_MISCINT 0xb0
+#define T4D_START_B 0xb4
+#define T4D_STOP_B 0xb8
+#define T4D_CSPF_B 0xbc
+#define T4D_SBBL_SBCL 0xc0
+#define T4D_SBCTRL_SBE2R_SBDD 0xc4
+#define T4D_STIMER 0xc8
+#define T4D_LFO_B_I2S_DELTA 0xcc
+#define T4D_AINT_B 0xd8
+#define T4D_AINTEN_B 0xdc
// MPU-401 UART
-#define T4D_MPU401_BASE 0x20
-#define T4D_MPUR0 0x20
-#define T4D_MPUR1 0x21
-#define T4D_MPUR2 0x22
-#define T4D_MPUR3 0x23
+#define T4D_MPU401_BASE 0x20
+#define T4D_MPUR0 0x20
+#define T4D_MPUR1 0x21
+#define T4D_MPUR2 0x22
+#define T4D_MPUR3 0x23
// S/PDIF Registers
-#define NX_SPCTRL_SPCSO 0x24
-#define NX_SPLBA 0x28
-#define NX_SPESO 0x2c
-#define NX_SPCSTATUS 0x64
+#define NX_SPCTRL_SPCSO 0x24
+#define NX_SPLBA 0x28
+#define NX_SPESO 0x2c
+#define NX_SPCSTATUS 0x64
// Channel Registers
-#define CH_DX_CSO_ALPHA_FMS 0xe0
-#define CH_DX_ESO_DELTA 0xe8
-#define CH_DX_FMC_RVOL_CVOL 0xec
+#define CH_DX_CSO_ALPHA_FMS 0xe0
+#define CH_DX_ESO_DELTA 0xe8
+#define CH_DX_FMC_RVOL_CVOL 0xec
-#define CH_NX_DELTA_CSO 0xe0
-#define CH_NX_DELTA_ESO 0xe8
+#define CH_NX_DELTA_CSO 0xe0
+#define CH_NX_DELTA_ESO 0xe8
#define CH_NX_ALPHA_FMS_FMC_RVOL_CVOL 0xec
-#define CH_LBA 0xe4
-#define CH_GVSEL_PAN_VOL_CTRL_EC 0xf0
+#define CH_LBA 0xe4
+#define CH_GVSEL_PAN_VOL_CTRL_EC 0xf0
// AC-97 Registers
-#define DX_ACR0_AC97_W 0x40
-#define DX_ACR1_AC97_R 0x44
-#define DX_ACR2_AC97_COM_STAT 0x48
-
-#define NX_ACR0_AC97_COM_STAT 0x40
-#define NX_ACR1_AC97_W 0x44
-#define NX_ACR2_AC97_R_PRIMARY 0x48
-#define NX_ACR3_AC97_R_SECONDARY 0x4c
-
-#define AC97_SIGMATEL_DAC2INVERT 0x6E
-#define AC97_SIGMATEL_BIAS1 0x70
-#define AC97_SIGMATEL_BIAS2 0x72
-#define AC97_SIGMATEL_CIC1 0x76
-#define AC97_SIGMATEL_CIC2 0x78
-
-#endif /* __TRID4DWAVE_H */
+#define DX_ACR0_AC97_W 0x40
+#define DX_ACR1_AC97_R 0x44
+#define DX_ACR2_AC97_COM_STAT 0x48
+
+#define NX_ACR0_AC97_COM_STAT 0x40
+#define NX_ACR1_AC97_W 0x44
+#define NX_ACR2_AC97_R_PRIMARY 0x48
+#define NX_ACR3_AC97_R_SECONDARY 0x4c
+
+#define SI_AC97_WRITE 0x40
+#define SI_AC97_READ 0x44
+#define SI_SERIAL_INTF_CTRL 0x48
+#define SI_AC97_GPIO 0x4c
+
+#define AC97_SIGMATEL_DAC2INVERT 0x6E
+#define AC97_SIGMATEL_BIAS1 0x70
+#define AC97_SIGMATEL_BIAS2 0x72
+#define AC97_SIGMATEL_CIC1 0x76
+#define AC97_SIGMATEL_CIC2 0x78
+
+#define SI_AC97_BUSY_WRITE 0x8000
+#define SI_AC97_AUDIO_BUSY 0x4000
+#define DX_AC97_BUSY_WRITE 0x8000
+#define NX_AC97_BUSY_WRITE 0x0800
+#define SI_AC97_BUSY_READ 0x8000
+#define DX_AC97_BUSY_READ 0x8000
+#define NX_AC97_BUSY_READ 0x0800
+#define AC97_REG_ADDR 0x000000ff
+#define DX_AC97_REG_ADDR 0x000000ff
+#define NX_AC97_REG_ADDR 0x000000ff
+
+enum global_control_bits {
+ CHANNLE_IDX = 0x0000003f, PB_RESET = 0x00000100,
+ PAUSE_ENG = 0x00000200,
+ OVERRUN_IE = 0x00000400, UNDERRUN_IE = 0x00000800,
+ ENDLP_IE = 0x00001000, MIDLP_IE = 0x00002000,
+ ETOG_IE = 0x00004000,
+ EDROP_IE = 0x00008000, BANK_B_EN = 0x00010000
+};
+
+enum miscint_bits {
+ PB_UNDERRUN_IRO = 0x00000001, REC_OVERRUN_IRQ = 0x00000002,
+ SB_IRQ = 0x00000004, MPU401_IRQ = 0x00000008,
+ OPL3_IRQ = 0x00000010, ADDRESS_IRQ = 0x00000020,
+ ENVELOPE_IRQ = 0x00000040, ST_IRQ = 0x00000080,
+ PB_UNDERRUN = 0x00000100, REC_OVERRUN = 0x00000200,
+ MIXER_UNDERFLOW = 0x00000400, MIXER_OVERFLOW = 0x00000800,
+ ST_TARGET_REACHED = 0x00008000, PB_24K_MODE = 0x00010000,
+ ST_IRQ_EN = 0x00800000, ACGPIO_IRQ = 0x01000000
+};
+
+#define IWriteAinten( x ) \
+ {int i; \
+ for( i= 0; i < ChanDwordCount; i++) \
+ outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));}
+
+#define IReadAinten( x ) \
+ {int i; \
+ for( i= 0; i < ChanDwordCount; i++) \
+ (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));}
+
+#define ReadAint( x ) \
+ IReadAint( x )
+
+#define WriteAint( x ) \
+ IWriteAint( x )
+
+#define IWriteAint( x ) \
+ {int i; \
+ for( i= 0; i < ChanDwordCount; i++) \
+ outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));}
+
+#define IReadAint( x ) \
+ {int i; \
+ for( i= 0; i < ChanDwordCount; i++) \
+ (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));}
+
+#define VALIDATE_MAGIC(FOO,MAG) \
+({ \
+ if (!(FOO) || (FOO)->magic != MAG) { \
+ printk(invalid_magic,__FUNCTION__); \
+ return -ENXIO; \
+ } \
+})
+
+#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
+#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+
+#endif /* __TRID4DWAVE_H */
--- /dev/null
+#
+# Telephony device configuration
+#
+mainmenu_option next_comment
+comment 'Telephony Support'
+
+tristate 'Linux telephony support' CONFIG_PHONE
+dep_tristate 'QuickNet Internet LineJack/PhoneJack support' CONFIG_PHONE_IXJ $CONFIG_PHONE
+endmenu
--- /dev/null
+#
+# Makefile for the kernel miscellaneous drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := telephony.a
+MX_OBJS :=
+M_OBJS :=
+
+ifeq ($(CONFIG_PHONE),y)
+ LX_OBJS += phonedev.o
+else
+ ifeq ($(CONFIG_PHONE),m)
+ MX_OBJS += phonedev.o
+ endif
+endif
+
+ifeq ($(CONFIG_PHONE_IXJ),y)
+ L_OBJS += ixj.o
+else
+ ifeq ($(CONFIG_PHONE_IXJ),m)
+ M_OBJS += ixj.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * ixj.c
+ *
+ * Device Driver for the Internet PhoneJACK and
+ * Internet LineJACK Telephony Cards.
+ *
+ * (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Author: Ed Okerson, <eokerson@quicknet.net>
+ *
+ * Contributors: Greg Herlein, <gherlein@quicknet.net>
+ * David W. Erhart, <derhart@quicknet.net>
+ * John Sellers, <jsellers@quicknet.net>
+ * Mike Preston, <mpreston@quicknet.net>
+ *
+ * Fixes:
+ *
+ * 2.3.x port : Alan Cox
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website: http://www.quicknet.net
+ *
+ */
+
+static char ixj_c_rcsid[] = "$Id: ixj.c,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+//#define PERFMON_STATS
+#define IXJDEBUG 0
+#define MAXRINGS 5
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/fs.h> /* everything... */
+#include <linux/errno.h> /* error codes */
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_ISAPNP
+#include <linux/isapnp.h>
+#endif
+
+#include "ixj.h"
+
+#define TYPE(dev) (MINOR(dev) >> 4)
+#define NUM(dev) (MINOR(dev) & 0xf)
+
+static int ixjdebug = 0;
+static int hertz = HZ;
+static int samplerate = 100;
+
+MODULE_PARM(ixjdebug, "i");
+
+static IXJ ixj[IXJMAX];
+
+static struct timer_list ixj_timer;
+
+int ixj_convert_loaded = 0;
+
+/************************************************************************
+*
+* These are function definitions to allow external modules to register
+* enhanced functionality call backs.
+*
+************************************************************************/
+
+static int Stub(IXJ * J, unsigned long arg)
+{
+ return 0;
+}
+
+static IXJ_REGFUNC ixj_DownloadG729 = &Stub;
+static IXJ_REGFUNC ixj_DownloadTS85 = &Stub;
+static IXJ_REGFUNC ixj_PreRead = &Stub;
+static IXJ_REGFUNC ixj_PostRead = &Stub;
+static IXJ_REGFUNC ixj_PreWrite = &Stub;
+static IXJ_REGFUNC ixj_PostWrite = &Stub;
+static IXJ_REGFUNC ixj_PreIoctl = &Stub;
+static IXJ_REGFUNC ixj_PostIoctl = &Stub;
+
+static void ixj_read_frame(int board);
+static void ixj_write_frame(int board);
+static void ixj_init_timer(void);
+static void ixj_add_timer(void);
+static void ixj_del_timer(void);
+static void ixj_timeout(unsigned long ptr);
+static int read_filters(int board);
+static int LineMonitor(int board);
+static int ixj_fasync(int fd, struct file *, int mode);
+static int ixj_hookstate(int board);
+static int ixj_record_start(int board);
+static void ixj_record_stop(int board);
+static int ixj_play_start(int board);
+static void ixj_play_stop(int board);
+static int ixj_set_tone_on(unsigned short arg, int board);
+static int ixj_set_tone_off(unsigned short, int board);
+static int ixj_play_tone(int board, char tone);
+static int idle(int board);
+static void ixj_ring_on(int board);
+static void ixj_ring_off(int board);
+static void aec_stop(int board);
+static void ixj_ringback(int board);
+static void ixj_busytone(int board);
+static void ixj_dialtone(int board);
+static void ixj_cpt_stop(int board);
+static char daa_int_read(int board);
+static int daa_set_mode(int board, int mode);
+static int ixj_linetest(int board);
+static int ixj_daa_cid_read(int board);
+static void DAA_Coeff_US(int board);
+static void DAA_Coeff_UK(int board);
+static void DAA_Coeff_France(int board);
+static void DAA_Coeff_Germany(int board);
+static void DAA_Coeff_Australia(int board);
+static void DAA_Coeff_Japan(int board);
+static int ixj_init_filter(int board, IXJ_FILTER * jf);
+static int ixj_init_tone(int board, IXJ_TONE * ti);
+static int ixj_build_cadence(int board, IXJ_CADENCE * cp);
+// Serial Control Interface funtions
+static int SCI_Control(int board, int control);
+static int SCI_Prepare(int board);
+static int SCI_WaitHighSCI(int board);
+static int SCI_WaitLowSCI(int board);
+static DWORD PCIEE_GetSerialNumber(WORD wAddress);
+
+/************************************************************************
+CT8020/CT8021 Host Programmers Model
+Host address Function Access
+DSPbase +
+0-1 Aux Software Status Register (reserved) Read Only
+2-3 Software Status Register Read Only
+4-5 Aux Software Control Register (reserved) Read Write
+6-7 Software Control Register Read Write
+8-9 Hardware Status Register Read Only
+A-B Hardware Control Register Read Write
+C-D Host Transmit (Write) Data Buffer Access Port (buffer input)Write Only
+E-F Host Recieve (Read) Data Buffer Access Port (buffer input) Read Only
+************************************************************************/
+
+extern __inline__ void ixj_read_HSR(int board)
+{
+ ixj[board].hsr.bytes.low = inb_p(ixj[board].DSPbase + 8);
+ ixj[board].hsr.bytes.high = inb_p(ixj[board].DSPbase + 9);
+}
+extern __inline__ int IsControlReady(int board)
+{
+ ixj_read_HSR(board);
+ return ixj[board].hsr.bits.controlrdy ? 1 : 0;
+}
+
+extern __inline__ int IsStatusReady(int board)
+{
+ ixj_read_HSR(board);
+ return ixj[board].hsr.bits.statusrdy ? 1 : 0;
+}
+
+extern __inline__ int IsRxReady(int board)
+{
+ ixj_read_HSR(board);
+ return ixj[board].hsr.bits.rxrdy ? 1 : 0;
+}
+
+extern __inline__ int IsTxReady(int board)
+{
+ ixj_read_HSR(board);
+ return ixj[board].hsr.bits.txrdy ? 1 : 0;
+}
+
+extern __inline__ BYTE SLIC_GetState(int board)
+{
+ IXJ *j = &ixj[board];
+
+ j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01);
+
+ return j->pld_slicr.bits.state;
+}
+
+static BOOL SLIC_SetState(BYTE byState, int board)
+{
+ BOOL fRetVal = FALSE;
+ IXJ *j = &ixj[board];
+
+ // Set the C1, C2, C3 & B2EN signals.
+ switch (byState) {
+ case PLD_SLIC_STATE_OC:
+ j->pld_slicw.bits.c1 = 0;
+ j->pld_slicw.bits.c2 = 0;
+ j->pld_slicw.bits.c3 = 0;
+ j->pld_slicw.bits.b2en = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ case PLD_SLIC_STATE_RINGING:
+ j->pld_slicw.bits.c1 = 1;
+ j->pld_slicw.bits.c2 = 0;
+ j->pld_slicw.bits.c3 = 0;
+ j->pld_slicw.bits.b2en = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ case PLD_SLIC_STATE_ACTIVE:
+ j->pld_slicw.bits.c1 = 0;
+ j->pld_slicw.bits.c2 = 1;
+ j->pld_slicw.bits.c3 = 0;
+ j->pld_slicw.bits.b2en = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ case PLD_SLIC_STATE_OHT: // On-hook transmit
+
+ j->pld_slicw.bits.c1 = 1;
+ j->pld_slicw.bits.c2 = 1;
+ j->pld_slicw.bits.c3 = 0;
+ j->pld_slicw.bits.b2en = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ case PLD_SLIC_STATE_TIPOPEN:
+ j->pld_slicw.bits.c1 = 0;
+ j->pld_slicw.bits.c2 = 0;
+ j->pld_slicw.bits.c3 = 1;
+ j->pld_slicw.bits.b2en = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ case PLD_SLIC_STATE_STANDBY:
+ j->pld_slicw.bits.c1 = 1;
+ j->pld_slicw.bits.c2 = 0;
+ j->pld_slicw.bits.c3 = 1;
+ j->pld_slicw.bits.b2en = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ case PLD_SLIC_STATE_APR: // Active polarity reversal
+
+ j->pld_slicw.bits.c1 = 0;
+ j->pld_slicw.bits.c2 = 1;
+ j->pld_slicw.bits.c3 = 1;
+ j->pld_slicw.bits.b2en = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ case PLD_SLIC_STATE_OHTPR: // OHT polarity reversal
+
+ j->pld_slicw.bits.c1 = 1;
+ j->pld_slicw.bits.c2 = 1;
+ j->pld_slicw.bits.c3 = 1;
+ j->pld_slicw.bits.b2en = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ fRetVal = TRUE;
+ break;
+ default:
+ fRetVal = FALSE;
+ break;
+ }
+
+ return fRetVal;
+}
+
+int ixj_register(int index, IXJ_REGFUNC regfunc)
+{
+ int cnt;
+ int retval = 0;
+ switch (index) {
+ case G729LOADER:
+ ixj_DownloadG729 = regfunc;
+ for (cnt = 0; cnt < IXJMAX; cnt++)
+ ixj_DownloadG729(&ixj[cnt], 0L);
+ break;
+ case TS85LOADER:
+ ixj_DownloadTS85 = regfunc;
+ for (cnt = 0; cnt < IXJMAX; cnt++)
+ ixj_DownloadTS85(&ixj[cnt], 0L);
+ break;
+ case PRE_READ:
+ ixj_PreRead = regfunc;
+ break;
+ case POST_READ:
+ ixj_PostRead = regfunc;
+ break;
+ case PRE_WRITE:
+ ixj_PreWrite = regfunc;
+ break;
+ case POST_WRITE:
+ ixj_PostWrite = regfunc;
+ break;
+ case PRE_IOCTL:
+ ixj_PreIoctl = regfunc;
+ break;
+ case POST_IOCTL:
+ ixj_PostIoctl = regfunc;
+ break;
+ default:
+ retval = 1;
+ }
+ return retval;
+}
+
+int ixj_unregister(int index)
+{
+ int retval = 0;
+ switch (index) {
+ case G729LOADER:
+ ixj_DownloadG729 = &Stub;
+ break;
+ case TS85LOADER:
+ ixj_DownloadTS85 = &Stub;
+ break;
+ case PRE_READ:
+ ixj_PreRead = &Stub;
+ break;
+ case POST_READ:
+ ixj_PostRead = &Stub;
+ break;
+ case PRE_WRITE:
+ ixj_PreWrite = &Stub;
+ break;
+ case POST_WRITE:
+ ixj_PostWrite = &Stub;
+ break;
+ case PRE_IOCTL:
+ ixj_PreIoctl = &Stub;
+ break;
+ case POST_IOCTL:
+ ixj_PostIoctl = &Stub;
+ break;
+ default:
+ retval = 1;
+ }
+ return retval;
+}
+
+static void ixj_init_timer(void)
+{
+ init_timer(&ixj_timer);
+ ixj_timer.function = ixj_timeout;
+ ixj_timer.data = (int) NULL;
+}
+
+static void ixj_add_timer(void)
+{
+ ixj_timer.expires = jiffies + (hertz / samplerate);
+ add_timer(&ixj_timer);
+}
+
+static void ixj_del_timer(void)
+{
+ del_timer(&ixj_timer);
+}
+
+static void ixj_tone_timeout(int board)
+{
+ IXJ *j = &ixj[board];
+ IXJ_TONE ti;
+
+ j->tone_state++;
+ if (j->tone_state == 3) {
+ j->tone_state = 0;
+ if (j->cadence_t) {
+ j->tone_cadence_state++;
+ if (j->tone_cadence_state >= j->cadence_t->elements_used)
+ {
+ switch (j->cadence_t->termination)
+ {
+ case PLAY_ONCE:
+ ixj_cpt_stop(board);
+ break;
+ case REPEAT_LAST_ELEMENT:
+ j->tone_cadence_state--;
+ ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index);
+ break;
+ case REPEAT_ALL:
+ j->tone_cadence_state = 0;
+ if (j->cadence_t->ce[j->tone_cadence_state].freq0)
+ {
+ ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+ ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+ ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+ ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+ ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+ ixj_init_tone(board, &ti);
+ }
+ ixj_set_tone_on(j->cadence_t->ce[0].tone_on_time, board);
+ ixj_set_tone_off(j->cadence_t->ce[0].tone_off_time, board);
+ ixj_play_tone(board, j->cadence_t->ce[0].index);
+ break;
+ }
+ } else {
+ if (j->cadence_t->ce[j->tone_cadence_state].gain0)
+ {
+ ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+ ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+ ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+ ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+ ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+ ixj_init_tone(board, &ti);
+ }
+ ixj_set_tone_on(j->cadence_t->ce[j->tone_cadence_state].tone_on_time, board);
+ ixj_set_tone_off(j->cadence_t->ce[j->tone_cadence_state].tone_off_time, board);
+ ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index);
+ }
+ }
+ }
+}
+
+static void ixj_timeout(unsigned long ptr)
+{
+ int board;
+ unsigned long jifon;
+ IXJ *j;
+
+ for (board = 0; board < IXJMAX; board++)
+ {
+ j = &ixj[board];
+
+ if (j->DSPbase)
+ {
+#ifdef PERFMON_STATS
+ j->timerchecks++;
+#endif
+ if (j->tone_state)
+ {
+ if (!ixj_hookstate(board))
+ {
+ ixj_cpt_stop(board);
+ if (j->m_hook)
+ {
+ j->m_hook = 0;
+ j->ex.bits.hookstate = 1;
+ if (j->async_queue)
+ kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change
+ }
+ goto timer_end;
+ }
+ if (j->tone_state == 1)
+ jifon = (hertz * j->tone_on_time * 25 / 100000);
+ else
+ jifon = (hertz * j->tone_on_time * 25 / 100000) +
+ (hertz * j->tone_off_time * 25 / 100000);
+ if (jiffies < j->tone_start_jif + jifon) {
+ if (j->tone_state == 1) {
+ ixj_play_tone(board, j->tone_index);
+ if (j->dsp.low == 0x20) {
+ goto timer_end;
+ }
+ } else {
+ ixj_play_tone(board, 0);
+ if (j->dsp.low == 0x20) {
+ goto timer_end;
+ }
+ }
+ } else {
+ ixj_tone_timeout(board);
+ if (j->flags.dialtone) {
+ ixj_dialtone(board);
+ }
+ if (j->flags.busytone) {
+ ixj_busytone(board);
+ if (j->dsp.low == 0x20) {
+ goto timer_end;
+ }
+ }
+ if (j->flags.ringback) {
+ ixj_ringback(board);
+ if (j->dsp.low == 0x20) {
+ goto timer_end;
+ }
+ }
+ if (!j->tone_state) {
+ if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1))
+ idle(board);
+ if (j->dsp.low == 0x20 && j->play_mode != -1)
+ ixj_play_start(board);
+ if (j->dsp.low == 0x20 && j->rec_mode != -1)
+ ixj_record_start(board);
+ }
+ }
+ }
+ if (!j->tone_state || j->dsp.low != 0x20) {
+ if (IsRxReady(board)) {
+ ixj_read_frame(board);
+ }
+ if (IsTxReady(board)) {
+ ixj_write_frame(board);
+ }
+ }
+ if (j->flags.cringing) {
+ if (ixj_hookstate(board) & 1) {
+ j->flags.cringing = 0;
+ ixj_ring_off(board);
+ } else {
+ if (jiffies - j->ring_cadence_jif >= (.5 * hertz)) {
+ j->ring_cadence_t--;
+ if (j->ring_cadence_t == -1)
+ j->ring_cadence_t = 15;
+ j->ring_cadence_jif = jiffies;
+ }
+ if (j->ring_cadence & 1 << j->ring_cadence_t) {
+ ixj_ring_on(board);
+ } else {
+ ixj_ring_off(board);
+ }
+ goto timer_end;
+ }
+ }
+ if (!j->flags.ringing) {
+ if (ixj_hookstate(board)) {
+ if (j->dsp.low == 0x21 &&
+ j->pld_slicr.bits.state != PLD_SLIC_STATE_ACTIVE)
+ // Internet LineJACK
+ {
+ SLIC_SetState(PLD_SLIC_STATE_ACTIVE, board);
+ }
+ LineMonitor(board);
+ read_filters(board);
+ ixj_WriteDSPCommand(0x511B, board);
+ j->proc_load = j->ssr.high << 8 | j->ssr.low;
+ if (!j->m_hook) {
+ j->m_hook = j->ex.bits.hookstate = 1;
+ if (j->async_queue)
+ kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change
+ }
+ } else {
+ if (j->dsp.low == 0x21 &&
+ j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE)
+ // Internet LineJACK
+ {
+ SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+ }
+ if (j->ex.bits.dtmf_ready) {
+ j->dtmf_wp = j->dtmf_rp = j->ex.bits.dtmf_ready = 0;
+ }
+ if (j->m_hook) {
+ j->m_hook = 0;
+ j->ex.bits.hookstate = 1;
+ if (j->async_queue)
+ kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change
+ }
+ }
+ }
+ if (j->cardtype == 300) {
+ if (j->flags.pstn_present) {
+ j->pld_scrr.byte = inb_p(j->XILINXbase);
+ if (jiffies >= j->pstn_sleeptil && j->pld_scrr.bits.daaflag) {
+ daa_int_read(board);
+ if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.RING) {
+ if (!j->flags.pstn_ringing) {
+ j->flags.pstn_ringing = 1;
+ if (j->daa_mode != SOP_PU_RINGING)
+ daa_set_mode(board, SOP_PU_RINGING);
+ }
+ }
+ if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+ j->pstn_winkstart = 0;
+ if (j->flags.pstn_ringing && !j->pstn_envelope) {
+ j->ex.bits.pstn_ring = 0;
+ j->pstn_envelope = 1;
+ j->pstn_ring_start = jiffies;
+ }
+ } else {
+ if (j->flags.pstn_ringing && j->pstn_envelope &&
+ jiffies > j->pstn_ring_start + ((hertz * 15) / 10)) {
+ j->ex.bits.pstn_ring = 1;
+ j->pstn_envelope = 0;
+ } else if (j->daa_mode == SOP_PU_CONVERSATION) {
+ if (!j->pstn_winkstart) {
+ j->pstn_winkstart = jiffies;
+ } else if (jiffies > j->pstn_winkstart + (hertz * j->winktime / 1000)) {
+ daa_set_mode(board, SOP_PU_SLEEP);
+ j->pstn_winkstart = 0;
+ j->ex.bits.pstn_wink = 1;
+ }
+ } else {
+ j->ex.bits.pstn_ring = 0;
+ }
+ }
+ if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.Cadence) {
+ if (j->daa_mode == SOP_PU_RINGING) {
+ daa_set_mode(board, SOP_PU_SLEEP);
+ j->flags.pstn_ringing = 0;
+ j->ex.bits.pstn_ring = 0;
+ }
+ }
+ if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.Caller_ID) {
+ if (j->daa_mode == SOP_PU_RINGING && j->flags.pstn_ringing) {
+ j->pstn_cid_intr = 1;
+ j->pstn_cid_recieved = jiffies;
+ }
+ }
+ } else {
+ if (j->pld_scrr.bits.daaflag) {
+ daa_int_read(board);
+ }
+ j->ex.bits.pstn_ring = 0;
+ if (j->pstn_cid_intr && jiffies > j->pstn_cid_recieved + (hertz * 3)) {
+ if (j->daa_mode == SOP_PU_RINGING) {
+ ixj_daa_cid_read(board);
+ j->ex.bits.caller_id = 1;
+ }
+ j->pstn_cid_intr = 0;
+ } else {
+ j->ex.bits.caller_id = 0;
+ }
+ if (!j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+ if (j->flags.pstn_ringing && j->pstn_envelope) {
+ j->ex.bits.pstn_ring = 1;
+ j->pstn_envelope = 0;
+ } else if (j->daa_mode == SOP_PU_CONVERSATION) {
+ if (!j->pstn_winkstart) {
+ j->pstn_winkstart = jiffies;
+ } else if (jiffies > j->pstn_winkstart + (hertz * 320 / 1000)) {
+ daa_set_mode(board, SOP_PU_SLEEP);
+ j->pstn_winkstart = 0;
+ j->ex.bits.pstn_wink = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ if ((j->ex.bits.f0 || j->ex.bits.f1 || j->ex.bits.f2 || j->ex.bits.f3)
+ && j->filter_cadence) {
+ }
+ if (j->ex.bytes) {
+ wake_up_interruptible(&j->poll_q); // Wake any blocked selects
+ if (j->async_queue)
+ kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change
+ }
+ } else {
+ break;
+ }
+ }
+timer_end:
+ ixj_add_timer();
+}
+
+static int ixj_status_wait(int board)
+{
+ unsigned long jif;
+
+ jif = jiffies;
+ while (!IsStatusReady(board)) {
+ if (jiffies - jif > (60 * (hertz / 100))) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int ixj_WriteDSPCommand(unsigned short cmd, int board)
+{
+ BYTES bytes;
+ unsigned long jif;
+
+ bytes.high = (cmd & 0xFF00) >> 8;
+ bytes.low = cmd & 0x00FF;
+ jif = jiffies;
+ while (!IsControlReady(board)) {
+ if (jiffies - jif > (60 * (hertz / 100))) {
+ return -1;
+ }
+ }
+ outb_p(bytes.low, ixj[board].DSPbase + 6);
+ outb_p(bytes.high, ixj[board].DSPbase + 7);
+
+ if (ixj_status_wait(board)) {
+ ixj[board].ssr.low = 0xFF;
+ ixj[board].ssr.high = 0xFF;
+ return -1;
+ }
+/* Read Software Status Register */
+ ixj[board].ssr.low = inb_p(ixj[board].DSPbase + 2);
+ ixj[board].ssr.high = inb_p(ixj[board].DSPbase + 3);
+ return 0;
+}
+
+/***************************************************************************
+*
+* General Purpose IO Register read routine
+*
+***************************************************************************/
+extern __inline__ int ixj_gpio_read(int board)
+{
+ if (ixj_WriteDSPCommand(0x5143, board))
+ return -1;
+
+ ixj[board].gpio.bytes.low = ixj[board].ssr.low;
+ ixj[board].gpio.bytes.high = ixj[board].ssr.high;
+
+ return 0;
+}
+
+extern __inline__ void LED_SetState(int state, int board)
+{
+ if (ixj[board].dsp.low == 0x21) {
+ ixj[board].pld_scrw.bits.led1 = state & 0x1 ? 1 : 0;
+ ixj[board].pld_scrw.bits.led2 = state & 0x2 ? 1 : 0;
+ ixj[board].pld_scrw.bits.led3 = state & 0x4 ? 1 : 0;
+ ixj[board].pld_scrw.bits.led4 = state & 0x8 ? 1 : 0;
+
+ outb_p(ixj[board].pld_scrw.byte, ixj[board].XILINXbase);
+ }
+}
+
+/*********************************************************************
+* GPIO Pins are configured as follows on the Quicknet Internet
+* PhoneJACK Telephony Cards
+*
+* POTS Select GPIO_6=0 GPIO_7=0
+* Mic/Speaker Select GPIO_6=0 GPIO_7=1
+* Handset Select GPIO_6=1 GPIO_7=0
+*
+* SLIC Active GPIO_1=0 GPIO_2=1 GPIO_5=0
+* SLIC Ringing GPIO_1=1 GPIO_2=1 GPIO_5=0
+* SLIC Open Circuit GPIO_1=0 GPIO_2=0 GPIO_5=0
+*
+* Hook Switch changes reported on GPIO_3
+*********************************************************************/
+static int ixj_set_port(int board, int arg)
+{
+ IXJ *j = &ixj[board];
+
+ if (j->cardtype == 400) {
+ if (arg != PORT_POTS)
+ return 10;
+ else
+ return 0;
+ }
+ switch (arg) {
+ case PORT_POTS:
+ j->port = PORT_POTS;
+ switch (j->cardtype) {
+ case 500:
+ j->pld_slicw.pcib.mic = 0;
+ j->pld_slicw.pcib.spk = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ break;
+ case 300:
+ if (ixj_WriteDSPCommand(0xC528, board)) /* Write CODEC config to
+ Software Control Register */
+ return 2;
+ j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ j->pld_clock.byte = 0;
+ outb_p(j->pld_clock.byte, j->XILINXbase + 0x04);
+ j->pld_slicw.bits.rly1 = 1;
+ j->pld_slicw.bits.spken = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+ break;
+ case 100:
+ j->gpio.bytes.high = 0x0B;
+ j->gpio.bits.gpio6 = 0;
+ j->gpio.bits.gpio7 = 0;
+ ixj_WriteDSPCommand(j->gpio.word, board);
+ break;
+ }
+ break;
+ case PORT_PSTN:
+ if (j->cardtype == 300) {
+ ixj_WriteDSPCommand(0xC534, board); /* Write CODEC config to Software Control Register */
+
+ j->pld_slicw.bits.rly3 = 0;
+ j->pld_slicw.bits.rly1 = 1;
+ j->pld_slicw.bits.spken = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ j->port = PORT_PSTN;
+ } else {
+ return 4;
+ }
+ break;
+ case PORT_SPEAKER:
+ j->port = PORT_SPEAKER;
+ switch (j->cardtype) {
+ case 500:
+ j->pld_slicw.pcib.mic = 1;
+ j->pld_slicw.pcib.spk = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ break;
+ case 300:
+ break;
+ case 100:
+ j->gpio.bytes.high = 0x0B;
+ j->gpio.bits.gpio6 = 0;
+ j->gpio.bits.gpio7 = 1;
+ ixj_WriteDSPCommand(j->gpio.word, board);
+ break;
+ }
+ break;
+ case PORT_HANDSET:
+ if (j->cardtype == 300 || j->cardtype == 500) {
+ return 5;
+ } else {
+ j->gpio.bytes.high = 0x0B;
+ j->gpio.bits.gpio6 = 1;
+ j->gpio.bits.gpio7 = 0;
+ ixj_WriteDSPCommand(j->gpio.word, board);
+ j->port = PORT_HANDSET;
+ }
+ break;
+ default:
+ return 6;
+ break;
+ }
+ return 0;
+}
+
+static int ixj_set_pots(int board, int arg)
+{
+ IXJ *j = &ixj[board];
+
+ if (j->cardtype == 300) {
+ if (arg) {
+ if (j->port == PORT_PSTN) {
+ j->pld_slicw.bits.rly1 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ j->pld_slicw.bits.rly1 = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ return 1;
+ }
+ } else {
+ return 0;
+ }
+}
+
+static void ixj_ring_on(int board)
+{
+ IXJ *j = &ixj[board];
+ if (j->dsp.low == 0x20) // Internet PhoneJACK
+ {
+ if (ixjdebug > 0)
+ printk(KERN_INFO "IXJ Ring On /dev/phone%d\n", board);
+
+ j->gpio.bytes.high = 0x0B;
+ j->gpio.bytes.low = 0x00;
+ j->gpio.bits.gpio1 = 1;
+ j->gpio.bits.gpio2 = 1;
+ j->gpio.bits.gpio5 = 0;
+ ixj_WriteDSPCommand(j->gpio.word, board); /* send the ring signal */
+ } else // Internet LineJACK, Internet PhoneJACK Lite or
+ // Internet PhoneJACK PCI
+ {
+ if (ixjdebug > 0)
+ printk(KERN_INFO "IXJ Ring On /dev/phone%d\n", board);
+
+ SLIC_SetState(PLD_SLIC_STATE_RINGING, board);
+ }
+}
+
+static int ixj_hookstate(int board)
+{
+ unsigned long det;
+ IXJ *j = &ixj[board];
+ int fOffHook = 0;
+
+ switch (j->cardtype) {
+ case 100:
+ ixj_gpio_read(board);
+ fOffHook = j->gpio.bits.gpio3read ? 1 : 0;
+ break;
+ case 300:
+ case 400:
+ case 500:
+ SLIC_GetState(board);
+ if (j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE ||
+ j->pld_slicr.bits.state == PLD_SLIC_STATE_STANDBY)
+ {
+ if (j->flags.ringing)
+ {
+ if(!in_interrupt())
+ {
+ det = jiffies + (hertz / 50);
+ while (time_before(jiffies, det)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ }
+ SLIC_GetState(board);
+ if (j->pld_slicr.bits.state == PLD_SLIC_STATE_RINGING) {
+ ixj_ring_on(board);
+ }
+ }
+ if (j->cardtype == 500) {
+ j->pld_scrr.byte = inb_p(j->XILINXbase);
+ fOffHook = j->pld_scrr.pcib.det ? 1 : 0;
+ } else
+ fOffHook = j->pld_slicr.bits.det ? 1 : 0;
+ }
+ break;
+ }
+ if (j->r_hook != fOffHook) {
+ j->r_hook = fOffHook;
+ if (j->port != PORT_POTS) {
+ j->ex.bits.hookstate = 1;
+ if (j->async_queue)
+ kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of change
+
+ }
+ }
+ if (j->port == PORT_PSTN && j->daa_mode == SOP_PU_CONVERSATION)
+ fOffHook |= 2;
+
+ if (j->port == PORT_SPEAKER)
+ fOffHook |= 2;
+
+ if (j->port == PORT_HANDSET)
+ fOffHook |= 2;
+
+ return fOffHook;
+}
+
+static void ixj_ring_off(board)
+{
+ IXJ *j = &ixj[board];
+
+ if (j->dsp.low == 0x20) // Internet PhoneJACK
+ {
+ if (ixjdebug > 0)
+ printk(KERN_INFO "IXJ Ring Off\n");
+ j->gpio.bytes.high = 0x0B;
+ j->gpio.bytes.low = 0x00;
+ j->gpio.bits.gpio1 = 0;
+ j->gpio.bits.gpio2 = 1;
+ j->gpio.bits.gpio5 = 0;
+ ixj_WriteDSPCommand(j->gpio.word, board);
+ } else // Internet LineJACK
+ {
+ if (ixjdebug > 0)
+ printk(KERN_INFO "IXJ Ring Off\n");
+
+ SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+
+ SLIC_GetState(board);
+ }
+}
+
+static void ixj_ring_start(int board)
+{
+ IXJ *j = &ixj[board];
+
+ j->flags.cringing = 1;
+ if (ixj_hookstate(board) & 1) {
+ if (j->port == PORT_POTS)
+ ixj_ring_off(board);
+ j->flags.cringing = 0;
+ } else {
+ j->ring_cadence_jif = jiffies;
+ j->ring_cadence_t = 15;
+ if (j->ring_cadence & 1 << j->ring_cadence_t) {
+ ixj_ring_on(board);
+ } else {
+ ixj_ring_off(board);
+ }
+ }
+}
+
+static int ixj_ring(int board)
+{
+ char cntr;
+ unsigned long jif, det;
+ IXJ *j = &ixj[board];
+
+ j->flags.ringing = 1;
+ if (ixj_hookstate(board) & 1) {
+ ixj_ring_off(board);
+ j->flags.ringing = 0;
+ return 1;
+ }
+ det = 0;
+ for (cntr = 0; cntr < j->maxrings; cntr++) {
+ jif = jiffies + (1 * hertz);
+ ixj_ring_on(board);
+ while (time_before(jiffies, jif)) {
+ if (ixj_hookstate(board) & 1) {
+ ixj_ring_off(board);
+ j->flags.ringing = 0;
+ return 1;
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ if(signal_pending(current))
+ break;
+ }
+ jif = jiffies + (3 * hertz);
+ ixj_ring_off(board);
+ while (time_before(jiffies, jif)) {
+ if (ixj_hookstate(board) & 1) {
+ det = jiffies + (hertz / 100);
+ while (time_before(jiffies, det)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ if(signal_pending(current))
+ break;
+ }
+ if (ixj_hookstate(board) & 1) {
+ j->flags.ringing = 0;
+ return 1;
+ }
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ if(signal_pending(current))
+ break;
+ }
+ }
+ ixj_ring_off(board);
+ j->flags.ringing = 0;
+ return 0;
+}
+
+int ixj_open(struct phone_device *p, struct file *file_p)
+{
+ IXJ *j = &ixj[p->board];
+
+ if (!j->DSPbase)
+ return -ENODEV;
+
+ if (file_p->f_mode & FMODE_READ)
+ j->readers++;
+ if (file_p->f_mode & FMODE_WRITE)
+ j->writers++;
+
+ MOD_INC_USE_COUNT;
+
+ if (ixjdebug > 0)
+// printk(KERN_INFO "Opening board %d\n", NUM(inode->i_rdev));
+ printk(KERN_INFO "Opening board %d\n", p->board);
+
+ return 0;
+}
+
+int ixj_release(struct inode *inode, struct file *file_p)
+{
+ IXJ_TONE ti;
+ int board = NUM(inode->i_rdev);
+ IXJ *j = &ixj[board];
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Closing board %d\n", NUM(inode->i_rdev));
+
+ daa_set_mode(board, SOP_PU_SLEEP);
+ ixj_set_port(board, PORT_POTS);
+ aec_stop(board);
+ ixj_play_stop(board);
+ ixj_record_stop(board);
+
+ ti.tone_index = 10;
+ ti.gain0 = 1;
+ ti.freq0 = hz941;
+ ti.gain1 = 0;
+ ti.freq1 = hz1209;
+ ti.tone_index = 11;
+ ti.gain0 = 1;
+ ti.freq0 = hz941;
+ ti.gain1 = 0;
+ ti.freq1 = hz1336;
+ ti.tone_index = 12;
+ ti.gain0 = 1;
+ ti.freq0 = hz941;
+ ti.gain1 = 0;
+ ti.freq1 = hz1477;
+ ti.tone_index = 13;
+ ti.gain0 = 1;
+ ti.freq0 = hz800;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 14;
+ ti.gain0 = 1;
+ ti.freq0 = hz1000;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 15;
+ ti.gain0 = 1;
+ ti.freq0 = hz1250;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 16;
+ ti.gain0 = 1;
+ ti.freq0 = hz950;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 17;
+ ti.gain0 = 1;
+ ti.freq0 = hz1100;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 18;
+ ti.gain0 = 1;
+ ti.freq0 = hz1400;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 19;
+ ti.gain0 = 1;
+ ti.freq0 = hz1500;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 20;
+ ti.gain0 = 1;
+ ti.freq0 = hz1600;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 21;
+ ti.gain0 = 1;
+ ti.freq0 = hz1800;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 22;
+ ti.gain0 = 1;
+ ti.freq0 = hz2100;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 23;
+ ti.gain0 = 1;
+ ti.freq0 = hz1300;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 24;
+ ti.gain0 = 1;
+ ti.freq0 = hz2450;
+ ti.gain1 = 0;
+ ti.freq1 = 0;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 25;
+ ti.gain0 = 1;
+ ti.freq0 = hz350;
+ ti.gain1 = 0;
+ ti.freq1 = hz440;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 26;
+ ti.gain0 = 1;
+ ti.freq0 = hz440;
+ ti.gain1 = 0;
+ ti.freq1 = hz480;
+ ixj_init_tone(board, &ti);
+ ti.tone_index = 27;
+ ti.gain0 = 1;
+ ti.freq0 = hz480;
+ ti.gain1 = 0;
+ ti.freq1 = hz620;
+ ixj_init_tone(board, &ti);
+
+ idle(board);
+
+ if (file_p->f_mode & FMODE_READ)
+ j->readers--;
+ if (file_p->f_mode & FMODE_WRITE)
+ j->writers--;
+
+ if (j->read_buffer && !j->readers) {
+ kfree(j->read_buffer);
+ j->read_buffer = NULL;
+ j->read_buffer_size = 0;
+ }
+ if (j->write_buffer && !j->writers) {
+ kfree(j->write_buffer);
+ j->write_buffer = NULL;
+ j->write_buffer_size = 0;
+ }
+ j->rec_codec = j->play_codec = 0;
+ j->rec_frame_size = j->play_frame_size = 0;
+ ixj_fasync(-1, file_p, 0); // remove from list of async notification
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int read_filters(int board)
+{
+ unsigned short fc, cnt;
+ IXJ *j = &ixj[board];
+
+ if (ixj_WriteDSPCommand(0x5144, board))
+ return -1;
+
+ fc = j->ssr.high << 8 | j->ssr.low;
+ if (fc == j->frame_count)
+ return 1;
+
+ j->frame_count = fc;
+
+ for (cnt = 0; cnt < 4; cnt++) {
+ if (ixj_WriteDSPCommand(0x5154 + cnt, board))
+ return -1;
+
+ if (ixj_WriteDSPCommand(0x515C, board))
+ return -1;
+
+ j->filter_hist[cnt] = j->ssr.high << 8 | j->ssr.low;
+ if ((j->filter_hist[cnt] & 1 && !(j->filter_hist[cnt] & 2)) ||
+ (j->filter_hist[cnt] & 2 && !(j->filter_hist[cnt] & 1))) {
+ switch (cnt) {
+ case 0:
+ j->ex.bits.f0 = 1;
+ break;
+ case 1:
+ j->ex.bits.f1 = 1;
+ break;
+ case 2:
+ j->ex.bits.f2 = 1;
+ break;
+ case 3:
+ j->ex.bits.f3 = 1;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int LineMonitor(int board)
+{
+ IXJ *j = &ixj[board];
+
+ if (j->dtmf_proc) {
+ return -1;
+ }
+ j->dtmf_proc = 1;
+
+ if (ixj_WriteDSPCommand(0x7000, board)) // Line Monitor
+
+ return -1;
+
+ j->dtmf.bytes.high = j->ssr.high;
+ j->dtmf.bytes.low = j->ssr.low;
+ if (!j->dtmf_state && j->dtmf.bits.dtmf_valid) {
+ j->dtmf_state = 1;
+ j->dtmf_current = j->dtmf.bits.digit;
+ }
+ if (j->dtmf_state && !j->dtmf.bits.dtmf_valid) // && j->dtmf_wp != j->dtmf_rp)
+ {
+ j->dtmfbuffer[j->dtmf_wp] = j->dtmf_current;
+ j->dtmf_wp++;
+ if (j->dtmf_wp == 79)
+ j->dtmf_wp = 0;
+ j->ex.bits.dtmf_ready = 1;
+ j->dtmf_state = 0;
+ }
+ j->dtmf_proc = 0;
+
+ return 0;
+}
+
+ssize_t ixj_read(struct file * file_p, char *buf, size_t length, loff_t * ppos)
+{
+ unsigned long i = *ppos;
+ IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&j->read_q, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ mb();
+
+ while (!j->read_buffer_ready || (j->dtmf_state && j->flags.dtmf_oob)) {
+ ++j->read_wait;
+ if (file_p->f_flags & O_NONBLOCK) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&j->read_q, &wait);
+ return -EAGAIN;
+ }
+ if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&j->read_q, &wait);
+ return 0;
+ }
+ interruptible_sleep_on(&j->read_q);
+ if (signal_pending(current)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&j->read_q, &wait);
+ return -EINTR;
+ }
+ }
+
+ remove_wait_queue(&j->read_q, &wait);
+ current->state = TASK_RUNNING;
+ /* Don't ever copy more than the user asks */
+ i = copy_to_user(buf, j->read_buffer, min(length, j->read_buffer_size));
+ j->read_buffer_ready = 0;
+ if (i)
+ return -EFAULT;
+ else
+ return min(length, j->read_buffer_size);
+}
+
+ssize_t ixj_enhanced_read(struct file * file_p, char *buf, size_t length,
+ loff_t * ppos)
+{
+ int pre_retval;
+ ssize_t read_retval = 0;
+ IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+ pre_retval = ixj_PreRead(j, 0L);
+ switch (pre_retval) {
+ case NORMAL:
+ read_retval = ixj_read(file_p, buf, length, ppos);
+ ixj_PostRead(j, 0L);
+ break;
+ case NOPOST:
+ read_retval = ixj_read(file_p, buf, length, ppos);
+ break;
+ case POSTONLY:
+ ixj_PostRead(j, 0L);
+ break;
+ default:
+ read_retval = pre_retval;
+ }
+ return read_retval;
+}
+
+ssize_t ixj_write(struct file * file_p, const char *buf, size_t count, loff_t * ppos)
+{
+ unsigned long i = *ppos;
+ int board = NUM(file_p->f_dentry->d_inode->i_rdev);
+ IXJ *j = &ixj[board];
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&j->read_q, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ mb();
+
+
+ while (!j->write_buffers_empty) {
+ ++j->write_wait;
+ if (file_p->f_flags & O_NONBLOCK) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&j->read_q, &wait);
+ return -EAGAIN;
+ }
+ if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&j->read_q, &wait);
+ return 0;
+ }
+ interruptible_sleep_on(&j->write_q);
+ if (signal_pending(current)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&j->read_q, &wait);
+ return -EINTR;
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&j->read_q, &wait);
+ if (j->write_buffer_wp + count >= j->write_buffer_end)
+ j->write_buffer_wp = j->write_buffer;
+ i = copy_from_user(j->write_buffer_wp, buf, min(count, j->write_buffer_size));
+ if (i)
+ return -EFAULT;
+
+ return min(count, j->write_buffer_size);
+}
+
+ssize_t ixj_enhanced_write(struct file * file_p, const char *buf, size_t count,
+ loff_t * ppos)
+{
+ int pre_retval;
+ ssize_t write_retval = 0;
+ IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+ pre_retval = ixj_PreWrite(j, 0L);
+ switch (pre_retval) {
+ case NORMAL:
+ write_retval = ixj_write(file_p, buf, count, ppos);
+ if (write_retval != -EFAULT) {
+ ixj_PostWrite(j, 0L);
+ j->write_buffer_wp += count;
+ j->write_buffers_empty--;
+ }
+ break;
+ case NOPOST:
+ write_retval = ixj_write(file_p, buf, count, ppos);
+ if (write_retval != -EFAULT) {
+ j->write_buffer_wp += count;
+ j->write_buffers_empty--;
+ }
+ break;
+ case POSTONLY:
+ ixj_PostWrite(j, 0L);
+ break;
+ default:
+ write_retval = pre_retval;
+ }
+ return write_retval;
+}
+
+static void ixj_read_frame(int board)
+{
+ int cnt, dly;
+ IXJ *j = &ixj[board];
+
+ if (j->read_buffer) {
+ for (cnt = 0; cnt < j->rec_frame_size * 2; cnt += 2) {
+ if (!(cnt % 16) && !IsRxReady(board)) {
+ dly = 0;
+ while (!IsRxReady(board)) {
+ if (dly++ > 5) {
+ dly = 0;
+ break;
+ }
+ udelay(10);
+ }
+ }
+ // Throw away word 0 of the 8021 compressed format to get standard G.729.
+ if (j->rec_codec == G729 && (cnt == 0 || cnt == 5 || cnt == 10)) {
+ inb_p(j->DSPbase + 0x0E);
+ inb_p(j->DSPbase + 0x0F);
+ }
+ *(j->read_buffer + cnt) = inb_p(j->DSPbase + 0x0E);
+ *(j->read_buffer + cnt + 1) = inb_p(j->DSPbase + 0x0F);
+ }
+#ifdef PERFMON_STATS
+ ++j->framesread;
+#endif
+ if (j->intercom != -1) {
+ if (IsTxReady(j->intercom)) {
+ for (cnt = 0; cnt < j->rec_frame_size * 2; cnt += 2) {
+ if (!(cnt % 16) && !IsTxReady(board)) {
+ dly = 0;
+ while (!IsTxReady(board)) {
+ if (dly++ > 5) {
+ dly = 0;
+ break;
+ }
+ udelay(10);
+ }
+ }
+ outb_p(*(j->read_buffer + cnt), ixj[j->intercom].DSPbase + 0x0C);
+ outb_p(*(j->read_buffer + cnt + 1), ixj[j->intercom].DSPbase + 0x0D);
+ }
+#ifdef PERFMON_STATS
+ ++ixj[j->intercom].frameswritten;
+#endif
+ }
+ } else {
+ j->read_buffer_ready = 1;
+ wake_up_interruptible(&j->read_q); // Wake any blocked readers
+
+ wake_up_interruptible(&j->poll_q); // Wake any blocked selects
+
+ if (j->async_queue)
+ kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of frame
+
+ }
+ }
+}
+
+static void ixj_write_frame(int board)
+{
+ int cnt, frame_count, dly;
+ BYTES blankword;
+ IXJ *j = &ixj[board];
+
+ frame_count = 0;
+ if (j->write_buffer && j->write_buffers_empty < 2) {
+ if (j->write_buffer_wp > j->write_buffer_rp) {
+ frame_count =
+ (j->write_buffer_wp - j->write_buffer_rp) / (j->play_frame_size * 2);
+ }
+ if (j->write_buffer_rp > j->write_buffer_wp) {
+ frame_count =
+ (j->write_buffer_wp - j->write_buffer) / (j->play_frame_size * 2) +
+ (j->write_buffer_end - j->write_buffer_rp) / (j->play_frame_size * 2);
+ }
+ if (frame_count >= 1) {
+ if (j->ver.low == 0x12 && j->play_mode && j->flags.play_first_frame) {
+ switch (j->play_mode) {
+ case PLAYBACK_MODE_ULAW:
+ case PLAYBACK_MODE_ALAW:
+ blankword.low = blankword.high = 0xFF;
+ break;
+ case PLAYBACK_MODE_8LINEAR:
+ case PLAYBACK_MODE_16LINEAR:
+ blankword.low = blankword.high = 0x00;
+ break;
+ case PLAYBACK_MODE_8LINEAR_WSS:
+ blankword.low = blankword.high = 0x80;
+ break;
+ }
+ for (cnt = 0; cnt < 16; cnt++) {
+ if (!(cnt % 16) && !IsTxReady(board)) {
+ dly = 0;
+ while (!IsTxReady(board)) {
+ if (dly++ > 5) {
+ dly = 0;
+ break;
+ }
+ udelay(10);
+ }
+ }
+ outb_p((blankword.low), j->DSPbase + 0x0C);
+ outb_p((blankword.high), j->DSPbase + 0x0D);
+ }
+ j->flags.play_first_frame = 0;
+ }
+ for (cnt = 0; cnt < j->play_frame_size * 2; cnt += 2) {
+ if (!(cnt % 16) && !IsTxReady(board)) {
+ dly = 0;
+ while (!IsTxReady(board)) {
+ if (dly++ > 5) {
+ dly = 0;
+ break;
+ }
+ udelay(10);
+ }
+ }
+// Add word 0 to G.729 frames for the 8021. Right now we don't do VAD/CNG
+ // so all frames are type 1.
+ if (j->play_codec == G729 && (cnt == 0 || cnt == 5 || cnt == 10)) {
+ outb_p(0x01, j->DSPbase + 0x0C);
+ outb_p(0x00, j->DSPbase + 0x0D);
+ }
+ outb_p(*(j->write_buffer_rp + cnt), j->DSPbase + 0x0C);
+ outb_p(*(j->write_buffer_rp + cnt + 1), j->DSPbase + 0x0D);
+ *(j->write_buffer_rp + cnt) = 0;
+ *(j->write_buffer_rp + cnt + 1) = 0;
+ }
+ j->write_buffer_rp += j->play_frame_size * 2;
+ if (j->write_buffer_rp >= j->write_buffer_end) {
+ j->write_buffer_rp = j->write_buffer;
+ }
+ j->write_buffers_empty++;
+ wake_up_interruptible(&(j->write_q)); // Wake any blocked writers
+
+ wake_up_interruptible(&j->poll_q); // Wake any blocked selects
+
+ if (j->async_queue)
+ kill_fasync(j->async_queue, SIGIO, POLL_IN); // Send apps notice of empty buffer
+#ifdef PERFMON_STATS
+ ++j->frameswritten;
+#endif
+ }
+ } else {
+ j->drybuffer++;
+ }
+}
+
+static int idle(int board)
+{
+ IXJ *j = &ixj[board];
+
+ if (ixj_WriteDSPCommand(0x0000, board)) // DSP Idle
+
+ return 0;
+ if (j->ssr.high || j->ssr.low)
+ return 0;
+ else
+ return 1;
+}
+
+static int set_base_frame(int board, int size)
+{
+ unsigned short cmd;
+ int cnt;
+ IXJ *j = &ixj[board];
+
+ aec_stop(board);
+ for (cnt = 0; cnt < 10; cnt++) {
+ if (idle(board))
+ break;
+ }
+ if (j->ssr.high || j->ssr.low)
+ return -1;
+ if (j->dsp.low != 0x20) {
+ switch (size) {
+ case 30:
+ cmd = 0x07F0;
+ /* Set Base Frame Size to 240 pg9-10 8021 */
+ break;
+ case 20:
+ cmd = 0x07A0;
+ /* Set Base Frame Size to 160 pg9-10 8021 */
+ break;
+ case 10:
+ cmd = 0x0750;
+ /* Set Base Frame Size to 80 pg9-10 8021 */
+ break;
+ default:
+ return -1;
+ }
+ } else {
+ if (size == 30)
+ return size;
+ else
+ return -1;
+ }
+ if (ixj_WriteDSPCommand(cmd, board)) {
+ j->baseframe.high = j->baseframe.low = 0xFF;
+ return -1;
+ } else {
+ j->baseframe.high = j->ssr.high;
+ j->baseframe.low = j->ssr.low;
+ }
+ return size;
+}
+
+static int set_rec_codec(int board, int rate)
+{
+ int retval = 0;
+ IXJ *j = &ixj[board];
+
+ j->rec_codec = rate;
+
+ switch (rate) {
+ case G723_63:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->rec_frame_size = 12;
+ j->rec_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case G723_53:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->rec_frame_size = 10;
+ j->rec_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case TS85:
+ if (j->dsp.low == 0x20 || j->flags.ts85_loaded) {
+ j->rec_frame_size = 16;
+ j->rec_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case TS48:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->rec_frame_size = 9;
+ j->rec_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case TS41:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->rec_frame_size = 8;
+ j->rec_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case G728:
+ if (j->dsp.low != 0x20) {
+ j->rec_frame_size = 48;
+ j->rec_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case G729:
+ if (j->dsp.low != 0x20) {
+ if (!j->flags.g729_loaded) {
+ retval = 1;
+ break;
+ }
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->rec_frame_size = 10;
+ break;
+ case 0x50:
+ j->rec_frame_size = 5;
+ break;
+ default:
+ j->rec_frame_size = 15;
+ break;
+ }
+ j->rec_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case ULAW:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->rec_frame_size = 80;
+ break;
+ case 0x50:
+ j->rec_frame_size = 40;
+ break;
+ default:
+ j->rec_frame_size = 120;
+ break;
+ }
+ j->rec_mode = 4;
+ break;
+ case ALAW:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->rec_frame_size = 80;
+ break;
+ case 0x50:
+ j->rec_frame_size = 40;
+ break;
+ default:
+ j->rec_frame_size = 120;
+ break;
+ }
+ j->rec_mode = 4;
+ break;
+ case LINEAR16:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->rec_frame_size = 160;
+ break;
+ case 0x50:
+ j->rec_frame_size = 80;
+ break;
+ default:
+ j->rec_frame_size = 240;
+ break;
+ }
+ j->rec_mode = 5;
+ break;
+ case LINEAR8:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->rec_frame_size = 80;
+ break;
+ case 0x50:
+ j->rec_frame_size = 40;
+ break;
+ default:
+ j->rec_frame_size = 120;
+ break;
+ }
+ j->rec_mode = 6;
+ break;
+ case WSS:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->rec_frame_size = 80;
+ break;
+ case 0x50:
+ j->rec_frame_size = 40;
+ break;
+ default:
+ j->rec_frame_size = 120;
+ break;
+ }
+ j->rec_mode = 7;
+ break;
+ default:
+ j->rec_frame_size = 0;
+ j->rec_mode = -1;
+ if (j->read_buffer) {
+ kfree(j->read_buffer);
+ j->read_buffer = NULL;
+ j->read_buffer_size = 0;
+ }
+ retval = 1;
+ break;
+ }
+ return retval;
+}
+
+static int ixj_record_start(int board)
+{
+ unsigned short cmd = 0x0000;
+ IXJ *j = &ixj[board];
+
+ if (!j->rec_mode) {
+ switch (j->rec_codec) {
+ case G723_63:
+ cmd = 0x5131;
+ break;
+ case G723_53:
+ cmd = 0x5132;
+ break;
+ case TS85:
+ cmd = 0x5130; // TrueSpeech 8.5
+
+ break;
+ case TS48:
+ cmd = 0x5133; // TrueSpeech 4.8
+
+ break;
+ case TS41:
+ cmd = 0x5134; // TrueSpeech 4.1
+
+ break;
+ case G728:
+ cmd = 0x5135;
+ break;
+ case G729:
+ cmd = 0x5136;
+ break;
+ default:
+ return 1;
+ }
+ if (ixj_WriteDSPCommand(cmd, board))
+ return -1;
+ }
+ if (!j->read_buffer) {
+ if (!j->read_buffer)
+ j->read_buffer = kmalloc(j->rec_frame_size * 2, GFP_ATOMIC);
+ if (!j->read_buffer) {
+ printk("Read buffer allocation for ixj board %d failed!\n", board);
+ return -ENOMEM;
+ }
+ }
+ j->read_buffer_size = j->rec_frame_size * 2;
+
+ if (ixj_WriteDSPCommand(0x5102, board)) // Set Poll sync mode
+
+ return -1;
+
+ switch (j->rec_mode) {
+ case 0:
+ cmd = 0x1C03; // Record C1
+
+ break;
+ case 4:
+ if (j->ver.low == 0x12) {
+ cmd = 0x1E03; // Record C1
+
+ } else {
+ cmd = 0x1E01; // Record C1
+
+ }
+ break;
+ case 5:
+ if (j->ver.low == 0x12) {
+ cmd = 0x1E83; // Record C1
+
+ } else {
+ cmd = 0x1E81; // Record C1
+
+ }
+ break;
+ case 6:
+ if (j->ver.low == 0x12) {
+ cmd = 0x1F03; // Record C1
+
+ } else {
+ cmd = 0x1F01; // Record C1
+
+ }
+ break;
+ case 7:
+ if (j->ver.low == 0x12) {
+ cmd = 0x1F83; // Record C1
+
+ } else {
+ cmd = 0x1F81; // Record C1
+
+ }
+ break;
+ }
+ if (ixj_WriteDSPCommand(cmd, board))
+ return -1;
+
+ return 0;
+}
+
+static void ixj_record_stop(int board)
+{
+ IXJ *j = &ixj[board];
+
+ if (j->rec_mode > -1) {
+ ixj_WriteDSPCommand(0x5120, board);
+ j->rec_mode = -1;
+ }
+}
+
+static void set_rec_depth(int board, int depth)
+{
+ if (depth > 60)
+ depth = 60;
+ if (depth < 0)
+ depth = 0;
+ ixj_WriteDSPCommand(0x5180 + depth, board);
+}
+
+static void set_rec_volume(int board, int volume)
+{
+ ixj_WriteDSPCommand(0xCF03, board);
+ ixj_WriteDSPCommand(volume, board);
+}
+
+static int get_rec_level(int board)
+{
+ IXJ *j = &ixj[board];
+
+ ixj_WriteDSPCommand(0xCF88, board);
+
+ return j->ssr.high << 8 | j->ssr.low;
+}
+
+static void ixj_aec_start(int board, int level)
+{
+ IXJ *j = &ixj[board];
+
+ j->aec_level = level;
+ if (!level) {
+ ixj_WriteDSPCommand(0xB002, board);
+ } else {
+ if (j->rec_codec == G729 || j->play_codec == G729) {
+ ixj_WriteDSPCommand(0xE022, board); // Move AEC filter buffer
+
+ ixj_WriteDSPCommand(0x0300, board);
+ }
+ ixj_WriteDSPCommand(0xB001, board); // AEC On
+
+ ixj_WriteDSPCommand(0xE013, board); // Advanced AEC C1
+
+ switch (level) {
+ case 1:
+ ixj_WriteDSPCommand(0x0000, board); // Advanced AEC C2 = off
+
+ ixj_WriteDSPCommand(0xE011, board);
+ ixj_WriteDSPCommand(0xFFFF, board);
+ break;
+
+ case 2:
+ ixj_WriteDSPCommand(0x0600, board); // Advanced AEC C2 = on medium
+
+ ixj_WriteDSPCommand(0xE011, board);
+ ixj_WriteDSPCommand(0x0080, board);
+ break;
+
+ case 3:
+ ixj_WriteDSPCommand(0x0C00, board); // Advanced AEC C2 = on high
+
+ ixj_WriteDSPCommand(0xE011, board);
+ ixj_WriteDSPCommand(0x0080, board);
+ break;
+ }
+ }
+}
+
+static void aec_stop(int board)
+{
+ IXJ *j = &ixj[board];
+
+ if (j->rec_codec == G729 || j->play_codec == G729) {
+ ixj_WriteDSPCommand(0xE022, board); // Move AEC filter buffer back
+
+ ixj_WriteDSPCommand(0x0700, board);
+ }
+ if (ixj[board].play_mode != -1 && ixj[board].rec_mode != -1);
+ {
+ ixj_WriteDSPCommand(0xB002, board); // AEC Stop
+
+ }
+}
+
+static int set_play_codec(int board, int rate)
+{
+ int retval = 0;
+ IXJ *j = &ixj[board];
+
+ j->play_codec = rate;
+
+ switch (rate) {
+ case G723_63:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->play_frame_size = 12;
+ j->play_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case G723_53:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->play_frame_size = 10;
+ j->play_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case TS85:
+ if (j->dsp.low == 0x20 || j->flags.ts85_loaded) {
+ j->play_frame_size = 16;
+ j->play_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case TS48:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->play_frame_size = 9;
+ j->play_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case TS41:
+ if (j->ver.low != 0x12 || ixj_convert_loaded) {
+ j->play_frame_size = 8;
+ j->play_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case G728:
+ if (j->dsp.low != 0x20) {
+ j->play_frame_size = 48;
+ j->play_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case G729:
+ if (j->dsp.low != 0x20) {
+ if (!j->flags.g729_loaded) {
+ retval = 1;
+ break;
+ }
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->play_frame_size = 10;
+ break;
+ case 0x50:
+ j->play_frame_size = 5;
+ break;
+ default:
+ j->play_frame_size = 15;
+ break;
+ }
+ j->play_mode = 0;
+ } else {
+ retval = 1;
+ }
+ break;
+ case ULAW:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->play_frame_size = 80;
+ break;
+ case 0x50:
+ j->play_frame_size = 40;
+ break;
+ default:
+ j->play_frame_size = 120;
+ break;
+ }
+ j->play_mode = 2;
+ break;
+ case ALAW:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->play_frame_size = 80;
+ break;
+ case 0x50:
+ j->play_frame_size = 40;
+ break;
+ default:
+ j->play_frame_size = 120;
+ break;
+ }
+ j->play_mode = 2;
+ break;
+ case LINEAR16:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->play_frame_size = 160;
+ break;
+ case 0x50:
+ j->play_frame_size = 80;
+ break;
+ default:
+ j->play_frame_size = 240;
+ break;
+ }
+ j->play_mode = 6;
+ break;
+ case LINEAR8:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->play_frame_size = 80;
+ break;
+ case 0x50:
+ j->play_frame_size = 40;
+ break;
+ default:
+ j->play_frame_size = 120;
+ break;
+ }
+ j->play_mode = 4;
+ break;
+ case WSS:
+ switch (j->baseframe.low) {
+ case 0xA0:
+ j->play_frame_size = 80;
+ break;
+ case 0x50:
+ j->play_frame_size = 40;
+ break;
+ default:
+ j->play_frame_size = 120;
+ break;
+ }
+ j->play_mode = 5;
+ break;
+ default:
+ j->play_frame_size = 0;
+ j->play_mode = -1;
+ if (j->write_buffer) {
+ kfree(j->write_buffer);
+ j->write_buffer = NULL;
+ j->write_buffer_size = 0;
+ }
+ retval = 1;
+ break;
+ }
+ return retval;
+}
+
+static int ixj_play_start(int board)
+{
+ unsigned short cmd = 0x0000;
+ IXJ *j = &ixj[board];
+
+ j->flags.play_first_frame = 1;
+ j->drybuffer = 0;
+
+ if (!j->play_mode) {
+ switch (j->play_codec) {
+ case G723_63:
+ cmd = 0x5231;
+ break;
+ case G723_53:
+ cmd = 0x5232;
+ break;
+ case TS85:
+ cmd = 0x5230; // TrueSpeech 8.5
+
+ break;
+ case TS48:
+ cmd = 0x5233; // TrueSpeech 4.8
+
+ break;
+ case TS41:
+ cmd = 0x5234; // TrueSpeech 4.1
+
+ break;
+ case G728:
+ cmd = 0x5235;
+ break;
+ case G729:
+ cmd = 0x5236;
+ break;
+ default:
+ return 1;
+ }
+ if (ixj_WriteDSPCommand(cmd, board))
+ return -1;
+ }
+ if (!j->write_buffer) {
+ j->write_buffer = kmalloc(j->play_frame_size * 2, GFP_ATOMIC);
+ if (!j->write_buffer) {
+ printk("Write buffer allocation for ixj board %d failed!\n", board);
+ return -ENOMEM;
+ }
+ }
+ j->write_buffers_empty = 2;
+ j->write_buffer_size = j->play_frame_size * 2;
+ j->write_buffer_end = j->write_buffer + j->play_frame_size * 2;
+ j->write_buffer_rp = j->write_buffer_wp = j->write_buffer;
+
+ if (ixj_WriteDSPCommand(0x5202, board)) // Set Poll sync mode
+
+ return -1;
+
+ switch (j->play_mode) {
+ case 0:
+ cmd = 0x2C03;
+ break;
+ case 2:
+ if (j->ver.low == 0x12) {
+ cmd = 0x2C23;
+ } else {
+ cmd = 0x2C21;
+ }
+ break;
+ case 4:
+ if (j->ver.low == 0x12) {
+ cmd = 0x2C43;
+ } else {
+ cmd = 0x2C41;
+ }
+ break;
+ case 5:
+ if (j->ver.low == 0x12) {
+ cmd = 0x2C53;
+ } else {
+ cmd = 0x2C51;
+ }
+ break;
+ case 6:
+ if (j->ver.low == 0x12) {
+ cmd = 0x2C63;
+ } else {
+ cmd = 0x2C61;
+ }
+ break;
+ }
+ if (ixj_WriteDSPCommand(cmd, board))
+ return -1;
+
+ if (ixj_WriteDSPCommand(0x2000, board)) // Playback C2
+
+ return -1;
+
+ if (ixj_WriteDSPCommand(0x2000 + ixj[board].play_frame_size, board)) // Playback C3
+
+ return -1;
+
+ return 0;
+}
+
+static void ixj_play_stop(int board)
+{
+ IXJ *j = &ixj[board];
+
+ if (j->play_mode > -1) {
+ ixj_WriteDSPCommand(0x5221, board); // Stop playback
+
+ j->play_mode = -1;
+ }
+}
+
+extern __inline__ void set_play_depth(int board, int depth)
+{
+ if (depth > 60)
+ depth = 60;
+ if (depth < 0)
+ depth = 0;
+ ixj_WriteDSPCommand(0x5280 + depth, board);
+}
+
+extern __inline__ void set_play_volume(int board, int volume)
+{
+ ixj_WriteDSPCommand(0xCF02, board);
+ ixj_WriteDSPCommand(volume, board);
+}
+
+extern __inline__ int get_play_level(int board)
+{
+ ixj_WriteDSPCommand(0xCF8F, board);
+ return ixj[board].ssr.high << 8 | ixj[board].ssr.low;
+}
+
+static unsigned int ixj_poll(struct file *file_p, poll_table * wait)
+{
+ unsigned int mask = 0;
+ IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+
+ poll_wait(file_p, &(j->poll_q), wait);
+ if (j->read_buffer_ready > 0)
+ mask |= POLLIN | POLLRDNORM; /* readable */
+ if (j->write_buffers_empty > 0)
+ mask |= POLLOUT | POLLWRNORM; /* writable */
+ if (j->ex.bytes)
+ mask |= POLLPRI;
+ return mask;
+}
+
+static int ixj_play_tone(int board, char tone)
+{
+ IXJ *j = &ixj[board];
+
+ if (!j->tone_state)
+ idle(board);
+
+ j->tone_index = tone;
+ if (ixj_WriteDSPCommand(0x6000 + j->tone_index, board))
+ return -1;
+
+ if (!j->tone_state) {
+ j->tone_start_jif = jiffies;
+
+ j->tone_state = 1;
+ }
+ return 0;
+}
+
+static int ixj_set_tone_on(unsigned short arg, int board)
+{
+ IXJ *j = &ixj[board];
+
+ j->tone_on_time = arg;
+
+ if (ixj_WriteDSPCommand(0x6E04, board)) // Set Tone On Period
+
+ return -1;
+
+ if (ixj_WriteDSPCommand(arg, board))
+ return -1;
+
+ return 0;
+}
+
+static int SCI_WaitHighSCI(int board)
+{
+ int cnt;
+ IXJ *j = &ixj[board];
+
+ j->pld_scrr.byte = inb_p(j->XILINXbase);
+ if (!j->pld_scrr.bits.sci) {
+ for (cnt = 0; cnt < 10; cnt++) {
+ udelay(32);
+ j->pld_scrr.byte = inb_p(j->XILINXbase);
+
+ if ((j->pld_scrr.bits.sci))
+ return 1;
+ }
+ if (ixjdebug > 1)
+ printk(KERN_INFO "SCI Wait High failed %x\n", j->pld_scrr.byte);
+ return 0;
+ } else
+ return 1;
+}
+
+static int SCI_WaitLowSCI(int board)
+{
+ int cnt;
+ IXJ *j = &ixj[board];
+
+ j->pld_scrr.byte = inb_p(j->XILINXbase);
+ if (j->pld_scrr.bits.sci) {
+ for (cnt = 0; cnt < 10; cnt++) {
+ udelay(32);
+ j->pld_scrr.byte = inb_p(j->XILINXbase);
+
+ if (!(j->pld_scrr.bits.sci))
+ return 1;
+ }
+ if (ixjdebug > 1)
+ printk(KERN_INFO "SCI Wait Low failed %x\n", j->pld_scrr.byte);
+ return 0;
+ } else
+ return 1;
+}
+
+static int SCI_Control(int board, int control)
+{
+ IXJ *j = &ixj[board];
+
+ switch (control) {
+ case SCI_End:
+ j->pld_scrw.bits.c0 = 0; // Set PLD Serial control interface
+
+ j->pld_scrw.bits.c1 = 0; // to no selection
+
+ break;
+ case SCI_Enable_DAA:
+ j->pld_scrw.bits.c0 = 1; // Set PLD Serial control interface
+
+ j->pld_scrw.bits.c1 = 0; // to write to DAA
+
+ break;
+ case SCI_Enable_Mixer:
+ j->pld_scrw.bits.c0 = 0; // Set PLD Serial control interface
+
+ j->pld_scrw.bits.c1 = 1; // to write to mixer
+
+ break;
+ case SCI_Enable_EEPROM:
+ j->pld_scrw.bits.c0 = 1; // Set PLD Serial control interface
+
+ j->pld_scrw.bits.c1 = 1; // to write to EEPROM
+
+ break;
+ default:
+ return 0;
+ break;
+ }
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+
+ switch (control) {
+ case SCI_End:
+ return 1;
+ break;
+ case SCI_Enable_DAA:
+ case SCI_Enable_Mixer:
+ case SCI_Enable_EEPROM:
+ if (!SCI_WaitHighSCI(board))
+ return 0;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ return 1;
+}
+
+static int SCI_Prepare(int board)
+{
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ return 1;
+}
+
+static int ixj_mixer(long val, int board)
+{
+ BYTES bytes;
+ IXJ *j = &ixj[board];
+
+ bytes.high = (val & 0xFF00) >> 8;
+ bytes.low = val & 0x00FF;
+
+ outb_p(bytes.high & 0x1F, j->XILINXbase + 0x03); // Load Mixer Address
+
+ outb_p(bytes.low, j->XILINXbase + 0x02); // Load Mixer Data
+
+ SCI_Control(board, SCI_Enable_Mixer);
+
+ SCI_Control(board, SCI_End);
+
+ return 0;
+}
+
+static int daa_load(BYTES * p_bytes, int board)
+{
+ IXJ *j = &ixj[board];
+
+ outb_p(p_bytes->high, j->XILINXbase + 0x03);
+ outb_p(p_bytes->low, j->XILINXbase + 0x02);
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+ else
+ return 1;
+}
+
+static int ixj_daa_cr4(int board, char reg)
+{
+ IXJ *j = &ixj[board];
+ BYTES bytes;
+
+ switch (j->daa_mode) {
+ case SOP_PU_SLEEP:
+ bytes.high = 0x14;
+ break;
+ case SOP_PU_RINGING:
+ bytes.high = 0x54;
+ break;
+ case SOP_PU_CONVERSATION:
+ bytes.high = 0x94;
+ break;
+ case SOP_PU_PULSEDIALING:
+ bytes.high = 0xD4;
+ break;
+ }
+
+ switch (j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGX) {
+ case 0:
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 0;
+ break;
+ case 1:
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 2;
+ break;
+ case 2:
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 1;
+ break;
+ case 3:
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 3;
+ break;
+ }
+
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg;
+
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ return 1;
+}
+
+static char daa_int_read(int board)
+{
+ BYTES bytes;
+ IXJ *j = &ixj[board];
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ bytes.high = 0x38;
+ bytes.low = 0x00;
+ outb_p(bytes.high, j->XILINXbase + 0x03);
+ outb_p(bytes.low, j->XILINXbase + 0x02);
+
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+
+ bytes.high = inb_p(j->XILINXbase + 0x03);
+ bytes.low = inb_p(j->XILINXbase + 0x02);
+ if (bytes.low != ALISDAA_ID_BYTE) {
+ if (ixjdebug > 0)
+ printk("Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+ return 0;
+ }
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+
+ bytes.high = inb_p(j->XILINXbase + 0x03);
+ bytes.low = inb_p(j->XILINXbase + 0x02);
+
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.reg = bytes.high;
+ return 1;
+}
+
+static int ixj_daa_cid_reset(int board)
+{
+ int i;
+ BYTES bytes;
+ IXJ *j = &ixj[board];
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ bytes.high = 0x58;
+ bytes.low = 0x00;
+ outb_p(bytes.high, j->XILINXbase + 0x03);
+ outb_p(bytes.low, j->XILINXbase + 0x02);
+
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+
+ if (!SCI_WaitHighSCI(board))
+ return 0;
+
+ for (i = 0; i < ALISDAA_CALLERID_SIZE - 1; i += 2) {
+ bytes.high = bytes.low = 0x00;
+ outb_p(bytes.high, j->XILINXbase + 0x03);
+
+ if (i < ALISDAA_CALLERID_SIZE - 1)
+ outb_p(bytes.low, j->XILINXbase + 0x02);
+
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+
+ if (!SCI_WaitHighSCI(board))
+ return 0;
+
+ }
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+
+ return 1;
+}
+
+static int ixj_daa_cid_read(int board)
+{
+ int i;
+ BYTES bytes;
+ char CID[ALISDAA_CALLERID_SIZE], mContinue;
+ char *pIn, *pOut;
+ IXJ *j = &ixj[board];
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ bytes.high = 0x78;
+ bytes.low = 0x00;
+ outb_p(bytes.high, j->XILINXbase + 0x03);
+ outb_p(bytes.low, j->XILINXbase + 0x02);
+
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+
+ if (!SCI_WaitHighSCI(board))
+ return 0;
+
+ bytes.high = inb_p(j->XILINXbase + 0x03);
+ bytes.low = inb_p(j->XILINXbase + 0x02);
+ if (bytes.low != ALISDAA_ID_BYTE) {
+ if (ixjdebug > 0)
+ printk("DAA Get Version Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+ return 0;
+ }
+ for (i = 0; i < ALISDAA_CALLERID_SIZE; i += 2) {
+ bytes.high = bytes.low = 0x00;
+ outb_p(bytes.high, j->XILINXbase + 0x03);
+ outb_p(bytes.low, j->XILINXbase + 0x02);
+
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+
+ if (!SCI_WaitHighSCI(board))
+ return 0;
+
+ CID[i + 0] = inb_p(j->XILINXbase + 0x03);
+ CID[i + 1] = inb_p(j->XILINXbase + 0x02);
+ }
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+
+ pIn = CID;
+ pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID;
+ mContinue = 1;
+ while (mContinue) {
+ if ((pIn[1] & 0x03) == 0x01) {
+ pOut[0] = pIn[0];
+ }
+ if ((pIn[2] & 0x0c) == 0x04) {
+ pOut[1] = ((pIn[2] & 0x03) << 6) | ((pIn[1] & 0xfc) >> 2);
+ }
+ if ((pIn[3] & 0x30) == 0x10) {
+ pOut[2] = ((pIn[3] & 0x0f) << 4) | ((pIn[2] & 0xf0) >> 4);
+ }
+ if ((pIn[4] & 0xc0) == 0x40) {
+ pOut[3] = ((pIn[4] & 0x3f) << 2) | ((pIn[3] & 0xc0) >> 6);
+ } else {
+ mContinue = FALSE;
+ }
+ pIn += 5, pOut += 4;
+ }
+ memset(&j->cid, 0, sizeof(IXJ_CID));
+ pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID;
+ pOut += 4;
+ strncpy(j->cid.month, pOut, 2);
+ pOut += 2;
+ strncpy(j->cid.day, pOut, 2);
+ pOut += 2;
+ strncpy(j->cid.hour, pOut, 2);
+ pOut += 2;
+ strncpy(j->cid.min, pOut, 2);
+ pOut += 3;
+ j->cid.numlen = *pOut;
+ pOut += 1;
+ strncpy(j->cid.number, pOut, j->cid.numlen);
+ pOut += j->cid.numlen + 1;
+ j->cid.namelen = *pOut;
+ pOut += 1;
+ strncpy(j->cid.name, pOut, j->cid.namelen);
+
+ ixj_daa_cid_reset(board);
+ return 1;
+}
+
+static char daa_get_version(int board)
+{
+ BYTES bytes;
+ IXJ *j = &ixj[board];
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ bytes.high = 0x35;
+ bytes.low = 0x00;
+ outb_p(bytes.high, j->XILINXbase + 0x03);
+ outb_p(bytes.low, j->XILINXbase + 0x02);
+
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+
+ bytes.high = inb_p(j->XILINXbase + 0x03);
+ bytes.low = inb_p(j->XILINXbase + 0x02);
+ if (bytes.low != ALISDAA_ID_BYTE) {
+ if (ixjdebug > 0)
+ printk("DAA Get Version Cannot read DAA ID Byte high = %d low = %d\n", bytes.high, bytes.low);
+ return 0;
+ }
+ if (!SCI_Control(board, SCI_Enable_DAA))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+
+ bytes.high = inb_p(j->XILINXbase + 0x03);
+ bytes.low = inb_p(j->XILINXbase + 0x02);
+ if (ixjdebug > 0)
+ printk("DAA CR5 Byte high = 0x%x low = 0x%x\n", bytes.high, bytes.low);
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr5.reg = bytes.high;
+ return bytes.high;
+}
+
+static int daa_set_mode(int board, int mode)
+{
+ // NOTE:
+ // The DAA *MUST* be in the conversation mode if the
+ // PSTN line is to be seized (PSTN line off-hook).
+ // Taking the PSTN line off-hook while the DAA is in
+ // a mode other than conversation mode will cause a
+ // hardware failure of the ALIS-A part.
+
+ // NOTE:
+ // The DAA can only go to SLEEP, RINGING or PULSEDIALING modes
+ // if the PSTN line is on-hook. Failure to have the PSTN line
+ // in the on-hook state WILL CAUSE A HARDWARE FAILURE OF THE
+ // ALIS-A part.
+ //
+
+
+ BYTES bytes;
+ IXJ *j = &ixj[board];
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ switch (mode) {
+ case SOP_PU_SLEEP:
+ j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ j->pld_slicw.bits.rly2 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ bytes.high = 0x10;
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+ daa_load(&bytes, board);
+ if (!SCI_Prepare(board))
+ return 0;
+ j->daa_mode = SOP_PU_SLEEP;
+ j->flags.pstn_ringing = 0;
+ j->pstn_sleeptil = jiffies + (hertz * 3);
+ break;
+ case SOP_PU_RINGING:
+ j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ j->pld_slicw.bits.rly2 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ bytes.high = 0x50;
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+ daa_load(&bytes, board);
+ if (!SCI_Prepare(board))
+ return 0;
+ j->daa_mode = SOP_PU_RINGING;
+ break;
+ case SOP_PU_CONVERSATION:
+ bytes.high = 0x90;
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+ daa_load(&bytes, board);
+ if (!SCI_Prepare(board))
+ return 0;
+ j->pld_slicw.bits.rly2 = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ j->pld_scrw.bits.daafsyncen = 1; // Turn on DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ j->daa_mode = SOP_PU_CONVERSATION;
+ j->flags.pstn_ringing = 0;
+ j->ex.bits.pstn_ring = 0;
+ break;
+ case SOP_PU_PULSEDIALING:
+ j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ j->pld_slicw.bits.rly2 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ bytes.high = 0xD0;
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+ daa_load(&bytes, board);
+ if (!SCI_Prepare(board))
+ return 0;
+ j->daa_mode = SOP_PU_PULSEDIALING;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+static int ixj_daa_write(int board)
+{
+ BYTES bytes;
+ IXJ *j = &ixj[board];
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ bytes.high = 0x14;
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg;
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg;
+ bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ bytes.high = 0x1F;
+ bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.XOP_xr6_W.reg;
+ bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg;
+ bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg;
+ bytes.low = j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.XOP_xr0_W.reg;
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Prepare(board))
+ return 0;
+
+ bytes.high = 0x00;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x01;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x02;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x03;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x04;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x05;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x06;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x07;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x08;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x09;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x0A;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x0B;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x0C;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x0D;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x0E;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+ if (!SCI_WaitLowSCI(board))
+ return 0;
+
+ bytes.high = 0x0F;
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2];
+ bytes.low = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1];
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ bytes.high = j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0];
+ bytes.low = 0x00;
+ if (!daa_load(&bytes, board))
+ return 0;
+
+ udelay(32);
+ j->pld_scrr.byte = inb_p(j->XILINXbase);
+ if (!SCI_Control(board, SCI_End))
+ return 0;
+
+ return 1;
+}
+
+int ixj_set_tone_off(unsigned short arg, int board)
+{
+ ixj[board].tone_off_time = arg;
+
+ if (ixj_WriteDSPCommand(0x6E05, board)) // Set Tone Off Period
+
+ return -1;
+
+ if (ixj_WriteDSPCommand(arg, board))
+ return -1;
+
+ return 0;
+}
+
+static int ixj_get_tone_on(int board)
+{
+ if (ixj_WriteDSPCommand(0x6E06, board)) // Get Tone On Period
+
+ return -1;
+
+ return 0;
+}
+
+static int ixj_get_tone_off(int board)
+{
+ if (ixj_WriteDSPCommand(0x6E07, board)) // Get Tone Off Period
+
+ return -1;
+
+ return 0;
+}
+
+static void ixj_busytone(int board)
+{
+ ixj[board].flags.ringback = 0;
+ ixj[board].flags.dialtone = 0;
+ ixj[board].flags.busytone = 1;
+
+ ixj_set_tone_on(0x07D0, board);
+ ixj_set_tone_off(0x07D0, board);
+ ixj_play_tone(board, 27);
+}
+
+static void ixj_dialtone(int board)
+{
+ ixj[board].flags.ringback = 0;
+ ixj[board].flags.dialtone = 1;
+ ixj[board].flags.busytone = 0;
+
+ if (ixj[board].dsp.low == 0x20) {
+ return;
+ } else {
+ ixj_set_tone_on(0xFFFF, board);
+ ixj_set_tone_off(0x0000, board);
+
+ ixj_play_tone(board, 25);
+ }
+}
+
+static void ixj_cpt_stop(board)
+{
+ IXJ *j = &ixj[board];
+
+ j->flags.dialtone = 0;
+ j->flags.busytone = 0;
+ j->flags.ringback = 0;
+
+ ixj_set_tone_on(0x0001, board);
+ ixj_set_tone_off(0x0000, board);
+
+ ixj_play_tone(board, 0);
+
+ j->tone_state = 0;
+
+ ixj_del_timer();
+ if (j->cadence_t) {
+ if (j->cadence_t->ce) {
+ kfree(j->cadence_t->ce);
+ }
+ kfree(j->cadence_t);
+ j->cadence_t = NULL;
+ }
+ ixj_add_timer();
+ if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1))
+ idle(board);
+ if (j->play_mode != -1)
+ ixj_play_start(board);
+ if (j->rec_mode != -1)
+ ixj_record_start(board);
+}
+
+static void ixj_ringback(int board)
+{
+ ixj[board].flags.busytone = 0;
+ ixj[board].flags.dialtone = 0;
+ ixj[board].flags.ringback = 1;
+
+ ixj_set_tone_on(0x0FA0, board);
+ ixj_set_tone_off(0x2EE0, board);
+ ixj_play_tone(board, 26);
+}
+
+static void ixj_testram(int board)
+{
+ ixj_WriteDSPCommand(0x3001, board); /* Test External SRAM */
+}
+
+static int ixj_build_cadence(int board, IXJ_CADENCE * cp)
+{
+ IXJ_CADENCE *lcp;
+ IXJ_CADENCE_ELEMENT *lcep;
+ IXJ_TONE ti;
+ IXJ *j = &ixj[board];
+
+ lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL);
+ if (lcp == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)))
+ return -EFAULT;
+
+ lcep = kmalloc(sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used, GFP_KERNEL);
+ if (lcep == NULL) {
+ kfree(lcp);
+ return -ENOMEM;
+ }
+ if (copy_from_user(lcep, lcp->ce, sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used))
+ return -EFAULT;
+
+ if(j->cadence_t)
+ {
+ kfree(j->cadence_t->ce);
+ kfree(j->cadence_t);
+ }
+
+ lcp->ce = (void *) lcep;
+ j->cadence_t = lcp;
+ j->tone_cadence_state = 0;
+ ixj_set_tone_on(lcp->ce[0].tone_on_time, board);
+ ixj_set_tone_off(lcp->ce[0].tone_off_time, board);
+ if (j->cadence_t->ce[j->tone_cadence_state].freq0) {
+ ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index;
+ ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0;
+ ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0;
+ ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1;
+ ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1;
+ ixj_init_tone(board, &ti);
+ }
+ ixj_play_tone(board, lcp->ce[0].index);
+
+ return 1;
+}
+
+static void add_caps(int board)
+{
+ IXJ *j = &ixj[board];
+ j->caps = 0;
+
+ j->caplist[j->caps].cap = vendor;
+ strcpy(j->caplist[j->caps].desc, "Quicknet Technologies, Inc. (www.quicknet.net)");
+ j->caplist[j->caps].captype = vendor;
+ j->caplist[j->caps].handle = j->caps++;
+ j->caplist[j->caps].captype = device;
+ switch (j->cardtype) {
+ case 100:
+ strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK");
+ j->caplist[j->caps].cap = 100;
+ break;
+ case 300:
+ strcpy(j->caplist[j->caps].desc, "Quicknet Internet LineJACK");
+ j->caplist[j->caps].cap = 300;
+ break;
+ case 400:
+ strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK Lite");
+ j->caplist[j->caps].cap = 400;
+ break;
+ case 500:
+ strcpy(j->caplist[j->caps].desc, "Quicknet Internet PhoneJACK PCI");
+ j->caplist[j->caps].cap = 500;
+ break;
+ }
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "POTS");
+ j->caplist[j->caps].captype = port;
+ j->caplist[j->caps].cap = pots;
+ j->caplist[j->caps].handle = j->caps++;
+ switch (ixj[board].cardtype) {
+ case 100:
+ strcpy(j->caplist[j->caps].desc, "SPEAKER");
+ j->caplist[j->caps].captype = port;
+ j->caplist[j->caps].cap = speaker;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "HANDSET");
+ j->caplist[j->caps].captype = port;
+ j->caplist[j->caps].cap = handset;
+ j->caplist[j->caps].handle = j->caps++;
+ break;
+ case 300:
+ strcpy(j->caplist[j->caps].desc, "SPEAKER");
+ j->caplist[j->caps].captype = port;
+ j->caplist[j->caps].cap = speaker;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "PSTN");
+ j->caplist[j->caps].captype = port;
+ j->caplist[j->caps].cap = pstn;
+ j->caplist[j->caps].handle = j->caps++;
+ break;
+ }
+ strcpy(j->caplist[j->caps].desc, "ULAW");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = ULAW;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "LINEAR 16 bit");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = LINEAR16;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "LINEAR 8 bit");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = LINEAR8;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "Windows Sound System");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = WSS;
+ j->caplist[j->caps].handle = j->caps++;
+ if (j->ver.low != 0x12) {
+ strcpy(j->caplist[j->caps].desc, "G.723.1 6.3Kbps");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = G723_63;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "G.723.1 5.3Kbps");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = G723_53;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.8Kbps");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = TS48;
+ j->caplist[j->caps].handle = j->caps++;
+ strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.1Kbps");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = TS41;
+ j->caplist[j->caps].handle = j->caps++;
+ }
+ if (j->cardtype == 100) {
+ strcpy(j->caplist[j->caps].desc, "TrueSpeech 8.5Kbps");
+ j->caplist[j->caps].captype = codec;
+ j->caplist[j->caps].cap = TS85;
+ j->caplist[j->caps].handle = j->caps++;
+ }
+}
+static int capabilities_check(int board, struct phone_capability *pcreq)
+{
+ int cnt;
+ IXJ *j = &ixj[board];
+ int retval = 0;
+
+ for (cnt = 0; cnt < j->caps; cnt++) {
+ if (pcreq->captype == j->caplist[cnt].captype &&
+ pcreq->cap == j->caplist[cnt].cap) {
+ retval = 1;
+ break;
+ }
+ }
+ return retval;
+}
+
+int ixj_ioctl(struct inode *inode, struct file *file_p,
+ unsigned int cmd, unsigned long arg)
+{
+ IXJ_TONE ti;
+ IXJ_FILTER jf;
+ unsigned int minor = MINOR(inode->i_rdev);
+ int board = NUM(inode->i_rdev);
+ IXJ *j = &ixj[NUM(inode->i_rdev)];
+ int retval = 0;
+
+ if (ixjdebug > 1)
+ printk(KERN_DEBUG "phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
+ if (minor >= IXJMAX)
+ return -ENODEV;
+
+ /*
+ * Check ioctls only root can use.
+ */
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ switch (cmd) {
+ case IXJCTL_TESTRAM:
+ case IXJCTL_HZ:
+ return -EPERM;
+ }
+ }
+ switch (cmd) {
+ case IXJCTL_TESTRAM:
+ ixj_testram(board);
+ retval = (j->ssr.high << 8) + j->ssr.low;
+ break;
+ case IXJCTL_CARDTYPE:
+ retval = j->cardtype;
+ break;
+ case IXJCTL_SERIAL:
+ retval = j->serial;
+ break;
+ case PHONE_RING_CADENCE:
+ j->ring_cadence = arg;
+ break;
+ case PHONE_RING_START:
+ ixj_ring_start(board);
+ break;
+ case PHONE_RING_STOP:
+ j->flags.cringing = 0;
+ ixj_ring_off(board);
+ break;
+ case PHONE_RING:
+ retval = ixj_ring(board);
+ break;
+ case PHONE_EXCEPTION:
+ retval = j->ex.bytes;
+ j->ex.bytes &= 0x03;
+ break;
+ case PHONE_HOOKSTATE:
+ j->ex.bits.hookstate = 0;
+ retval = j->r_hook;
+ break;
+ case IXJCTL_SET_LED:
+ LED_SetState(arg, board);
+ break;
+ case PHONE_FRAME:
+ retval = set_base_frame(board, arg);
+ break;
+ case PHONE_REC_CODEC:
+ retval = set_rec_codec(board, arg);
+ break;
+ case PHONE_REC_START:
+ ixj_record_start(board);
+ break;
+ case PHONE_REC_STOP:
+ ixj_record_stop(board);
+ break;
+ case PHONE_REC_DEPTH:
+ set_rec_depth(board, arg);
+ break;
+ case PHONE_REC_VOLUME:
+ set_rec_volume(board, arg);
+ break;
+ case PHONE_REC_LEVEL:
+ retval = get_rec_level(board);
+ break;
+ case IXJCTL_AEC_START:
+ ixj_aec_start(board, arg);
+ break;
+ case IXJCTL_AEC_STOP:
+ aec_stop(board);
+ break;
+ case IXJCTL_AEC_GET_LEVEL:
+ retval = j->aec_level;
+ break;
+ case PHONE_PLAY_CODEC:
+ retval = set_play_codec(board, arg);
+ break;
+ case PHONE_PLAY_START:
+ ixj_play_start(board);
+ break;
+ case PHONE_PLAY_STOP:
+ ixj_play_stop(board);
+ break;
+ case PHONE_PLAY_DEPTH:
+ set_play_depth(board, arg);
+ break;
+ case PHONE_PLAY_VOLUME:
+ set_play_volume(board, arg);
+ break;
+ case PHONE_PLAY_LEVEL:
+ retval = get_play_level(board);
+ break;
+ case IXJCTL_DSP_TYPE:
+ retval = (j->dsp.high << 8) + j->dsp.low;
+ break;
+ case IXJCTL_DSP_VERSION:
+ retval = (j->ver.high << 8) + j->ver.low;
+ break;
+ case IXJCTL_HZ:
+ hertz = arg;
+ break;
+ case IXJCTL_RATE:
+ if (arg > hertz)
+ retval = -1;
+ else
+ samplerate = arg;
+ break;
+ case IXJCTL_DRYBUFFER_READ:
+ put_user(j->drybuffer, (unsigned long *) arg);
+ break;
+ case IXJCTL_DRYBUFFER_CLEAR:
+ j->drybuffer = 0;
+ break;
+ case IXJCTL_FRAMES_READ:
+ put_user(j->framesread, (unsigned long *) arg);
+ break;
+ case IXJCTL_FRAMES_WRITTEN:
+ put_user(j->frameswritten, (unsigned long *) arg);
+ break;
+ case IXJCTL_READ_WAIT:
+ put_user(j->read_wait, (unsigned long *) arg);
+ break;
+ case IXJCTL_WRITE_WAIT:
+ put_user(j->write_wait, (unsigned long *) arg);
+ break;
+ case PHONE_MAXRINGS:
+ j->maxrings = arg;
+ break;
+ case PHONE_SET_TONE_ON_TIME:
+ ixj_set_tone_on(arg, board);
+ break;
+ case PHONE_SET_TONE_OFF_TIME:
+ ixj_set_tone_off(arg, board);
+ break;
+ case PHONE_GET_TONE_ON_TIME:
+ if (ixj_get_tone_on(board)) {
+ retval = -1;
+ } else {
+ retval = (j->ssr.high << 8) + j->ssr.low;
+ }
+ break;
+ case PHONE_GET_TONE_OFF_TIME:
+ if (ixj_get_tone_off(board)) {
+ retval = -1;
+ } else {
+ retval = (j->ssr.high << 8) + j->ssr.low;
+ }
+ break;
+ case PHONE_PLAY_TONE:
+ if (!j->tone_state)
+ ixj_play_tone(board, arg);
+ break;
+ case PHONE_GET_TONE_STATE:
+ retval = j->tone_state;
+ break;
+ case PHONE_DTMF_READY:
+ retval = j->ex.bits.dtmf_ready;
+ break;
+ case PHONE_GET_DTMF:
+ if (ixj_hookstate(board)) {
+ if (j->dtmf_rp != j->dtmf_wp) {
+ retval = j->dtmfbuffer[j->dtmf_rp];
+ j->dtmf_rp++;
+ if (j->dtmf_rp == 79)
+ j->dtmf_rp = 0;
+ if (j->dtmf_rp == j->dtmf_wp) {
+ j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
+ }
+ }
+ }
+ break;
+ case PHONE_GET_DTMF_ASCII:
+ if (ixj_hookstate(board)) {
+ if (j->dtmf_rp != j->dtmf_wp) {
+ switch (j->dtmfbuffer[j->dtmf_rp]) {
+ case 10:
+ retval = 42; //'*';
+
+ break;
+ case 11:
+ retval = 48; //'0';
+
+ break;
+ case 12:
+ retval = 35; //'#';
+
+ break;
+ case 28:
+ retval = 65; //'A';
+
+ break;
+ case 29:
+ retval = 66; //'B';
+
+ break;
+ case 30:
+ retval = 67; //'C';
+
+ break;
+ case 31:
+ retval = 68; //'D';
+
+ break;
+ default:
+ retval = 48 + j->dtmfbuffer[j->dtmf_rp];
+ break;
+ }
+ j->dtmf_rp++;
+ if (j->dtmf_rp == 79)
+ j->dtmf_rp = 0;
+// if(j->dtmf_rp == j->dtmf_wp)
+ {
+ j->ex.bits.dtmf_ready = j->dtmf_rp = j->dtmf_wp = 0;
+ }
+ }
+ }
+ break;
+ case PHONE_DTMF_OOB:
+ j->flags.dtmf_oob = arg;
+ break;
+ case PHONE_DIALTONE:
+ ixj_dialtone(board);
+ break;
+ case PHONE_BUSY:
+ ixj_busytone(board);
+ break;
+ case PHONE_RINGBACK:
+ ixj_ringback(board);
+ break;
+ case PHONE_CPT_STOP:
+ ixj_cpt_stop(board);
+ break;
+ case IXJCTL_DSP_IDLE:
+ idle(board);
+ break;
+ case IXJCTL_MIXER:
+ ixj_mixer(arg, board);
+ break;
+ case IXJCTL_DAA_COEFF_SET:
+ switch (arg) {
+ case DAA_US:
+ DAA_Coeff_US(board);
+ ixj_daa_write(board);
+ break;
+ case DAA_UK:
+ DAA_Coeff_UK(board);
+ ixj_daa_write(board);
+ break;
+ case DAA_FRANCE:
+ DAA_Coeff_France(board);
+ ixj_daa_write(board);
+ break;
+ case DAA_GERMANY:
+ DAA_Coeff_Germany(board);
+ ixj_daa_write(board);
+ break;
+ case DAA_AUSTRALIA:
+ DAA_Coeff_Australia(board);
+ ixj_daa_write(board);
+ break;
+ case DAA_JAPAN:
+ DAA_Coeff_Japan(board);
+ ixj_daa_write(board);
+ break;
+ default:
+ break;
+ }
+ break;
+ case IXJCTL_DAA_AGAIN:
+ ixj_daa_cr4(board, arg | 0x02);
+ break;
+ case IXJCTL_PSTN_LINETEST:
+ retval = ixj_linetest(board);
+ break;
+ case IXJCTL_CID:
+ if (copy_to_user((char *) arg, &j->cid, sizeof(IXJ_CID)))
+ return -EFAULT;
+ j->ex.bits.caller_id = 0;
+ break;
+ case IXJCTL_WINK_DURATION:
+ j->winktime = arg;
+ break;
+ case IXJCTL_PORT:
+ if (arg)
+ retval = ixj_set_port(board, arg);
+ else
+ retval = j->port;
+ break;
+ case IXJCTL_POTS_PSTN:
+ retval = ixj_set_pots(board, arg);
+ break;
+ case PHONE_CAPABILITIES:
+ retval = j->caps;
+ break;
+ case PHONE_CAPABILITIES_LIST:
+ if (copy_to_user((char *) arg, j->caplist, sizeof(struct phone_capability) * j->caps))
+ return -EFAULT;
+ break;
+ case PHONE_CAPABILITIES_CHECK:
+ retval = capabilities_check(board, (struct phone_capability *) arg);
+ break;
+ case PHONE_PSTN_SET_STATE:
+ daa_set_mode(board, arg);
+ break;
+ case PHONE_PSTN_GET_STATE:
+ retval = j->daa_mode;
+ j->ex.bits.pstn_ring = 0;
+ break;
+ case IXJCTL_SET_FILTER:
+ if (copy_from_user(&jf, (char *) arg, sizeof(ti)))
+ return -EFAULT;
+ retval = ixj_init_filter(board, &jf);
+ break;
+ case IXJCTL_GET_FILTER_HIST:
+ retval = j->filter_hist[arg];
+ break;
+ case IXJCTL_INIT_TONE:
+ copy_from_user(&ti, (char *) arg, sizeof(ti));
+ retval = ixj_init_tone(board, &ti);
+ break;
+ case IXJCTL_TONE_CADENCE:
+ retval = ixj_build_cadence(board, (IXJ_CADENCE *) arg);
+ break;
+ case IXJCTL_INTERCOM_STOP:
+ ixj[board].intercom = -1;
+ ixj[arg].intercom = -1;
+ ixj_record_stop(board);
+ ixj_record_stop(arg);
+ ixj_play_stop(board);
+ ixj_play_stop(arg);
+ idle(board);
+ idle(arg);
+ break;
+ case IXJCTL_INTERCOM_START:
+ ixj[board].intercom = arg;
+ ixj[arg].intercom = board;
+ ixj_play_start(arg);
+ ixj_record_start(board);
+ ixj_play_start(board);
+ ixj_record_start(arg);
+ idle(board);
+ idle(arg);
+ break;
+ }
+ return retval;
+}
+
+static int ixj_fasync(int fd, struct file *file_p, int mode)
+{
+ IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)];
+ return fasync_helper(fd, file_p, mode, &j->async_queue);
+}
+
+struct file_operations ixj_fops =
+{
+ NULL, /* ixj_lseek */
+ ixj_enhanced_read,
+ ixj_enhanced_write,
+ NULL, /* ixj_readdir */
+ ixj_poll,
+ ixj_ioctl,
+ NULL, /* ixj_mmap */
+// ixj_open,
+ NULL, /* ixj_open */
+ NULL, /* ixj_flush */
+ ixj_release,
+ NULL, /* ixj_fsync */
+ ixj_fasync, /* ixj_fasync */
+ NULL, /* media change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+static int ixj_linetest(int board)
+{
+ unsigned long jifwait;
+ IXJ *j = &ixj[board];
+
+ if (!j->flags.pots_correct) {
+ j->flags.pots_correct = 1; // Testing
+
+ daa_int_read(board); //Clear DAA Interrupt flags
+ //
+ // Hold all relays in the normally de-energized position.
+ //
+
+ j->pld_slicw.bits.rly1 = 0;
+ j->pld_slicw.bits.rly2 = 0;
+ j->pld_slicw.bits.rly3 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01);
+ if (j->pld_slicr.bits.potspstn) {
+ j->flags.pots_pstn = 1;
+ j->flags.pots_correct = 0;
+ LED_SetState(0x4, board);
+ } else {
+ j->flags.pots_pstn = 0;
+ j->pld_slicw.bits.rly1 = 0;
+ j->pld_slicw.bits.rly2 = 0;
+ j->pld_slicw.bits.rly3 = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ daa_set_mode(board, SOP_PU_CONVERSATION);
+ jifwait = jiffies + hertz;
+ while (time_before(jiffies, jifwait)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ daa_int_read(board);
+ daa_set_mode(board, SOP_PU_SLEEP);
+ if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+ j->flags.pots_correct = 0; // Should not be line voltage on POTS port.
+
+ LED_SetState(0x4, board);
+ j->pld_slicw.bits.rly3 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ } else {
+ j->flags.pots_correct = 1;
+ LED_SetState(0x8, board);
+ j->pld_slicw.bits.rly1 = 1;
+ j->pld_slicw.bits.rly2 = 0;
+ j->pld_slicw.bits.rly3 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ }
+ }
+ }
+ if (!j->flags.pstn_present) {
+ j->pld_slicw.bits.rly3 = 0;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ daa_set_mode(board, SOP_PU_CONVERSATION);
+ jifwait = jiffies + hertz;
+ while (time_before(jiffies, jifwait)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ daa_int_read(board);
+ daa_set_mode(board, SOP_PU_SLEEP);
+ if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) {
+ j->flags.pstn_present = 1;
+ } else {
+ j->flags.pstn_present = 0;
+ }
+ }
+ if (j->flags.pstn_present) {
+ if (j->flags.pots_correct) {
+ LED_SetState(0xA, board);
+ } else {
+ LED_SetState(0x6, board);
+ }
+ } else {
+ if (j->flags.pots_correct) {
+ LED_SetState(0x9, board);
+ } else {
+ LED_SetState(0x5, board);
+ }
+ }
+ return j->flags.pstn_present;
+}
+
+static int ixj_selfprobe(int board)
+{
+ unsigned short cmd;
+ unsigned long jif;
+ BYTES bytes;
+ IXJ *j = &ixj[board];
+
+ /*
+ * First initialise the queues
+ */
+
+ init_waitqueue_head(&j->read_q);
+ init_waitqueue_head(&j->write_q);
+ init_waitqueue_head(&j->poll_q);
+
+ /*
+ * Now we can probe
+ */
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Write IDLE to Software Control Register\n");
+
+ if (ixj_WriteDSPCommand(0x0000, board)) /* Write IDLE to Software Control Register */
+ return -1;
+
+// The read values of the SSR should be 0x00 for the IDLE command
+ if (j->ssr.low || j->ssr.high)
+ return -1;
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Get Device ID Code\n");
+
+ if (ixj_WriteDSPCommand(0x3400, board)) /* Get Device ID Code */
+ return -1;
+
+ j->dsp.low = j->ssr.low;
+ j->dsp.high = j->ssr.high;
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Get Device Version Code\n");
+
+ if (ixj_WriteDSPCommand(0x3800, board)) /* Get Device Version Code */
+ return -1;
+
+ j->ver.low = j->ssr.low;
+ j->ver.high = j->ssr.high;
+
+ if (!j->cardtype) {
+ if (j->dsp.low == 0x21) {
+ j->XILINXbase = j->DSPbase + 0x10;
+ bytes.high = bytes.low = inb_p(j->XILINXbase + 0x02);
+ outb_p(bytes.low ^ 0xFF, j->XILINXbase + 0x02);
+ // Test for Internet LineJACK or Internet PhoneJACK Lite
+ bytes.low = inb_p(j->XILINXbase + 0x02);
+ if (bytes.low == bytes.high) // Register is read only on
+ // Internet PhoneJack Lite
+ {
+ j->cardtype = 400; // Internet PhoneJACK Lite
+
+ if (check_region(j->XILINXbase, 4)) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+ return -1;
+ }
+ request_region(j->XILINXbase, 4, "ixj control");
+ j->pld_slicw.pcib.e1 = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase);
+ } else {
+ j->cardtype = 300; // Internet LineJACK
+
+ if (check_region(j->XILINXbase, 8)) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+ return -1;
+ }
+ request_region(j->XILINXbase, 8, "ixj control");
+ }
+ } else if (j->dsp.low == 0x22) {
+ j->cardtype = 500; // Internet PhoneJACK PCI
+
+ request_region(j->XILINXbase, 4, "ixj control");
+ j->pld_slicw.pcib.e1 = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase);
+ } else
+ j->cardtype = 100; // Internet PhoneJACK
+
+ } else {
+ switch (j->cardtype) {
+ case 100: // Internet PhoneJACK
+
+ if (!j->dsp.low != 0x20) {
+ j->dsp.high = 0x80;
+ j->dsp.low = 0x20;
+ ixj_WriteDSPCommand(0x3800, board);
+ j->ver.low = j->ssr.low;
+ j->ver.high = j->ssr.high;
+ }
+ break;
+ case 300: // Internet LineJACK
+
+ if (check_region(j->XILINXbase, 8)) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+ return -1;
+ }
+ request_region(j->XILINXbase, 8, "ixj control");
+ break;
+ case 400: //Internet PhoneJACK Lite
+
+ case 500: //Internet PhoneJACK PCI
+
+ if (check_region(j->XILINXbase, 4)) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", j->XILINXbase);
+ return -1;
+ }
+ request_region(j->XILINXbase, 4, "ixj control");
+ j->pld_slicw.pcib.e1 = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase);
+ break;
+ }
+ }
+ if (j->dsp.low == 0x20 || j->cardtype == 400 || j->cardtype == 500) {
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Write CODEC config to Software Control Register\n");
+
+ if (ixj_WriteDSPCommand(0xC462, board)) /* Write CODEC config to Software Control Register */
+ return -1;
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Write CODEC timing to Software Control Register\n");
+
+ if (j->cardtype == 100) {
+ cmd = 0x9FF2;
+ } else {
+ cmd = 0x9FF5;
+ }
+ if (ixj_WriteDSPCommand(cmd, board)) /* Write CODEC timing to Software Control Register */
+ return -1;
+ } else {
+ if (set_base_frame(board, 30) != 30)
+ return -1;
+
+ if (j->cardtype == 300) {
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Write CODEC config to Software Control Register\n");
+
+ if (ixj_WriteDSPCommand(0xC528, board)) /* Write CODEC config to Software Control Register */
+ return -1;
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Turn on the PLD Clock at 8Khz\n");
+
+ j->pld_clock.byte = 0;
+ outb_p(j->pld_clock.byte, j->XILINXbase + 0x04);
+ }
+ }
+
+ if (j->dsp.low == 0x20) {
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Configure GPIO pins\n");
+
+ j->gpio.bytes.high = 0x09;
+ /* bytes.low = 0xEF; 0xF7 */
+ j->gpio.bits.gpio1 = 1;
+ j->gpio.bits.gpio2 = 1;
+ j->gpio.bits.gpio3 = 0;
+ j->gpio.bits.gpio4 = 1;
+ j->gpio.bits.gpio5 = 1;
+ j->gpio.bits.gpio6 = 1;
+ j->gpio.bits.gpio7 = 1;
+ ixj_WriteDSPCommand(ixj[board].gpio.word, board); /* Set GPIO pin directions */
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Enable SLIC\n");
+
+ j->gpio.bytes.high = 0x0B;
+ j->gpio.bytes.low = 0x00;
+ j->gpio.bits.gpio1 = 0;
+ j->gpio.bits.gpio2 = 1;
+ j->gpio.bits.gpio5 = 0;
+ ixj_WriteDSPCommand(ixj[board].gpio.word, board); /* send the ring stop signal */
+ j->port = PORT_POTS;
+ } else {
+ if (j->cardtype == 300) {
+ LED_SetState(0x1, board);
+ jif = jiffies + (hertz / 10);
+ while (time_before(jiffies, jif)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ LED_SetState(0x2, board);
+ jif = jiffies + (hertz / 10);
+ while (time_before(jiffies, jif)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ LED_SetState(0x4, board);
+ jif = jiffies + (hertz / 10);
+ while (time_before(jiffies, jif)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ LED_SetState(0x8, board);
+ jif = jiffies + (hertz / 10);
+ while (time_before(jiffies, jif)) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ LED_SetState(0x0, board);
+
+ daa_get_version(board);
+
+ if (ixjdebug > 0)
+ printk("Loading DAA Coefficients\n");
+
+ DAA_Coeff_US(board);
+ if (!ixj_daa_write(board))
+ printk("DAA write failed on board %d\n", board);
+
+ ixj_daa_cid_reset(board);
+
+ j->flags.pots_correct = 0;
+ j->flags.pstn_present = 0;
+
+ ixj_linetest(board);
+
+ if (j->flags.pots_correct) {
+ j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(j->pld_scrw.byte, j->XILINXbase);
+ j->pld_slicw.bits.rly1 = 1;
+ j->pld_slicw.bits.spken = 1;
+ outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
+ SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+ j->port = PORT_POTS;
+ }
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Enable Mixer\n");
+
+ ixj_mixer(0x0000, board); //Master Volume Left unmute 0db
+
+ ixj_mixer(0x0100, board); //Master Volume Right unmute 0db
+
+ ixj_mixer(0x0F00, board); //Mono Out Volume unmute 0db
+
+ ixj_mixer(0x0C00, board); //Mono1 Volume unmute 0db
+
+ ixj_mixer(0x0200, board); //Voice Left Volume unmute 0db
+
+ ixj_mixer(0x0300, board); //Voice Right Volume unmute 0db
+
+ ixj_mixer(0x110C, board); //Voice Left and Right out
+
+ ixj_mixer(0x1401, board); //Mono1 switch on mixer left
+
+ ixj_mixer(0x1501, board); //Mono1 switch on mixer right
+
+ ixj_mixer(0x1700, board); //Clock select
+
+ ixj_mixer(0x1800, board); //ADC Source select
+
+ } else {
+ j->port = PORT_POTS;
+ SLIC_SetState(PLD_SLIC_STATE_STANDBY, board);
+ }
+ }
+
+ j->intercom = -1;
+ j->framesread = j->frameswritten = 0;
+ j->rxreadycheck = j->txreadycheck = 0;
+
+ if (ixj_WriteDSPCommand(0x0000, board)) /* Write IDLE to Software Control Register */
+ return -1;
+
+ // The read values of the SSR should be 0x00 for the IDLE command
+ if (j->ssr.low || j->ssr.high)
+ return -1;
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Enable Line Monitor\n");
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Set Line Monitor to Asyncronous Mode\n");
+
+ if (ixj_WriteDSPCommand(0x7E01, board)) // Asynchronous Line Monitor
+
+ return -1;
+
+ if (ixjdebug > 0)
+ printk(KERN_INFO "Enable DTMF Detectors\n");
+
+ if (ixj_WriteDSPCommand(0x5151, board)) // Enable DTMF detection
+
+ return -1;
+
+ if (ixj_WriteDSPCommand(0x6E01, board)) // Set Asyncronous Tone Generation
+
+ return -1;
+
+ set_rec_depth(board, 2); // Set Record Channel Limit to 2 frames
+
+ set_play_depth(board, 2); // Set Playback Channel Limit to 2 frames
+
+ j->ex.bits.dtmf_ready = 0;
+ j->dtmf_state = 0;
+ j->dtmf_wp = ixj[board].dtmf_rp = 0;
+
+ j->rec_mode = ixj[board].play_mode = -1;
+ j->flags.ringing = 0;
+ j->maxrings = MAXRINGS;
+ j->ring_cadence = USA_RING_CADENCE;
+ j->drybuffer = 0;
+ j->winktime = 320;
+ j->flags.dtmf_oob = 0;
+
+ /* must be a device on the specified address */
+ /* Register with the Telephony for Linux subsystem */
+ j->p.f_op = &ixj_fops;
+ j->p.open = ixj_open;
+ phone_register_device(&j->p, PHONE_UNIT_ANY);
+
+ add_caps(board);
+
+ return 0;
+}
+
+static void cleanup(void)
+{
+ int cnt;
+
+ del_timer(&ixj_timer);
+// if (ixj_major)
+ // unregister_chrdev(ixj_major, "ixj");
+ for (cnt = 0; cnt < IXJMAX; cnt++) {
+ if (ixj[cnt].cardtype == 300) {
+ ixj[cnt].pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync
+
+ outb_p(ixj[cnt].pld_scrw.byte, ixj[cnt].XILINXbase);
+ ixj[cnt].pld_slicw.bits.rly1 = 0;
+ ixj[cnt].pld_slicw.bits.rly2 = 0;
+ ixj[cnt].pld_slicw.bits.rly3 = 0;
+ outb_p(ixj[cnt].pld_slicw.byte, ixj[cnt].XILINXbase + 0x01);
+ LED_SetState(0x0, cnt);
+
+ release_region(ixj[cnt].XILINXbase, 8);
+ }
+ if (ixj[cnt].cardtype == 400 || ixj[cnt].cardtype == 500) {
+ release_region(ixj[cnt].XILINXbase, 4);
+ }
+ if (ixj[cnt].DSPbase) {
+ release_region(ixj[cnt].DSPbase, 16);
+ phone_unregister_device(&ixj[cnt].p);
+ }
+ if (ixj[cnt].read_buffer)
+ kfree(ixj[cnt].read_buffer);
+ if (ixj[cnt].write_buffer)
+ kfree(ixj[cnt].write_buffer);
+#ifdef CONFIG_ISAPNP
+ if (ixj[cnt].dev)
+ ixj[cnt].dev->deactivate(ixj[cnt].dev);
+#endif
+ }
+}
+
+
+// Typedefs
+typedef struct {
+ BYTE length;
+ DWORD bits;
+} DATABLOCK;
+
+static void PCIEE_WriteBit(WORD wEEPROMAddress, BYTE lastLCC, BYTE byData)
+{
+ lastLCC = lastLCC & 0xfb;
+ lastLCC = lastLCC | (byData ? 4 : 0);
+ outb(lastLCC, wEEPROMAddress); //set data out bit as appropriate
+
+ udelay(1000);
+ lastLCC = lastLCC | 0x01;
+ outb(lastLCC, wEEPROMAddress); //SK rising edge
+
+ byData = byData << 1;
+ lastLCC = lastLCC & 0xfe;
+
+ udelay(1000);
+ outb(lastLCC, wEEPROMAddress); //after delay, SK falling edge
+
+}
+
+static BYTE PCIEE_ReadBit(WORD wEEPROMAddress, BYTE lastLCC)
+{
+ udelay(1000);
+ lastLCC = lastLCC | 0x01;
+ outb(lastLCC, wEEPROMAddress); //SK rising edge
+
+ lastLCC = lastLCC & 0xfe;
+ udelay(1000);
+ outb(lastLCC, wEEPROMAddress); //after delay, SK falling edge
+
+ return ((inb(wEEPROMAddress) >> 3) & 1);
+}
+
+static BOOL PCIEE_ReadWord(WORD wAddress, WORD wLoc, WORD * pwResult)
+{
+ BYTE lastLCC;
+ WORD wEEPROMAddress = wAddress + 3;
+ DWORD i;
+ BYTE byResult;
+
+ *pwResult = 0;
+
+ lastLCC = inb(wEEPROMAddress);
+
+ lastLCC = lastLCC | 0x02;
+ lastLCC = lastLCC & 0xfe;
+ outb(lastLCC, wEEPROMAddress); // CS hi, SK lo
+
+ udelay(1000); // delay
+
+ PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1);
+ PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1);
+ PCIEE_WriteBit(wEEPROMAddress, lastLCC, 0);
+
+ for (i = 0; i < 8; i++) {
+ PCIEE_WriteBit(wEEPROMAddress, lastLCC, wLoc & 0x80 ? 1 : 0);
+ wLoc <<= 1;
+ }
+
+ for (i = 0; i < 16; i++) {
+ byResult = PCIEE_ReadBit(wEEPROMAddress, lastLCC);
+ *pwResult = (*pwResult << 1) | byResult;
+ }
+
+ udelay(1000); // another delay
+
+ lastLCC = lastLCC & 0xfd;
+ outb(lastLCC, wEEPROMAddress); // negate CS
+
+ return 0;
+}
+
+static DWORD PCIEE_GetSerialNumber(WORD wAddress)
+{
+ WORD wLo, wHi;
+
+ if (PCIEE_ReadWord(wAddress, 62, &wLo))
+ return 0;
+
+ if (PCIEE_ReadWord(wAddress, 63, &wHi))
+ return 0;
+
+ return (((DWORD) wHi << 16) | wLo);
+}
+
+static int dspio[IXJMAX + 1] = {0,};
+static int xio[IXJMAX + 1] = {0,};
+
+MODULE_DESCRIPTION("Internet PhoneJACK/Internet LineJACK module - www.quicknet.net");
+MODULE_AUTHOR("Ed Okerson <eokerson@quicknet.net>");
+
+MODULE_PARM(dspio, "1-" __MODULE_STRING(IXJMAX) "i");
+MODULE_PARM(xio, "1-" __MODULE_STRING(IXJMAX) "i");
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+ cleanup();
+}
+
+int init_module(void)
+#else
+int __init ixj_init(void)
+#endif
+{
+ int result;
+
+ int func = 0x110, i = 0;
+ int cnt = 0;
+ int probe = 0;
+ struct pci_dev *dev = NULL, *old_dev = NULL;
+ struct pci_dev *pci = NULL;
+
+#ifdef CONFIG_ISAPNP
+ while (1) {
+ do {
+ old_dev = dev;
+ dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('Q', 'T', 'I'),
+ ISAPNP_FUNCTION(func), old_dev);
+ if (!dev)
+ break;
+ printk("preparing %x\n", func);
+ result = dev->prepare(dev);
+ if (result < 0) {
+ printk("preparing failed %d \n", result);
+ break;
+ }
+ if (!(dev->resource[0].flags & IORESOURCE_IO))
+ return -ENODEV;
+ dev->resource[0].flags |= IORESOURCE_AUTO;
+ if (func != 0x110)
+ dev->resource[1].flags |= IORESOURCE_AUTO;
+ if (dev->activate(dev) < 0) {
+ printk("isapnp configure failed (out of resources?)\n");
+ return -ENOMEM;
+ }
+ ixj[cnt].DSPbase = dev->resource[0].start; /* get real port */
+ if (func != 0x110)
+ ixj[cnt].XILINXbase = dev->resource[1].start; /* get real port */
+
+ result = check_region(ixj[cnt].DSPbase, 16);
+ if (result) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+ cleanup();
+ return result;
+ }
+ request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+ switch (func) {
+ case (0x110):
+ ixj[cnt].cardtype = 100;
+ break;
+ case (0x310):
+ ixj[cnt].cardtype = 300;
+ break;
+ case (0x410):
+ ixj[cnt].cardtype = 400;
+ break;
+ }
+ probe = ixj_selfprobe(cnt);
+
+ ixj[cnt].serial = dev->bus->serial;
+ ixj[cnt].dev = dev;
+ printk(KERN_INFO "ixj: found card at 0x%x\n", ixj[cnt].DSPbase);
+ cnt++;
+ } while (dev);
+
+ if (func == 0x410)
+ break;
+ if (func == 0x310)
+ func = 0x410;
+ if (func == 0x110)
+ func = 0x310;
+ dev = NULL;
+ }
+#else //CONFIG_ISAPNP
+ /* Use passed parameters for older kernels without PnP */
+
+ for (cnt = 0; cnt < IXJMAX; cnt++) {
+ if (dspio[cnt]) {
+ ixj[cnt].DSPbase = dspio[cnt];
+ ixj[cnt].XILINXbase = xio[cnt];
+ ixj[cnt].cardtype = 0;
+ result = check_region(ixj[cnt].DSPbase, 16);
+ if (result) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+ cleanup();
+ return result;
+ }
+ request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+ probe = ixj_selfprobe(cnt);
+ ixj[cnt].dev = NULL;
+ }
+ }
+#endif
+#ifdef CONFIG_PCI
+ if (pci_present()) {
+ for (i = 0; i < IXJMAX - cnt; i++) {
+ pci = pci_find_device(0x15E2, 0x0500, pci);
+ if (!pci)
+ break;
+ {
+ ixj[cnt].DSPbase = pci->resource[0].start;
+ ixj[cnt].XILINXbase = ixj[cnt].DSPbase + 0x10;
+ ixj[cnt].serial = PCIEE_GetSerialNumber(pci->resource[2].start);
+
+ result = check_region(ixj[cnt].DSPbase, 16);
+ if (result) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase);
+ cleanup();
+ return result;
+ }
+ request_region(ixj[cnt].DSPbase, 16, "ixj DSP");
+ ixj[cnt].cardtype = 500;
+ probe = ixj_selfprobe(cnt);
+ cnt++;
+ }
+ }
+ }
+#endif
+ printk("%s\n", ixj_c_rcsid);
+
+ ixj_init_timer();
+ ixj_add_timer();
+ return probe;
+}
+
+static void DAA_Coeff_US(int board)
+{
+ IXJ *j = &ixj[board];
+
+ int i;
+
+ //-----------------------------------------------
+ // CAO
+ for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+ j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+ }
+
+ // Bytes for IM-filter part 1 (04): 0E,32,E2,2F,C2,5A,C0,00
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2F;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xC2;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xC0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 72,85,00,0E,2B,3A,D0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x72;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x85;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x2B;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter (08): 03,8F,48,F2,8F,48,70,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x03;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x48;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0xF2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x48;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x70;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter (07): 04,8F,38,7F,9B,EA,B0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x04;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0x38;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x7F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9B;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter (0A): 16,55,DD,CA
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x55;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter (09): 52,D3,11,42
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xD3;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x11;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x42;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,B3,80,00,98
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,F2,33,A0,68,AB,8A,AD
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xF2;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x33;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xA0;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x68;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAB;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAD;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,54,A4,BA,2D,BB
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x54;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0xA4;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2D;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBB;
+
+// ; (10K, 0.68uF)
+ //
+ // Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x9B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0xD4;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0xD4;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+//
+ // Levelmetering Ringing (0D):B2,45,0F,8E
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+//
+ // ;CR Registers
+ // Config. Reg. 0 (filters) (cr0):FE ; CLK gen. by crystal
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE;
+
+// Config. Reg. 1 (dialing) (cr1):05
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID) (cr2):04
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops) (cr3):03 ; SEL Bit==0, HP-disabled
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x03;
+
+// Config. Reg. 4 (analog gain) (cr4):01
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01;
+
+// Config. Reg. 5 (Version) (cr5):02
+ // Config. Reg. 6 (Reserved) (cr6):00
+ // Config. Reg. 7 (Reserved) (cr7):00
+ //
+
+// ;xr Registers
+ // Ext. Reg. 0 (Interrupt Reg.) (xr0):02
+ j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C // Cadence, RING, Caller ID, VDD_OK
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x3C;
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char) (xr3):32 ; B-Filter Off == 1
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x12; //0x32;
+
+// Ext. Reg. 4 (Cadence) (xr4):00
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer) (xr5):22
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State) (xr6):00
+ j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd) (xr7):40
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00?
+
+//
+ // DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz
+ // 12,33,5A,C3 ; 770 Hz
+ // 13,3C,5B,32 ; 852 Hz
+ // 1D,1B,5C,CC ; 941 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz
+ // EC,1D,52,22 ; 1336 Hz
+ // AA,AC,51,D2 ; 1477 Hz
+ // 9B,3B,51,25 ; 1633 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static void DAA_Coeff_UK(int board)
+{
+ IXJ *j = &ixj[board];
+
+ int i;
+
+ //-----------------------------------------------
+ // CAO
+ for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+ j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+ }
+
+ // Bytes for IM-filter part 1 (04): 00,C2,BB,A8,CB,81,A0,00
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xC2;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xA8;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xCB;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+ // Bytes for IM-filter part 2 (05): 40,00,00,0A,A4,33,E0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x40;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0A;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0xA4;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter (08): 07,9B,ED,24,B2,A2,A0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9B;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xED;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x24;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0xB2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0xA2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xA0;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter (07): 0F,92,F2,B2,87,D2,30,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x92;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xF2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0xB2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x87;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xD2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x30;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter (0A): 1B,A5,DD,CA
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xA5;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter (09): E2,27,10,D6
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x27;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 80,2D,38,8B,D0,00,00,98
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x2D;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x38;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x8B;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xD0;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,5A,53,F0,0B,5F,84,D4
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x53;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xF0;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x0B;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5F;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x84;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xD4;
+
+// Bytes for TH-filter part 3 (02): 00,88,6A,A4,8F,52,F5,32
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x6A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0xA4;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xF5;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x32;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing (0D):AA,35,0F,8E ; 25Hz 30V less possible?
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+ // Config. Reg. 0 (filters) (cr0):FF
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF; //0xFE;
+
+// Config. Reg. 1 (dialing) (cr1):05
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID) (cr2):04
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops) (cr3):00 ;
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain) (cr4):01
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01;
+
+// Config. Reg. 5 (Version) (cr5):02
+ // Config. Reg. 6 (Reserved) (cr6):00
+ // Config. Reg. 7 (Reserved) (cr7):00
+
+// ;xr Registers
+ // Ext. Reg. 0 (Interrupt Reg.) (xr0):02
+ j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char) (xr3):36 ;
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36;
+
+// Ext. Reg. 4 (Cadence) (xr4):00
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer) (xr5):22
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State) (xr6):00
+ j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd) (xr7):46
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46; // 0x46 ??? Should it be 0x00?
+
+// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz
+ // 12,33,5A,C3 ; 770 Hz
+ // 13,3C,5B,32 ; 852 Hz
+ // 1D,1B,5C,CC ; 941 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz
+ // EC,1D,52,22 ; 1336 Hz
+ // AA,AC,51,D2 ; 1477 Hz
+ // 9B,3B,51,25 ; 1633 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_France(int board)
+{
+ IXJ *j = &ixj[board];
+
+ int i;
+
+ //-----------------------------------------------
+ // CAO
+ for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+ j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+ }
+
+ // Bytes for IM-filter part 1 (04): 02,A2,43,2C,22,AF,A0,00
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA2;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0x43;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2C;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xAF;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 67,CE,00,0C,22,33,E0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x67;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xCE;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x2C;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter (08): 07,9A,28,F6,23,4A,B0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9A;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x28;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0xF6;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x23;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x4A;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xB0;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter (07): 03,8F,F9,2F,9E,FA,20,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xF9;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x2F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9E;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xFA;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter (0A): 16,B5,DD,CA
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter (09): 52,C7,10,D6
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xC7;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,A6,80,00,98
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xA6;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,AC,2A,30,78,AC,8A,2C
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAC;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x2A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x30;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x78;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAC;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x2C;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,A5,22,BA,2C,45
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0xA5;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2C;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x45;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing (0D):32,45,B5,84 ; 50Hz 20V
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84;
+
+// Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+ // Config. Reg. 0 (filters) (cr0):FF
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing) (cr1):05
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID) (cr2):04
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops) (cr3):00 ;
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain) (cr4):01
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01;
+
+// Config. Reg. 5 (Version) (cr5):02
+ // Config. Reg. 6 (Reserved) (cr6):00
+ // Config. Reg. 7 (Reserved) (cr7):00
+
+// ;xr Registers
+ // Ext. Reg. 0 (Interrupt Reg.) (xr0):02
+ j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char) (xr3):36 ;
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36;
+
+// Ext. Reg. 4 (Cadence) (xr4):00
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer) (xr5):22
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State) (xr6):00
+ j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd) (xr7):46
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46; // 0x46 ??? Should it be 0x00?
+
+// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz
+ // 12,33,5A,C3 ; 770 Hz
+ // 13,3C,5B,32 ; 852 Hz
+ // 1D,1B,5C,CC ; 941 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz
+ // EC,1D,52,22 ; 1336 Hz
+ // AA,AC,51,D2 ; 1477 Hz
+ // 9B,3B,51,25 ; 1633 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_Germany(int board)
+{
+ IXJ *j = &ixj[board];
+
+ int i;
+
+ //-----------------------------------------------
+ // CAO
+ for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+ j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+ }
+
+ // Bytes for IM-filter part 1 (04): 00,CE,BB,B8,D2,81,B0,00
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xCE;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xB8;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xD2;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xB0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 45,8F,00,0C,D2,3A,D0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x45;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0C;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0xD2;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter (08): 07,AA,E2,34,24,89,20,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0xAA;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xE2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x34;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x24;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x89;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x20;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter (07): 02,87,FA,37,9A,CA,B0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x87;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xFA;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x37;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x9A;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter (0A): 72,D5,DD,CA
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x72;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xD5;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter (09): 72,42,13,4B
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x72;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x42;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x13;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x4B;
+
+// Bytes for TH-filter part 1 (00): 80,52,48,81,AD,80,00,98
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAD;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,42,5A,20,E8,1A,81,27
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x42;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x20;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0xE8;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x1A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x27;
+
+// Bytes for TH-filter part 3 (02): 00,88,63,26,BD,4B,A3,C2
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x63;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x26;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0xBD;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x4B;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xA3;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xC2;
+
+// ; (10K, 0.68uF)
+
+// Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x9B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0xD4;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0xD4;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing (0D):B2,45,0F,8E
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+ // Config. Reg. 0 (filters) (cr0):FF ; all Filters enabled, CLK from ext. source
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing) (cr1):05 ; Manual Ring, Ring metering enabled
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID) (cr2):04 ; Analog Gain 0dB, FSC internal
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops) (cr3):00 ; SEL Bit==0, HP-enabled
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain) (cr4):01
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01;
+
+// Config. Reg. 5 (Version) (cr5):02
+ // Config. Reg. 6 (Reserved) (cr6):00
+ // Config. Reg. 7 (Reserved) (cr7):00
+
+// ;xr Registers
+ // Ext. Reg. 0 (Interrupt Reg.) (xr0):02
+ j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C ; Ring, CID, VDDOK Interrupts enabled
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char) (xr3):32 ; B-Filter Off==1, U0=3.5V, R=200Ohm
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x32;
+
+// Ext. Reg. 4 (Cadence) (xr4):00
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer) (xr5):22
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State) (xr6):00
+ j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd) (xr7):40 ; VDD=4.25 V
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz
+ // 12,33,5A,C3 ; 770 Hz
+ // 13,3C,5B,32 ; 852 Hz
+ // 1D,1B,5C,CC ; 941 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz
+ // EC,1D,52,22 ; 1336 Hz
+ // AA,AC,51,D2 ; 1477 Hz
+ // 9B,3B,51,25 ; 1633 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+
+static void DAA_Coeff_Australia(int board)
+{
+ IXJ *j = &ixj[board];
+
+ int i;
+
+ //-----------------------------------------------
+ // CAO
+ for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+ j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+ }
+
+ // Bytes for IM-filter part 1 (04): 00,A3,AA,28,B3,82,D0,00
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA3;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xAA;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x28;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x82;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xD0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 70,96,00,09,32,6B,C0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x70;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x96;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x09;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x6B;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xC0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter (08): 07,96,E2,34,32,9B,30,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x96;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0xE2;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x34;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x9B;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x30;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter (07): 0F,9A,E9,2F,22,CC,A0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x9A;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0xE9;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x2F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCC;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xA0;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter (0A): CB,45,DD,CA
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0xCB;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x45;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter (09): 1B,67,10,D6
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x67;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 80,52,48,81,AF,80,00,98
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAF;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,DB,52,B0,38,01,82,AC
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xDB;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0xB0;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x38;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x01;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x82;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAC;
+
+// Bytes for TH-filter part 3 (02): 00,88,4A,3E,2C,3B,24,46
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0x4A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x3E;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x2C;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x3B;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x24;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x46;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing (0D):32,45,B5,84 ; 50Hz 20V
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84;
+
+// Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+ // Config. Reg. 0 (filters) (cr0):FF
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing) (cr1):05
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID) (cr2):04
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops) (cr3):00 ;
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain) (cr4):01
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01;
+
+// Config. Reg. 5 (Version) (cr5):02
+ // Config. Reg. 6 (Reserved) (cr6):00
+ // Config. Reg. 7 (Reserved) (cr7):00
+
+// ;xr Registers
+ // Ext. Reg. 0 (Interrupt Reg.) (xr0):02
+ j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char) (xr3):2B ;
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x2B;
+
+// Ext. Reg. 4 (Cadence) (xr4):00
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer) (xr5):22
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State) (xr6):00
+ j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd) (xr7):40
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz
+ // 12,33,5A,C3 ; 770 Hz
+ // 13,3C,5B,32 ; 852 Hz
+ // 1D,1B,5C,CC ; 941 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz
+ // EC,1D,52,22 ; 1336 Hz
+ // AA,AC,51,D2 ; 1477 Hz
+ // 9B,3B,51,25 ; 1633 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static void DAA_Coeff_Japan(int board)
+{
+ IXJ *j = &ixj[board];
+
+ int i;
+
+ //-----------------------------------------------
+ // CAO
+ for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) {
+ j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0;
+ }
+
+ // Bytes for IM-filter part 1 (04): 06,BD,E2,2D,BA,F9,A0,00
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x06;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xBD;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2D;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[3] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xF9;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00;
+
+// Bytes for IM-filter part 2 (05): 6F,F7,00,0E,34,33,E0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x6F;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xF7;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[4] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[3] = 0x34;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0;
+ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08;
+
+// Bytes for FRX-filter (08): 02,8F,68,77,9C,58,F0,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[5] = 0x68;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[4] = 0x77;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[3] = 0x9C;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x58;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xF0;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08;
+
+// Bytes for FRR-filter (07): 03,8F,38,73,87,EA,20,08
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[5] = 0x38;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[4] = 0x73;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[3] = 0x87;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20;
+ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08;
+
+// Bytes for AX-filter (0A): 51,C5,DD,CA
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x51;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xC5;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD;
+ j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA;
+
+// Bytes for AR-filter (09): 25,A7,10,D6
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x25;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xA7;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10;
+ j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6;
+
+// Bytes for TH-filter part 1 (00): 00,42,48,81,AE,80,00,98
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[5] = 0x48;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[4] = 0x81;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[3] = 0xAE;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98;
+
+// Bytes for TH-filter part 2 (01): 02,AB,2A,20,99,5B,89,28
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAB;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[5] = 0x2A;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[4] = 0x20;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[3] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5B;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x89;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x28;
+
+// Bytes for TH-filter part 3 (02): 00,88,DA,25,34,C5,4C,BA
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[5] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[4] = 0x25;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[3] = 0x34;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xC5;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x4C;
+ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBA;
+
+// ; idle
+
+// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[4] = 0x3A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23;
+
+// Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[4] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[3] = 0x22;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A;
+ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5;
+
+// Levelmetering Ringing (0D):AA,35,0F,8E ; 25Hz 30V ?????????
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F;
+ j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E;
+
+// Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[5] = 0xCA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[4] = 0x09;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[3] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99;
+
+// Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[5] = 0xBA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[4] = 0x07;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[3] = 0xDA;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00;
+ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00;
+
+// ;CR Registers
+ // Config. Reg. 0 (filters) (cr0):FF
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF;
+
+// Config. Reg. 1 (dialing) (cr1):05
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05;
+
+// Config. Reg. 2 (caller ID) (cr2):04
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04;
+
+// Config. Reg. 3 (testloops) (cr3):00 ;
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00;
+
+// Config. Reg. 4 (analog gain) (cr4):01
+ j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01;
+
+// Config. Reg. 5 (Version) (cr5):02
+ // Config. Reg. 6 (Reserved) (cr6):00
+ // Config. Reg. 7 (Reserved) (cr7):00
+
+// ;xr Registers
+ // Ext. Reg. 0 (Interrupt Reg.) (xr0):02
+ j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted.
+
+// Ext. Reg. 1 (Interrupt enable) (xr1):1C
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK
+
+// Ext. Reg. 2 (Cadence Time Out) (xr2):7D
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D;
+
+// Ext. Reg. 3 (DC Char) (xr3):22 ;
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x22;
+
+// Ext. Reg. 4 (Cadence) (xr4):00
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00;
+
+// Ext. Reg. 5 (Ring timer) (xr5):22
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22;
+
+// Ext. Reg. 6 (Power State) (xr6):00
+ j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00;
+
+// Ext. Reg. 7 (Vdd) (xr7):40
+ j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00?
+
+// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz
+ // 12,33,5A,C3 ; 770 Hz
+ // 13,3C,5B,32 ; 852 Hz
+ // 1D,1B,5C,CC ; 941 Hz
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C;
+
+// DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz
+ // EC,1D,52,22 ; 1336 Hz
+ // AA,AC,51,D2 ; 1477 Hz
+ // 9B,3B,51,25 ; 1633 Hz
+
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52;
+ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3;
+
+}
+
+static s16 tone_table[][19] =
+{
+ { // f20_50[]
+ 32538, // A1 = 1.985962
+ -32325, // A2 = -0.986511
+ -343, // B2 = -0.010493
+ 0, // B1 = 0
+ 343, // B0 = 0.010493
+ 32619, // A1 = 1.990906
+ -32520, // A2 = -0.992462
+ 19179, // B2 = 0.585327
+ -19178, // B1 = -1.170593
+ 19179, // B0 = 0.585327
+ 32723, // A1 = 1.997314
+ -32686, // A2 = -0.997528
+ 9973, // B2 = 0.304352
+ -9955, // B1 = -0.607605
+ 9973, // B0 = 0.304352
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f133_200[]
+ 32072, // A1 = 1.95752
+ -31896, // A2 = -0.973419
+ -435, // B2 = -0.013294
+ 0, // B1 = 0
+ 435, // B0 = 0.013294
+ 32188, // A1 = 1.9646
+ -32400, // A2 = -0.98877
+ 15139, // B2 = 0.462036
+ -14882, // B1 = -0.908356
+ 15139, // B0 = 0.462036
+ 32473, // A1 = 1.981995
+ -32524, // A2 = -0.992584
+ 23200, // B2 = 0.708008
+ -23113, // B1 = -1.410706
+ 23200, // B0 = 0.708008
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 300.txt
+ 31769, // A1 = -1.939026
+ -32584, // A2 = 0.994385
+ -475, // B2 = -0.014522
+ 0, // B1 = 0.000000
+ 475, // B0 = 0.014522
+ 31789, // A1 = -1.940247
+ -32679, // A2 = 0.997284
+ 17280, // B2 = 0.527344
+ -16865, // B1 = -1.029358
+ 17280, // B0 = 0.527344
+ 31841, // A1 = -1.943481
+ -32681, // A2 = 0.997345
+ 543, // B2 = 0.016579
+ -525, // B1 = -0.032097
+ 543, // B0 = 0.016579
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f300_420[]
+ 30750, // A1 = 1.876892
+ -31212, // A2 = -0.952515
+ -804, // B2 = -0.024541
+ 0, // B1 = 0
+ 804, // B0 = 0.024541
+ 30686, // A1 = 1.872925
+ -32145, // A2 = -0.980988
+ 14747, // B2 = 0.450043
+ -13703, // B1 = -0.836395
+ 14747, // B0 = 0.450043
+ 31651, // A1 = 1.931824
+ -32321, // A2 = -0.986389
+ 24425, // B2 = 0.745422
+ -23914, // B1 = -1.459595
+ 24427, // B0 = 0.745483
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 330.txt
+ 31613, // A1 = -1.929565
+ -32646, // A2 = 0.996277
+ -185, // B2 = -0.005657
+ 0, // B1 = 0.000000
+ 185, // B0 = 0.005657
+ 31620, // A1 = -1.929932
+ -32713, // A2 = 0.998352
+ 19253, // B2 = 0.587585
+ -18566, // B1 = -1.133179
+ 19253, // B0 = 0.587585
+ 31674, // A1 = -1.933228
+ -32715, // A2 = 0.998413
+ 2575, // B2 = 0.078590
+ -2495, // B1 = -0.152283
+ 2575, // B0 = 0.078590
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f300_425[]
+ 30741, // A1 = 1.876282
+ -31475, // A2 = -0.960541
+ -703, // B2 = -0.021484
+ 0, // B1 = 0
+ 703, // B0 = 0.021484
+ 30688, // A1 = 1.873047
+ -32248, // A2 = -0.984161
+ 14542, // B2 = 0.443787
+ -13523, // B1 = -0.825439
+ 14542, // B0 = 0.443817
+ 31494, // A1 = 1.922302
+ -32366, // A2 = -0.987762
+ 21577, // B2 = 0.658508
+ -21013, // B1 = -1.282532
+ 21577, // B0 = 0.658508
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f330_440[]
+ 30627, // A1 = 1.869324
+ -31338, // A2 = -0.95636
+ -843, // B2 = -0.025749
+ 0, // B1 = 0
+ 843, // B0 = 0.025749
+ 30550, // A1 = 1.864685
+ -32221, // A2 = -0.983337
+ 13594, // B2 = 0.414886
+ -12589, // B1 = -0.768402
+ 13594, // B0 = 0.414886
+ 31488, // A1 = 1.921936
+ -32358, // A2 = -0.987518
+ 24684, // B2 = 0.753296
+ -24029, // B1 = -1.466614
+ 24684, // B0 = 0.753296
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 340.txt
+ 31546, // A1 = -1.925476
+ -32646, // A2 = 0.996277
+ -445, // B2 = -0.013588
+ 0, // B1 = 0.000000
+ 445, // B0 = 0.013588
+ 31551, // A1 = -1.925781
+ -32713, // A2 = 0.998352
+ 23884, // B2 = 0.728882
+ -22979, // B1 = -1.402527
+ 23884, // B0 = 0.728882
+ 31606, // A1 = -1.929138
+ -32715, // A2 = 0.998413
+ 863, // B2 = 0.026367
+ -835, // B1 = -0.050985
+ 863, // B0 = 0.026367
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f350_400[]
+ 31006, // A1 = 1.892517
+ -32029, // A2 = -0.977448
+ -461, // B2 = -0.014096
+ 0, // B1 = 0
+ 461, // B0 = 0.014096
+ 30999, // A1 = 1.892029
+ -32487, // A2 = -0.991455
+ 11325, // B2 = 0.345612
+ -10682, // B1 = -0.651978
+ 11325, // B0 = 0.345612
+ 31441, // A1 = 1.919067
+ -32526, // A2 = -0.992615
+ 24324, // B2 = 0.74231
+ -23535, // B1 = -1.436523
+ 24324, // B0 = 0.74231
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f350_440[]
+ 30634, // A1 = 1.869751
+ -31533, // A2 = -0.962341
+ -680, // B2 = -0.020782
+ 0, // B1 = 0
+ 680, // B0 = 0.020782
+ 30571, // A1 = 1.865906
+ -32277, // A2 = -0.985016
+ 12894, // B2 = 0.393524
+ -11945, // B1 = -0.729065
+ 12894, // B0 = 0.393524
+ 31367, // A1 = 1.91449
+ -32379, // A2 = -0.988129
+ 23820, // B2 = 0.726929
+ -23104, // B1 = -1.410217
+ 23820, // B0 = 0.726929
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f350_450[]
+ 30552, // A1 = 1.864807
+ -31434, // A2 = -0.95929
+ -690, // B2 = -0.021066
+ 0, // B1 = 0
+ 690, // B0 = 0.021066
+ 30472, // A1 = 1.859924
+ -32248, // A2 = -0.984161
+ 13385, // B2 = 0.408478
+ -12357, // B1 = -0.754242
+ 13385, // B0 = 0.408478
+ 31358, // A1 = 1.914001
+ -32366, // A2 = -0.987732
+ 26488, // B2 = 0.80835
+ -25692, // B1 = -1.568176
+ 26490, // B0 = 0.808411
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 360.txt
+ 31397, // A1 = -1.916321
+ -32623, // A2 = 0.995605
+ -117, // B2 = -0.003598
+ 0, // B1 = 0.000000
+ 117, // B0 = 0.003598
+ 31403, // A1 = -1.916687
+ -32700, // A2 = 0.997925
+ 3388, // B2 = 0.103401
+ -3240, // B1 = -0.197784
+ 3388, // B0 = 0.103401
+ 31463, // A1 = -1.920410
+ -32702, // A2 = 0.997986
+ 13346, // B2 = 0.407288
+ -12863, // B1 = -0.785126
+ 13346, // B0 = 0.407288
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f380_420[]
+ 30831, // A1 = 1.881775
+ -32064, // A2 = -0.978546
+ -367, // B2 = -0.01122
+ 0, // B1 = 0
+ 367, // B0 = 0.01122
+ 30813, // A1 = 1.880737
+ -32456, // A2 = -0.990509
+ 11068, // B2 = 0.337769
+ -10338, // B1 = -0.631042
+ 11068, // B0 = 0.337769
+ 31214, // A1 = 1.905212
+ -32491, // A2 = -0.991577
+ 16374, // B2 = 0.499695
+ -15781, // B1 = -0.963196
+ 16374, // B0 = 0.499695
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 392.txt
+ 31152, // A1 = -1.901428
+ -32613, // A2 = 0.995300
+ -314, // B2 = -0.009605
+ 0, // B1 = 0.000000
+ 314, // B0 = 0.009605
+ 31156, // A1 = -1.901672
+ -32694, // A2 = 0.997742
+ 28847, // B2 = 0.880371
+ -2734, // B1 = -0.166901
+ 28847, // B0 = 0.880371
+ 31225, // A1 = -1.905823
+ -32696, // A2 = 0.997803
+ 462, // B2 = 0.014108
+ -442, // B1 = -0.027019
+ 462, // B0 = 0.014108
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f400_425[]
+ 30836, // A1 = 1.882141
+ -32296, // A2 = -0.985596
+ -324, // B2 = -0.009903
+ 0, // B1 = 0
+ 324, // B0 = 0.009903
+ 30825, // A1 = 1.881409
+ -32570, // A2 = -0.993958
+ 16847, // B2 = 0.51416
+ -15792, // B1 = -0.963898
+ 16847, // B0 = 0.51416
+ 31106, // A1 = 1.89856
+ -32584, // A2 = -0.994415
+ 9579, // B2 = 0.292328
+ -9164, // B1 = -0.559357
+ 9579, // B0 = 0.292328
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f400_440[]
+ 30702, // A1 = 1.873962
+ -32134, // A2 = -0.980682
+ -517, // B2 = -0.015793
+ 0, // B1 = 0
+ 517, // B0 = 0.015793
+ 30676, // A1 = 1.872375
+ -32520, // A2 = -0.992462
+ 8144, // B2 = 0.24855
+ -7596, // B1 = -0.463684
+ 8144, // B0 = 0.24855
+ 31084, // A1 = 1.897217
+ -32547, // A2 = -0.993256
+ 22713, // B2 = 0.693176
+ -21734, // B1 = -1.326599
+ 22713, // B0 = 0.693176
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f400_450[]
+ 30613, // A1 = 1.86853
+ -32031, // A2 = -0.977509
+ -618, // B2 = -0.018866
+ 0, // B1 = 0
+ 618, // B0 = 0.018866
+ 30577, // A1 = 1.866272
+ -32491, // A2 = -0.991577
+ 9612, // B2 = 0.293335
+ -8935, // B1 = -0.54541
+ 9612, // B0 = 0.293335
+ 31071, // A1 = 1.896484
+ -32524, // A2 = -0.992584
+ 21596, // B2 = 0.659058
+ -20667, // B1 = -1.261414
+ 21596, // B0 = 0.659058
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 420.txt
+ 30914, // A1 = -1.886841
+ -32584, // A2 = 0.994385
+ -426, // B2 = -0.013020
+ 0, // B1 = 0.000000
+ 426, // B0 = 0.013020
+ 30914, // A1 = -1.886841
+ -32679, // A2 = 0.997314
+ 17520, // B2 = 0.534668
+ -16471, // B1 = -1.005310
+ 17520, // B0 = 0.534668
+ 31004, // A1 = -1.892334
+ -32683, // A2 = 0.997406
+ 819, // B2 = 0.025023
+ -780, // B1 = -0.047619
+ 819, // B0 = 0.025023
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 425.txt
+ 30881, // A1 = -1.884827
+ -32603, // A2 = 0.994965
+ -496, // B2 = -0.015144
+ 0, // B1 = 0.000000
+ 496, // B0 = 0.015144
+ 30880, // A1 = -1.884766
+ -32692, // A2 = 0.997711
+ 24767, // B2 = 0.755859
+ -23290, // B1 = -1.421509
+ 24767, // B0 = 0.755859
+ 30967, // A1 = -1.890076
+ -32694, // A2 = 0.997772
+ 728, // B2 = 0.022232
+ -691, // B1 = -0.042194
+ 728, // B0 = 0.022232
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f425_450[]
+ 30646, // A1 = 1.870544
+ -32327, // A2 = -0.986572
+ -287, // B2 = -0.008769
+ 0, // B1 = 0
+ 287, // B0 = 0.008769
+ 30627, // A1 = 1.869324
+ -32607, // A2 = -0.995087
+ 13269, // B2 = 0.404968
+ -12376, // B1 = -0.755432
+ 13269, // B0 = 0.404968
+ 30924, // A1 = 1.887512
+ -32619, // A2 = -0.995453
+ 19950, // B2 = 0.608826
+ -18940, // B1 = -1.156006
+ 19950, // B0 = 0.608826
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f425_475[]
+ 30396, // A1 = 1.855225
+ -32014, // A2 = -0.97699
+ -395, // B2 = -0.012055
+ 0, // B1 = 0
+ 395, // B0 = 0.012055
+ 30343, // A1 = 1.85199
+ -32482, // A2 = -0.991302
+ 17823, // B2 = 0.543945
+ -16431, // B1 = -1.002869
+ 17823, // B0 = 0.543945
+ 30872, // A1 = 1.884338
+ -32516, // A2 = -0.99231
+ 18124, // B2 = 0.553101
+ -17246, // B1 = -1.052673
+ 18124, // B0 = 0.553101
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 435.txt
+ 30796, // A1 = -1.879639
+ -32603, // A2 = 0.994965
+ -254, // B2 = -0.007762
+ 0, // B1 = 0.000000
+ 254, // B0 = 0.007762
+ 30793, // A1 = -1.879456
+ -32692, // A2 = 0.997711
+ 18934, // B2 = 0.577820
+ -17751, // B1 = -1.083496
+ 18934, // B0 = 0.577820
+ 30882, // A1 = -1.884888
+ -32694, // A2 = 0.997772
+ 1858, // B2 = 0.056713
+ -1758, // B1 = -0.107357
+ 1858, // B0 = 0.056713
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f440_450[]
+ 30641, // A1 = 1.870239
+ -32458, // A2 = -0.99057
+ -155, // B2 = -0.004735
+ 0, // B1 = 0
+ 155, // B0 = 0.004735
+ 30631, // A1 = 1.869568
+ -32630, // A2 = -0.995789
+ 11453, // B2 = 0.349548
+ -10666, // B1 = -0.651001
+ 11453, // B0 = 0.349548
+ 30810, // A1 = 1.880554
+ -32634, // A2 = -0.995941
+ 12237, // B2 = 0.373474
+ -11588, // B1 = -0.707336
+ 12237, // B0 = 0.373474
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f440_480[]
+ 30367, // A1 = 1.853455
+ -32147, // A2 = -0.981079
+ -495, // B2 = -0.015113
+ 0, // B1 = 0
+ 495, // B0 = 0.015113
+ 30322, // A1 = 1.850769
+ -32543, // A2 = -0.993134
+ 10031, // B2 = 0.306152
+ -9252, // B1 = -0.564728
+ 10031, // B0 = 0.306152
+ 30770, // A1 = 1.878052
+ -32563, // A2 = -0.993774
+ 22674, // B2 = 0.691956
+ -21465, // B1 = -1.31012
+ 22674, // B0 = 0.691956
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 445.txt
+ 30709, // A1 = -1.874329
+ -32603, // A2 = 0.994965
+ -83, // B2 = -0.002545
+ 0, // B1 = 0.000000
+ 83, // B0 = 0.002545
+ 30704, // A1 = -1.874084
+ -32692, // A2 = 0.997711
+ 10641, // B2 = 0.324738
+ -9947, // B1 = -0.607147
+ 10641, // B0 = 0.324738
+ 30796, // A1 = -1.879639
+ -32694, // A2 = 0.997772
+ 10079, // B2 = 0.307587
+ 9513, // B1 = 0.580688
+ 10079, // B0 = 0.307587
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 450.txt
+ 30664, // A1 = -1.871643
+ -32603, // A2 = 0.994965
+ -164, // B2 = -0.005029
+ 0, // B1 = 0.000000
+ 164, // B0 = 0.005029
+ 30661, // A1 = -1.871399
+ -32692, // A2 = 0.997711
+ 15294, // B2 = 0.466736
+ -14275, // B1 = -0.871307
+ 15294, // B0 = 0.466736
+ 30751, // A1 = -1.876953
+ -32694, // A2 = 0.997772
+ 3548, // B2 = 0.108284
+ -3344, // B1 = -0.204155
+ 3548, // B0 = 0.108284
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 452.txt
+ 30653, // A1 = -1.870911
+ -32615, // A2 = 0.995361
+ -209, // B2 = -0.006382
+ 0, // B1 = 0.000000
+ 209, // B0 = 0.006382
+ 30647, // A1 = -1.870605
+ -32702, // A2 = 0.997986
+ 18971, // B2 = 0.578979
+ -17716, // B1 = -1.081299
+ 18971, // B0 = 0.578979
+ 30738, // A1 = -1.876099
+ -32702, // A2 = 0.998016
+ 2967, // B2 = 0.090561
+ -2793, // B1 = -0.170502
+ 2967, // B0 = 0.090561
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 475.txt
+ 30437, // A1 = -1.857727
+ -32603, // A2 = 0.994965
+ -264, // B2 = -0.008062
+ 0, // B1 = 0.000000
+ 264, // B0 = 0.008062
+ 30430, // A1 = -1.857300
+ -32692, // A2 = 0.997711
+ 21681, // B2 = 0.661682
+ -20082, // B1 = -1.225708
+ 21681, // B0 = 0.661682
+ 30526, // A1 = -1.863220
+ -32694, // A2 = 0.997742
+ 1559, // B2 = 0.047600
+ -1459, // B1 = -0.089096
+ 1559, // B0 = 0.047600
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f480_620[]
+ 28975, // A1 = 1.768494
+ -30955, // A2 = -0.944672
+ -1026, // B2 = -0.03133
+ 0, // B1 = 0
+ 1026, // B0 = 0.03133
+ 28613, // A1 = 1.746399
+ -32089, // A2 = -0.979309
+ 14214, // B2 = 0.433807
+ -12202, // B1 = -0.744812
+ 14214, // B0 = 0.433807
+ 30243, // A1 = 1.845947
+ -32238, // A2 = -0.983856
+ 24825, // B2 = 0.757629
+ -23402, // B1 = -1.428345
+ 24825, // B0 = 0.757629
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 494.txt
+ 30257, // A1 = -1.846741
+ -32605, // A2 = 0.995056
+ -249, // B2 = -0.007625
+ 0, // B1 = 0.000000
+ 249, // B0 = 0.007625
+ 30247, // A1 = -1.846191
+ -32694, // A2 = 0.997772
+ 18088, // B2 = 0.552002
+ -16652, // B1 = -1.016418
+ 18088, // B0 = 0.552002
+ 30348, // A1 = -1.852295
+ -32696, // A2 = 0.997803
+ 2099, // B2 = 0.064064
+ -1953, // B1 = -0.119202
+ 2099, // B0 = 0.064064
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 500.txt
+ 30202, // A1 = -1.843431
+ -32624, // A2 = 0.995622
+ -413, // B2 = -0.012622
+ 0, // B1 = 0.000000
+ 413, // B0 = 0.012622
+ 30191, // A1 = -1.842721
+ -32714, // A2 = 0.998364
+ 25954, // B2 = 0.792057
+ -23890, // B1 = -1.458131
+ 25954, // B0 = 0.792057
+ 30296, // A1 = -1.849172
+ -32715, // A2 = 0.998397
+ 2007, // B2 = 0.061264
+ -1860, // B1 = -0.113568
+ 2007, // B0 = 0.061264
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 520.txt
+ 30001, // A1 = -1.831116
+ -32613, // A2 = 0.995270
+ -155, // B2 = -0.004750
+ 0, // B1 = 0.000000
+ 155, // B0 = 0.004750
+ 29985, // A1 = -1.830200
+ -32710, // A2 = 0.998260
+ 6584, // B2 = 0.200928
+ -6018, // B1 = -0.367355
+ 6584, // B0 = 0.200928
+ 30105, // A1 = -1.837524
+ -32712, // A2 = 0.998291
+ 23812, // B2 = 0.726685
+ -21936, // B1 = -1.338928
+ 23812, // B0 = 0.726685
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 523.txt
+ 29964, // A1 = -1.828918
+ -32601, // A2 = 0.994904
+ -101, // B2 = -0.003110
+ 0, // B1 = 0.000000
+ 101, // B0 = 0.003110
+ 29949, // A1 = -1.827942
+ -32700, // A2 = 0.997925
+ 11041, // B2 = 0.336975
+ -10075, // B1 = -0.614960
+ 11041, // B0 = 0.336975
+ 30070, // A1 = -1.835388
+ -32702, // A2 = 0.997986
+ 16762, // B2 = 0.511536
+ -15437, // B1 = -0.942230
+ 16762, // B0 = 0.511536
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 525.txt
+ 29936, // A1 = -1.827209
+ -32584, // A2 = 0.994415
+ -91, // B2 = -0.002806
+ 0, // B1 = 0.000000
+ 91, // B0 = 0.002806
+ 29921, // A1 = -1.826233
+ -32688, // A2 = 0.997559
+ 11449, // B2 = 0.349396
+ -10426, // B1 = -0.636383
+ 11449, // B0 = 0.349396
+ 30045, // A1 = -1.833862
+ -32688, // A2 = 0.997589
+ 13055, // B2 = 0.398407
+ -12028, // B1 = -0.734161
+ 13055, // B0 = 0.398407
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f540_660[]
+ 28499, // A1 = 1.739441
+ -31129, // A2 = -0.949982
+ -849, // B2 = -0.025922
+ 0, // B1 = 0
+ 849, // B0 = 0.025922
+ 28128, // A1 = 1.716797
+ -32130, // A2 = -0.98056
+ 14556, // B2 = 0.444214
+ -12251, // B1 = -0.747772
+ 14556, // B0 = 0.444244
+ 29667, // A1 = 1.81073
+ -32244, // A2 = -0.984039
+ 23038, // B2 = 0.703064
+ -21358, // B1 = -1.303589
+ 23040, // B0 = 0.703125
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 587.txt
+ 29271, // A1 = -1.786560
+ -32599, // A2 = 0.994873
+ -490, // B2 = -0.014957
+ 0, // B1 = 0.000000
+ 490, // B0 = 0.014957
+ 29246, // A1 = -1.785095
+ -32700, // A2 = 0.997925
+ 28961, // B2 = 0.883850
+ -25796, // B1 = -1.574463
+ 28961, // B0 = 0.883850
+ 29383, // A1 = -1.793396
+ -32700, // A2 = 0.997955
+ 1299, // B2 = 0.039650
+ -1169, // B1 = -0.071396
+ 1299, // B0 = 0.039650
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 590.txt
+ 29230, // A1 = -1.784058
+ -32584, // A2 = 0.994415
+ -418, // B2 = -0.012757
+ 0, // B1 = 0.000000
+ 418, // B0 = 0.012757
+ 29206, // A1 = -1.782593
+ -32688, // A2 = 0.997559
+ 36556, // B2 = 1.115601
+ -32478, // B1 = -1.982300
+ 36556, // B0 = 1.115601
+ 29345, // A1 = -1.791077
+ -32688, // A2 = 0.997589
+ 897, // B2 = 0.027397
+ -808, // B1 = -0.049334
+ 897, // B0 = 0.027397
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 600.txt
+ 29116, // A1 = -1.777100
+ -32603, // A2 = 0.994965
+ -165, // B2 = -0.005039
+ 0, // B1 = 0.000000
+ 165, // B0 = 0.005039
+ 29089, // A1 = -1.775452
+ -32708, // A2 = 0.998199
+ 6963, // B2 = 0.212494
+ -6172, // B1 = -0.376770
+ 6963, // B0 = 0.212494
+ 29237, // A1 = -1.784485
+ -32710, // A2 = 0.998230
+ 24197, // B2 = 0.738464
+ -21657, // B1 = -1.321899
+ 24197, // B0 = 0.738464
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 660.txt
+ 28376, // A1 = -1.731934
+ -32567, // A2 = 0.993896
+ -363, // B2 = -0.011102
+ 0, // B1 = 0.000000
+ 363, // B0 = 0.011102
+ 28337, // A1 = -1.729614
+ -32683, // A2 = 0.997434
+ 21766, // B2 = 0.664246
+ -18761, // B1 = -1.145081
+ 21766, // B0 = 0.664246
+ 28513, // A1 = -1.740356
+ -32686, // A2 = 0.997498
+ 2509, // B2 = 0.076584
+ -2196, // B1 = -0.134041
+ 2509, // B0 = 0.076584
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 700.txt
+ 27844, // A1 = -1.699463
+ -32563, // A2 = 0.993744
+ -366, // B2 = -0.011187
+ 0, // B1 = 0.000000
+ 366, // B0 = 0.011187
+ 27797, // A1 = -1.696655
+ -32686, // A2 = 0.997498
+ 22748, // B2 = 0.694214
+ -19235, // B1 = -1.174072
+ 22748, // B0 = 0.694214
+ 27995, // A1 = -1.708740
+ -32688, // A2 = 0.997559
+ 2964, // B2 = 0.090477
+ -2546, // B1 = -0.155449
+ 2964, // B0 = 0.090477
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 740.txt
+ 27297, // A1 = -1.666077
+ -32551, // A2 = 0.993408
+ -345, // B2 = -0.010540
+ 0, // B1 = 0.000000
+ 345, // B0 = 0.010540
+ 27240, // A1 = -1.662598
+ -32683, // A2 = 0.997406
+ 22560, // B2 = 0.688477
+ -18688, // B1 = -1.140625
+ 22560, // B0 = 0.688477
+ 27461, // A1 = -1.676147
+ -32684, // A2 = 0.997467
+ 3541, // B2 = 0.108086
+ -2985, // B1 = -0.182220
+ 3541, // B0 = 0.108086
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 750.txt
+ 27155, // A1 = -1.657410
+ -32551, // A2 = 0.993408
+ -462, // B2 = -0.014117
+ 0, // B1 = 0.000000
+ 462, // B0 = 0.014117
+ 27097, // A1 = -1.653870
+ -32683, // A2 = 0.997406
+ 32495, // B2 = 0.991699
+ -26776, // B1 = -1.634338
+ 32495, // B0 = 0.991699
+ 27321, // A1 = -1.667542
+ -32684, // A2 = 0.997467
+ 1835, // B2 = 0.056007
+ -1539, // B1 = -0.093948
+ 1835, // B0 = 0.056007
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f750_1450[]
+ 19298, // A1 = 1.177917
+ -24471, // A2 = -0.746796
+ -4152, // B2 = -0.126709
+ 0, // B1 = 0
+ 4152, // B0 = 0.126709
+ 12902, // A1 = 0.787476
+ -29091, // A2 = -0.887817
+ 12491, // B2 = 0.38121
+ -1794, // B1 = -0.109528
+ 12494, // B0 = 0.381317
+ 26291, // A1 = 1.604736
+ -30470, // A2 = -0.929901
+ 28859, // B2 = 0.880737
+ -26084, // B1 = -1.592102
+ 28861, // B0 = 0.880798
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 770.txt
+ 26867, // A1 = -1.639832
+ -32551, // A2 = 0.993408
+ -123, // B2 = -0.003755
+ 0, // B1 = 0.000000
+ 123, // B0 = 0.003755
+ 26805, // A1 = -1.636108
+ -32683, // A2 = 0.997406
+ 17297, // B2 = 0.527863
+ -14096, // B1 = -0.860382
+ 17297, // B0 = 0.527863
+ 27034, // A1 = -1.650085
+ -32684, // A2 = 0.997467
+ 12958, // B2 = 0.395477
+ -10756, // B1 = -0.656525
+ 12958, // B0 = 0.395477
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 800.txt
+ 26413, // A1 = -1.612122
+ -32547, // A2 = 0.993286
+ -223, // B2 = -0.006825
+ 0, // B1 = 0.000000
+ 223, // B0 = 0.006825
+ 26342, // A1 = -1.607849
+ -32686, // A2 = 0.997498
+ 6391, // B2 = 0.195053
+ -5120, // B1 = -0.312531
+ 6391, // B0 = 0.195053
+ 26593, // A1 = -1.623108
+ -32688, // A2 = 0.997559
+ 23681, // B2 = 0.722717
+ -19328, // B1 = -1.179688
+ 23681, // B0 = 0.722717
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 816.txt
+ 26168, // A1 = -1.597209
+ -32528, // A2 = 0.992706
+ -235, // B2 = -0.007182
+ 0, // B1 = 0.000000
+ 235, // B0 = 0.007182
+ 26092, // A1 = -1.592590
+ -32675, // A2 = 0.997192
+ 20823, // B2 = 0.635498
+ -16510, // B1 = -1.007751
+ 20823, // B0 = 0.635498
+ 26363, // A1 = -1.609070
+ -32677, // A2 = 0.997253
+ 6739, // B2 = 0.205688
+ -5459, // B1 = -0.333206
+ 6739, // B0 = 0.205688
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 850.txt
+ 25641, // A1 = -1.565063
+ -32536, // A2 = 0.992950
+ -121, // B2 = -0.003707
+ 0, // B1 = 0.000000
+ 121, // B0 = 0.003707
+ 25560, // A1 = -1.560059
+ -32684, // A2 = 0.997437
+ 18341, // B2 = 0.559753
+ -14252, // B1 = -0.869904
+ 18341, // B0 = 0.559753
+ 25837, // A1 = -1.577026
+ -32684, // A2 = 0.997467
+ 16679, // B2 = 0.509003
+ -13232, // B1 = -0.807648
+ 16679, // B0 = 0.509003
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f857_1645[]
+ 16415, // A1 = 1.001953
+ -23669, // A2 = -0.722321
+ -4549, // B2 = -0.138847
+ 0, // B1 = 0
+ 4549, // B0 = 0.138847
+ 8456, // A1 = 0.516174
+ -28996, // A2 = -0.884918
+ 13753, // B2 = 0.419724
+ -12, // B1 = -0.000763
+ 13757, // B0 = 0.419846
+ 24632, // A1 = 1.503418
+ -30271, // A2 = -0.923828
+ 29070, // B2 = 0.887146
+ -25265, // B1 = -1.542114
+ 29073, // B0 = 0.887268
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 900.txt
+ 24806, // A1 = -1.514099
+ -32501, // A2 = 0.991852
+ -326, // B2 = -0.009969
+ 0, // B1 = 0.000000
+ 326, // B0 = 0.009969
+ 24709, // A1 = -1.508118
+ -32659, // A2 = 0.996674
+ 20277, // B2 = 0.618835
+ -15182, // B1 = -0.926636
+ 20277, // B0 = 0.618835
+ 25022, // A1 = -1.527222
+ -32661, // A2 = 0.996735
+ 4320, // B2 = 0.131836
+ -3331, // B1 = -0.203339
+ 4320, // B0 = 0.131836
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f900_1300[]
+ 19776, // A1 = 1.207092
+ -27437, // A2 = -0.837341
+ -2666, // B2 = -0.081371
+ 0, // B1 = 0
+ 2666, // B0 = 0.081371
+ 16302, // A1 = 0.995026
+ -30354, // A2 = -0.926361
+ 10389, // B2 = 0.317062
+ -3327, // B1 = -0.203064
+ 10389, // B0 = 0.317062
+ 24299, // A1 = 1.483154
+ -30930, // A2 = -0.943909
+ 25016, // B2 = 0.763428
+ -21171, // B1 = -1.292236
+ 25016, // B0 = 0.763428
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f935_1215[]
+ 20554, // A1 = 1.254517
+ -28764, // A2 = -0.877838
+ -2048, // B2 = -0.062515
+ 0, // B1 = 0
+ 2048, // B0 = 0.062515
+ 18209, // A1 = 1.11145
+ -30951, // A2 = -0.94458
+ 9390, // B2 = 0.286575
+ -3955, // B1 = -0.241455
+ 9390, // B0 = 0.286575
+ 23902, // A1 = 1.458923
+ -31286, // A2 = -0.954803
+ 23252, // B2 = 0.709595
+ -19132, // B1 = -1.167725
+ 23252, // B0 = 0.709595
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f941_1477[]
+ 17543, // A1 = 1.07074
+ -26220, // A2 = -0.800201
+ -3298, // B2 = -0.100647
+ 0, // B1 = 0
+ 3298, // B0 = 0.100647
+ 12423, // A1 = 0.75827
+ -30036, // A2 = -0.916626
+ 12651, // B2 = 0.386078
+ -2444, // B1 = -0.14917
+ 12653, // B0 = 0.386154
+ 23518, // A1 = 1.435425
+ -30745, // A2 = -0.938293
+ 27282, // B2 = 0.832581
+ -22529, // B1 = -1.375122
+ 27286, // B0 = 0.832703
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 942.txt
+ 24104, // A1 = -1.471252
+ -32507, // A2 = 0.992065
+ -351, // B2 = -0.010722
+ 0, // B1 = 0.000000
+ 351, // B0 = 0.010722
+ 23996, // A1 = -1.464600
+ -32671, // A2 = 0.997040
+ 22848, // B2 = 0.697266
+ -16639, // B1 = -1.015564
+ 22848, // B0 = 0.697266
+ 24332, // A1 = -1.485168
+ -32673, // A2 = 0.997101
+ 4906, // B2 = 0.149727
+ -3672, // B1 = -0.224174
+ 4906, // B0 = 0.149727
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 950.txt
+ 23967, // A1 = -1.462830
+ -32507, // A2 = 0.992065
+ -518, // B2 = -0.015821
+ 0, // B1 = 0.000000
+ 518, // B0 = 0.015821
+ 23856, // A1 = -1.456055
+ -32671, // A2 = 0.997040
+ 26287, // B2 = 0.802246
+ -19031, // B1 = -1.161560
+ 26287, // B0 = 0.802246
+ 24195, // A1 = -1.476746
+ -32673, // A2 = 0.997101
+ 2890, // B2 = 0.088196
+ -2151, // B1 = -0.131317
+ 2890, // B0 = 0.088196
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f950_1400[]
+ 18294, // A1 = 1.116638
+ -26962, // A2 = -0.822845
+ -2914, // B2 = -0.088936
+ 0, // B1 = 0
+ 2914, // B0 = 0.088936
+ 14119, // A1 = 0.861786
+ -30227, // A2 = -0.922455
+ 11466, // B2 = 0.349945
+ -2833, // B1 = -0.172943
+ 11466, // B0 = 0.349945
+ 23431, // A1 = 1.430115
+ -30828, // A2 = -0.940796
+ 25331, // B2 = 0.773071
+ -20911, // B1 = -1.276367
+ 25331, // B0 = 0.773071
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 975.txt
+ 23521, // A1 = -1.435608
+ -32489, // A2 = 0.991516
+ -193, // B2 = -0.005915
+ 0, // B1 = 0.000000
+ 193, // B0 = 0.005915
+ 23404, // A1 = -1.428467
+ -32655, // A2 = 0.996582
+ 17740, // B2 = 0.541412
+ -12567, // B1 = -0.767029
+ 17740, // B0 = 0.541412
+ 23753, // A1 = -1.449829
+ -32657, // A2 = 0.996613
+ 9090, // B2 = 0.277405
+ -6662, // B1 = -0.406647
+ 9090, // B0 = 0.277405
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1000.txt
+ 23071, // A1 = -1.408203
+ -32489, // A2 = 0.991516
+ -293, // B2 = -0.008965
+ 0, // B1 = 0.000000
+ 293, // B0 = 0.008965
+ 22951, // A1 = -1.400818
+ -32655, // A2 = 0.996582
+ 5689, // B2 = 0.173645
+ -3951, // B1 = -0.241150
+ 5689, // B0 = 0.173645
+ 23307, // A1 = -1.422607
+ -32657, // A2 = 0.996613
+ 18692, // B2 = 0.570435
+ -13447, // B1 = -0.820770
+ 18692, // B0 = 0.570435
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1020.txt
+ 22701, // A1 = -1.385620
+ -32474, // A2 = 0.991058
+ -292, // B2 = -0.008933
+ 0, //163840 , // B1 = 10.000000
+ 292, // B0 = 0.008933
+ 22564, // A1 = -1.377258
+ -32655, // A2 = 0.996552
+ 20756, // B2 = 0.633423
+ -14176, // B1 = -0.865295
+ 20756, // B0 = 0.633423
+ 22960, // A1 = -1.401428
+ -32657, // A2 = 0.996613
+ 6520, // B2 = 0.198990
+ -4619, // B1 = -0.281937
+ 6520, // B0 = 0.198990
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1050.txt
+ 22142, // A1 = -1.351501
+ -32474, // A2 = 0.991058
+ -147, // B2 = -0.004493
+ 0, // B1 = 0.000000
+ 147, // B0 = 0.004493
+ 22000, // A1 = -1.342834
+ -32655, // A2 = 0.996552
+ 15379, // B2 = 0.469360
+ -10237, // B1 = -0.624847
+ 15379, // B0 = 0.469360
+ 22406, // A1 = -1.367554
+ -32657, // A2 = 0.996613
+ 17491, // B2 = 0.533783
+ -12096, // B1 = -0.738312
+ 17491, // B0 = 0.533783
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f1100_1750[]
+ 12973, // A1 = 0.79184
+ -24916, // A2 = -0.760376
+ 6655, // B2 = 0.203102
+ 367, // B1 = 0.0224
+ 6657, // B0 = 0.203171
+ 5915, // A1 = 0.361053
+ -29560, // A2 = -0.90213
+ -7777, // B2 = -0.23735
+ 0, // B1 = 0
+ 7777, // B0 = 0.23735
+ 20510, // A1 = 1.251892
+ -30260, // A2 = -0.923462
+ 26662, // B2 = 0.81366
+ -20573, // B1 = -1.255737
+ 26668, // B0 = 0.813843
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1140.txt
+ 20392, // A1 = -1.244629
+ -32460, // A2 = 0.990601
+ -270, // B2 = -0.008240
+ 0, // B1 = 0.000000
+ 270, // B0 = 0.008240
+ 20218, // A1 = -1.234009
+ -32655, // A2 = 0.996582
+ 21337, // B2 = 0.651154
+ -13044, // B1 = -0.796143
+ 21337, // B0 = 0.651154
+ 20684, // A1 = -1.262512
+ -32657, // A2 = 0.996643
+ 8572, // B2 = 0.261612
+ -5476, // B1 = -0.334244
+ 8572, // B0 = 0.261612
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1200.txt
+ 19159, // A1 = -1.169373
+ -32456, // A2 = 0.990509
+ -335, // B2 = -0.010252
+ 0, // B1 = 0.000000
+ 335, // B0 = 0.010252
+ 18966, // A1 = -1.157593
+ -32661, // A2 = 0.996735
+ 6802, // B2 = 0.207588
+ -3900, // B1 = -0.238098
+ 6802, // B0 = 0.207588
+ 19467, // A1 = -1.188232
+ -32661, // A2 = 0.996765
+ 25035, // B2 = 0.764008
+ -15049, // B1 = -0.918579
+ 25035, // B0 = 0.764008
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1209.txt
+ 18976, // A1 = -1.158264
+ -32439, // A2 = 0.989990
+ -183, // B2 = -0.005588
+ 0, // B1 = 0.000000
+ 183, // B0 = 0.005588
+ 18774, // A1 = -1.145874
+ -32650, // A2 = 0.996429
+ 15468, // B2 = 0.472076
+ -8768, // B1 = -0.535217
+ 15468, // B0 = 0.472076
+ 19300, // A1 = -1.177979
+ -32652, // A2 = 0.996490
+ 19840, // B2 = 0.605499
+ -11842, // B1 = -0.722809
+ 19840, // B0 = 0.605499
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1330.txt
+ 16357, // A1 = -0.998413
+ -32368, // A2 = 0.987793
+ -217, // B2 = -0.006652
+ 0, // B1 = 0.000000
+ 217, // B0 = 0.006652
+ 16107, // A1 = -0.983126
+ -32601, // A2 = 0.994904
+ 11602, // B2 = 0.354065
+ -5555, // B1 = -0.339111
+ 11602, // B0 = 0.354065
+ 16722, // A1 = -1.020630
+ -32603, // A2 = 0.994965
+ 15574, // B2 = 0.475311
+ -8176, // B1 = -0.499069
+ 15574, // B0 = 0.475311
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1336.txt
+ 16234, // A1 = -0.990875
+ 32404, // A2 = -0.988922
+ -193, // B2 = -0.005908
+ 0, // B1 = 0.000000
+ 193, // B0 = 0.005908
+ 15986, // A1 = -0.975769
+ -32632, // A2 = 0.995880
+ 18051, // B2 = 0.550903
+ -8658, // B1 = -0.528473
+ 18051, // B0 = 0.550903
+ 16591, // A1 = -1.012695
+ -32634, // A2 = 0.995941
+ 15736, // B2 = 0.480240
+ -8125, // B1 = -0.495926
+ 15736, // B0 = 0.480240
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1366.txt
+ 15564, // A1 = -0.949982
+ -32404, // A2 = 0.988922
+ -269, // B2 = -0.008216
+ 0, // B1 = 0.000000
+ 269, // B0 = 0.008216
+ 15310, // A1 = -0.934479
+ -32632, // A2 = 0.995880
+ 10815, // B2 = 0.330063
+ -4962, // B1 = -0.302887
+ 10815, // B0 = 0.330063
+ 15924, // A1 = -0.971924
+ -32634, // A2 = 0.995941
+ 18880, // B2 = 0.576172
+ -9364, // B1 = -0.571594
+ 18880, // B0 = 0.576172
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1380.txt
+ 15247, // A1 = -0.930603
+ -32397, // A2 = 0.988708
+ -244, // B2 = -0.007451
+ 0, // B1 = 0.000000
+ 244, // B0 = 0.007451
+ 14989, // A1 = -0.914886
+ -32627, // A2 = 0.995697
+ 18961, // B2 = 0.578644
+ -8498, // B1 = -0.518707
+ 18961, // B0 = 0.578644
+ 15608, // A1 = -0.952667
+ -32628, // A2 = 0.995758
+ 11145, // B2 = 0.340134
+ -5430, // B1 = -0.331467
+ 11145, // B0 = 0.340134
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1400.txt
+ 14780, // A1 = -0.902130
+ -32393, // A2 = 0.988586
+ -396, // B2 = -0.012086
+ 0, // B1 = 0.000000
+ 396, // B0 = 0.012086
+ 14510, // A1 = -0.885651
+ -32630, // A2 = 0.995819
+ 6326, // B2 = 0.193069
+ -2747, // B1 = -0.167671
+ 6326, // B0 = 0.193069
+ 15154, // A1 = -0.924957
+ -32632, // A2 = 0.995850
+ 23235, // B2 = 0.709076
+ -10983, // B1 = -0.670380
+ 23235, // B0 = 0.709076
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1477.txt
+ 13005, // A1 = -0.793793
+ -32368, // A2 = 0.987823
+ -500, // B2 = -0.015265
+ 0, // B1 = 0.000000
+ 500, // B0 = 0.015265
+ 12708, // A1 = -0.775665
+ -32615, // A2 = 0.995331
+ 11420, // B2 = 0.348526
+ -4306, // B1 = -0.262833
+ 11420, // B0 = 0.348526
+ 13397, // A1 = -0.817688
+ -32615, // A2 = 0.995361
+ 9454, // B2 = 0.288528
+ -3981, // B1 = -0.243027
+ 9454, // B0 = 0.288528
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1600.txt
+ 10046, // A1 = -0.613190
+ -32331, // A2 = 0.986694
+ -455, // B2 = -0.013915
+ 0, // B1 = 0.000000
+ 455, // B0 = 0.013915
+ 9694, // A1 = -0.591705
+ -32601, // A2 = 0.994934
+ 6023, // B2 = 0.183815
+ -1708, // B1 = -0.104279
+ 6023, // B0 = 0.183815
+ 10478, // A1 = -0.639587
+ -32603, // A2 = 0.994965
+ 22031, // B2 = 0.672333
+ -7342, // B1 = -0.448151
+ 22031, // B0 = 0.672333
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // f1633_1638[]
+ 9181, // A1 = 0.560394
+ -32256, // A2 = -0.984375
+ -556, // B2 = -0.016975
+ 0, // B1 = 0
+ 556, // B0 = 0.016975
+ 8757, // A1 = 0.534515
+ -32574, // A2 = -0.99408
+ 8443, // B2 = 0.25769
+ -2135, // B1 = -0.130341
+ 8443, // B0 = 0.25769
+ 9691, // A1 = 0.591522
+ -32574, // A2 = -0.99411
+ 15446, // B2 = 0.471375
+ -4809, // B1 = -0.293579
+ 15446, // B0 = 0.471375
+ 7, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1800.txt
+ 5076, // A1 = -0.309875
+ -32304, // A2 = 0.985840
+ -508, // B2 = -0.015503
+ 0, // B1 = 0.000000
+ 508, // B0 = 0.015503
+ 4646, // A1 = -0.283600
+ -32605, // A2 = 0.995026
+ 6742, // B2 = 0.205780
+ -878, // B1 = -0.053635
+ 6742, // B0 = 0.205780
+ 5552, // A1 = -0.338928
+ -32605, // A2 = 0.995056
+ 23667, // B2 = 0.722260
+ -4297, // B1 = -0.262329
+ 23667, // B0 = 0.722260
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },
+ { // 1860.txt
+ 3569, // A1 = -0.217865
+ -32292, // A2 = 0.985504
+ -239, // B2 = -0.007322
+ 0, // B1 = 0.000000
+ 239, // B0 = 0.007322
+ 3117, // A1 = -0.190277
+ -32603, // A2 = 0.994965
+ 18658, // B2 = 0.569427
+ -1557, // B1 = -0.095032
+ 18658, // B0 = 0.569427
+ 4054, // A1 = -0.247437
+ -32603, // A2 = 0.994965
+ 18886, // B2 = 0.576385
+ -2566, // B1 = -0.156647
+ 18886, // B0 = 0.576385
+ 5, // Internal filter scaling
+ 159, // Minimum in-band energy threshold
+ 21, // 21/32 in-band to broad-band ratio
+ 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5
+ },};
+
+static int ixj_init_filter(int board, IXJ_FILTER * jf)
+{
+ unsigned short cmd;
+ int cnt, max;
+ IXJ *j = &ixj[board];
+
+ if (jf->filter > 3) {
+ return -1;
+ }
+ if (ixj_WriteDSPCommand(0x5154 + jf->filter, board)) // Select Filter
+
+ return -1;
+
+ if (!jf->enable) {
+ if (ixj_WriteDSPCommand(0x5152, board)) // Disable Filter
+
+ return -1;
+ else
+ return 0;
+ } else {
+ if (ixj_WriteDSPCommand(0x5153, board)) // Enable Filter
+
+ return -1;
+
+ // Select the filter (f0 - f3) to use.
+ if (ixj_WriteDSPCommand(0x5154 + jf->filter, board))
+ return -1;
+ }
+ if (jf->freq < 12 && jf->freq > 3) {
+ // Select the frequency for the selected filter.
+ if (ixj_WriteDSPCommand(0x5170 + jf->freq, board))
+ return -1;
+ } else if (jf->freq > 11) {
+ // We need to load a programmable filter set for undefined
+ // frequencies. So we will point the filter to a programmable set.
+ // Since there are only 4 filters and 4 programmable sets, we will
+ // just point the filter to the same number set and program it for the
+ // frequency we want.
+ if (ixj_WriteDSPCommand(0x5170 + jf->filter, board))
+ return -1;
+
+ if (j->ver.low != 0x12) {
+ cmd = 0x515B;
+ max = 19;
+ } else {
+ cmd = 0x515E;
+ max = 15;
+ }
+ if (ixj_WriteDSPCommand(cmd, board))
+ return -1;
+
+ for (cnt = 0; cnt < max; cnt++) {
+ if (ixj_WriteDSPCommand(tone_table[jf->freq][cnt], board))
+ return -1;
+ }
+/* if(j->ver.low != 0x12)
+ {
+ if(ixj_WriteDSPCommand(7, board))
+ return -1;
+ if(ixj_WriteDSPCommand(159, board))
+ return -1;
+ if(ixj_WriteDSPCommand(21, board))
+ return -1;
+ if(ixj_WriteDSPCommand(0x0FF5, board))
+ return -1;
+ } */
+ }
+ return 0;
+}
+
+static int ixj_init_tone(int board, IXJ_TONE * ti)
+{
+ int freq0, freq1;
+ unsigned short data;
+
+ if (ti->freq0) {
+ freq0 = ti->freq0;
+ } else {
+ freq0 = 0x7FFF;
+ }
+
+ if (ti->freq1) {
+ freq1 = ti->freq1;
+ } else {
+ freq1 = 0x7FFF;
+ }
+
+// if(ti->tone_index > 12 && ti->tone_index < 28)
+ {
+ if (ixj_WriteDSPCommand(0x6800 + ti->tone_index, board))
+ return -1;
+
+ if (ixj_WriteDSPCommand(0x6000 + (ti->gain0 << 4) + ti->gain1, board))
+ return -1;
+
+ data = freq0;
+ if (ixj_WriteDSPCommand(data, board))
+ return -1;
+
+ data = freq1;
+ if (ixj_WriteDSPCommand(data, board))
+ return -1;
+ }
+ return freq0;
+}
--- /dev/null
+/*
+ * ixj.h
+ *
+ * Device Driver for the Internet PhoneJACK and
+ * Internet LineJACK Telephony Cards.
+ *
+ * (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Author: Ed Okerson, <eokerson@quicknet.net>
+ *
+ * Contributors: Greg Herlein, <gherlein@quicknet.net>
+ * David W. Erhart, <derhart@quicknet.net>
+ * John Sellers, <jsellers@quicknet.net>
+ * Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website: http://www.quicknet.net
+ *
+ * Fixes:
+ * Linux 2.3 port, Alan Cox
+ */
+static char ixj_h_rcsid[] = "$Id: ixj.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#ifndef _I386_TYPES_H
+#include <asm/types.h>
+#endif
+
+#include <linux/ixjuser.h>
+#include <linux/phonedev.h>
+
+typedef __u16 WORD;
+typedef __u32 DWORD;
+typedef __u8 BYTE;
+typedef __u8 BOOL;
+
+#define IXJMAX 16
+
+#define TRUE 1
+#define FALSE 0
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/******************************************************************************
+*
+* This structure when unioned with the structures below makes simple byte
+* access to the registers easier.
+*
+******************************************************************************/
+typedef struct {
+ unsigned char low;
+ unsigned char high;
+} BYTES;
+
+int ixj_WriteDSPCommand(unsigned short, int board);
+
+/******************************************************************************
+*
+* This structure represents the Hardware Control Register of the CT8020/8021
+* The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+* Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+ unsigned int rxrdy:1;
+ unsigned int txrdy:1;
+ unsigned int status:1;
+ unsigned int auxstatus:1;
+ unsigned int rxdma:1;
+ unsigned int txdma:1;
+ unsigned int rxburst:1;
+ unsigned int txburst:1;
+ unsigned int dmadir:1;
+ unsigned int cont:1;
+ unsigned int irqn:1;
+ unsigned int t:5;
+} HCRBIT;
+
+typedef union {
+ HCRBIT bits;
+ BYTES bytes;
+} HCR;
+
+/******************************************************************************
+*
+* This structure represents the Hardware Status Register of the CT8020/8021
+* The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+* Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+ unsigned int controlrdy:1;
+ unsigned int auxctlrdy:1;
+ unsigned int statusrdy:1;
+ unsigned int auxstatusrdy:1;
+ unsigned int rxrdy:1;
+ unsigned int txrdy:1;
+ unsigned int restart:1;
+ unsigned int irqn:1;
+ unsigned int rxdma:1;
+ unsigned int txdma:1;
+ unsigned int cohostshutdown:1;
+ unsigned int t:5;
+} HSRBIT;
+
+typedef union {
+ HSRBIT bits;
+ BYTES bytes;
+} HSR;
+
+/******************************************************************************
+*
+* This structure represents the General Purpose IO Register of the CT8020/8021
+* The CT8020 is used in the Internet PhoneJACK, and the 8021 in the
+* Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+ unsigned int x:1;
+ unsigned int gpio1:1;
+ unsigned int gpio2:1;
+ unsigned int gpio3:1;
+ unsigned int gpio4:1;
+ unsigned int gpio5:1;
+ unsigned int gpio6:1;
+ unsigned int gpio7:1;
+ unsigned int xread:1;
+ unsigned int gpio1read:1;
+ unsigned int gpio2read:1;
+ unsigned int gpio3read:1;
+ unsigned int gpio4read:1;
+ unsigned int gpio5read:1;
+ unsigned int gpio6read:1;
+ unsigned int gpio7read:1;
+} GPIOBIT;
+
+typedef union {
+ GPIOBIT bits;
+ BYTES bytes;
+ unsigned short word;
+} GPIO;
+
+/******************************************************************************
+*
+* This structure represents the Line Monitor status response
+*
+******************************************************************************/
+typedef struct {
+ unsigned int digit:4;
+ unsigned int cpf_valid:1;
+ unsigned int dtmf_valid:1;
+ unsigned int peak:1;
+ unsigned int z:1;
+ unsigned int f0:1;
+ unsigned int f1:1;
+ unsigned int f2:1;
+ unsigned int f3:1;
+ unsigned int frame:4;
+} LMON;
+
+typedef union {
+ LMON bits;
+ BYTES bytes;
+} DTMF;
+
+typedef struct {
+ unsigned int z:7;
+ unsigned int dtmf_en:1;
+ unsigned int y:4;
+ unsigned int F3:1;
+ unsigned int F2:1;
+ unsigned int F1:1;
+ unsigned int F0:1;
+} CP;
+
+typedef union {
+ CP bits;
+ BYTES bytes;
+} CPTF;
+
+/******************************************************************************
+*
+* This structure represents the Status Control Register on the Internet
+* LineJACK
+*
+******************************************************************************/
+typedef struct {
+ unsigned int c0:1;
+ unsigned int c1:1;
+ unsigned int stereo:1;
+ unsigned int daafsyncen:1;
+ unsigned int led1:1;
+ unsigned int led2:1;
+ unsigned int led3:1;
+ unsigned int led4:1;
+} PSCRWI; // Internet LineJACK and Internet PhoneJACK Lite
+
+typedef struct {
+ unsigned int eidp:1;
+ unsigned int eisd:1;
+ unsigned int x:6;
+} PSCRWP; // Internet PhoneJACK PCI
+
+typedef union {
+ PSCRWI bits;
+ PSCRWP pcib;
+ char byte;
+} PLD_SCRW;
+
+typedef struct {
+ unsigned int c0:1;
+ unsigned int c1:1;
+ unsigned int x:1;
+ unsigned int d0ee:1;
+ unsigned int mixerbusy:1;
+ unsigned int sci:1;
+ unsigned int dspflag:1;
+ unsigned int daaflag:1;
+} PSCRRI;
+
+typedef struct {
+ unsigned int eidp:1;
+ unsigned int eisd:1;
+ unsigned int x:4;
+ unsigned int dspflag:1;
+ unsigned int det:1;
+} PSCRRP;
+
+typedef union {
+ PSCRRI bits;
+ PSCRRP pcib;
+ char byte;
+} PLD_SCRR;
+
+/******************************************************************************
+*
+* These structures represents the SLIC Control Register on the
+* Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+ unsigned int c1:1;
+ unsigned int c2:1;
+ unsigned int c3:1;
+ unsigned int b2en:1;
+ unsigned int spken:1;
+ unsigned int rly1:1;
+ unsigned int rly2:1;
+ unsigned int rly3:1;
+} PSLICWRITE;
+
+typedef struct {
+ unsigned int state:3;
+ unsigned int b2en:1;
+ unsigned int spken:1;
+ unsigned int c3:1;
+ unsigned int potspstn:1;
+ unsigned int det:1;
+} PSLICREAD;
+
+typedef struct {
+ unsigned int c1:1;
+ unsigned int c2:1;
+ unsigned int c3:1;
+ unsigned int b2en:1;
+ unsigned int e1:1;
+ unsigned int mic:1;
+ unsigned int spk:1;
+ unsigned int x:1;
+} PSLICPCI;
+
+typedef union {
+ PSLICPCI pcib;
+ PSLICWRITE bits;
+ PSLICREAD slic;
+ char byte;
+} PLD_SLICW;
+
+typedef union {
+ PSLICPCI pcib;
+ PSLICREAD bits;
+ char byte;
+} PLD_SLICR;
+
+/******************************************************************************
+*
+* These structures represents the Clock Control Register on the
+* Internet LineJACK
+*
+******************************************************************************/
+typedef struct {
+ unsigned int clk0:1;
+ unsigned int clk1:1;
+ unsigned int clk2:1;
+ unsigned int x0:1;
+ unsigned int slic_e1:1;
+ unsigned int x1:1;
+ unsigned int x2:1;
+ unsigned int x3:1;
+} PCLOCK;
+
+typedef union {
+ PCLOCK bits;
+ char byte;
+} PLD_CLOCK;
+
+/******************************************************************************
+*
+* These structures deal with the mixer on the Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct {
+ unsigned short vol[10];
+ unsigned int recsrc;
+ unsigned int modcnt;
+ unsigned short micpreamp;
+} MIX;
+
+/******************************************************************************
+*
+* These structures deal with the DAA on the Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct _DAA_REGS {
+ //-----------------------------------------------
+ // SOP Registers
+ //
+ BYTE bySOP;
+
+ union _SOP_REGS {
+ struct _SOP {
+ union // SOP - CR0 Register
+ {
+ BYTE reg;
+ struct _CR0_BITREGS {
+ BYTE CLK_EXT:1; // cr0[0:0]
+
+ BYTE RIP:1; // cr0[1:1]
+
+ BYTE AR:1; // cr0[2:2]
+
+ BYTE AX:1; // cr0[3:3]
+
+ BYTE FRR:1; // cr0[4:4]
+
+ BYTE FRX:1; // cr0[5:5]
+
+ BYTE IM:1; // cr0[6:6]
+
+ BYTE TH:1; // cr0[7:7]
+
+ } bitreg;
+ } cr0;
+
+ union // SOP - CR1 Register
+ {
+ BYTE reg;
+ struct _CR1_REGS {
+ BYTE RM:1; // cr1[0:0]
+
+ BYTE RMR:1; // cr1[1:1]
+
+ BYTE No_auto:1; // cr1[2:2]
+
+ BYTE Pulse:1; // cr1[3:3]
+
+ BYTE P_Tone1:1; // cr1[4:4]
+
+ BYTE P_Tone2:1; // cr1[5:5]
+
+ BYTE E_Tone1:1; // cr1[6:6]
+
+ BYTE E_Tone2:1; // cr1[7:7]
+
+ } bitreg;
+ } cr1;
+
+ union // SOP - CR2 Register
+ {
+ BYTE reg;
+ struct _CR2_REGS {
+ BYTE Call_II:1; // CR2[0:0]
+
+ BYTE Call_I:1; // CR2[1:1]
+
+ BYTE Call_en:1; // CR2[2:2]
+
+ BYTE Call_pon:1; // CR2[3:3]
+
+ BYTE IDR:1; // CR2[4:4]
+
+ BYTE COT_R:3; // CR2[5:7]
+
+ } bitreg;
+ } cr2;
+
+ union // SOP - CR3 Register
+ {
+ BYTE reg;
+ struct _CR3_REGS {
+ BYTE DHP_X:1; // CR3[0:0]
+
+ BYTE DHP_R:1; // CR3[1:1]
+
+ BYTE Cal_pctl:1; // CR3[2:2]
+
+ BYTE SEL:1; // CR3[3:3]
+
+ BYTE TestLoops:4; // CR3[4:7]
+
+ } bitreg;
+ } cr3;
+
+ union // SOP - CR4 Register
+ {
+ BYTE reg;
+ struct _CR4_REGS {
+ BYTE Fsc_en:1; // CR4[0:0]
+
+ BYTE Int_en:1; // CR4[1:1]
+
+ BYTE AGX:2; // CR4[2:3]
+
+ BYTE AGR_R:2; // CR4[4:5]
+
+ BYTE AGR_Z:2; // CR4[6:7]
+
+ } bitreg;
+ } cr4;
+
+ union // SOP - CR5 Register
+ {
+ BYTE reg;
+ struct _CR5_REGS {
+ BYTE V_0:1; // CR5[0:0]
+
+ BYTE V_1:1; // CR5[1:1]
+
+ BYTE V_2:1; // CR5[2:2]
+
+ BYTE V_3:1; // CR5[3:3]
+
+ BYTE V_4:1; // CR5[4:4]
+
+ BYTE V_5:1; // CR5[5:5]
+
+ BYTE V_6:1; // CR5[6:6]
+
+ BYTE V_7:1; // CR5[7:7]
+
+ } bitreg;
+ } cr5;
+
+ union // SOP - CR6 Register
+ {
+ BYTE reg;
+ struct _CR6_REGS {
+ BYTE reserved:8; // CR6[0:7]
+
+ } bitreg;
+ } cr6;
+
+ union // SOP - CR7 Register
+ {
+ BYTE reg;
+ struct _CR7_REGS {
+ BYTE reserved:8; // CR7[0:7]
+
+ } bitreg;
+ } cr7;
+ } SOP;
+
+ BYTE ByteRegs[sizeof(struct _SOP)];
+
+ } SOP_REGS;
+
+ // DAA_REGS.SOP_REGS.SOP.CR5.reg
+ // DAA_REGS.SOP_REGS.SOP.CR5.bitreg
+ // DAA_REGS.SOP_REGS.SOP.CR5.bitreg.V_2
+ // DAA_REGS.SOP_REGS.ByteRegs[5]
+
+ //-----------------------------------------------
+ // XOP Registers
+ //
+ BYTE byXOP;
+
+ union _XOP_REGS {
+ struct _XOP {
+ union // XOP - XR0 Register - Read values
+ {
+ BYTE reg;
+ struct _XR0_BITREGS {
+ BYTE SI_0:1; // XR0[0:0] - Read
+
+ BYTE SI_1:1; // XR0[1:1] - Read
+
+ BYTE VDD_OK:1; // XR0[2:2] - Read
+
+ BYTE Caller_ID:1; // XR0[3:3] - Read
+
+ BYTE RING:1; // XR0[4:4] - Read
+
+ BYTE Cadence:1; // XR0[5:5] - Read
+
+ BYTE Wake_up:1; // XR0[6:6] - Read
+
+ BYTE unused:1; // XR0[7:7] - Read
+
+ } bitreg;
+ } xr0;
+
+ union // XOP - XR1 Register
+ {
+ BYTE reg;
+ struct _XR1_BITREGS {
+ BYTE M_SI_0:1; // XR1[0:0]
+
+ BYTE M_SI_1:1; // XR1[1:1]
+
+ BYTE M_VDD_OK:1; // XR1[2:2]
+
+ BYTE M_Caller_ID:1; // XR1[3:3]
+
+ BYTE M_RING:1; // XR1[4:4]
+
+ BYTE M_Cadence:1; // XR1[5:5]
+
+ BYTE M_Wake_up:1; // XR1[6:6]
+
+ BYTE unused:1; // XR1[7:7]
+
+ } bitreg;
+ } xr1;
+
+ union // XOP - XR2 Register
+ {
+ BYTE reg;
+ struct _XR2_BITREGS {
+ BYTE CTO0:1; // XR2[0:0]
+
+ BYTE CTO1:1; // XR2[1:1]
+
+ BYTE CTO2:1; // XR2[2:2]
+
+ BYTE CTO3:1; // XR2[3:3]
+
+ BYTE CTO4:1; // XR2[4:4]
+
+ BYTE CTO5:1; // XR2[5:5]
+
+ BYTE CTO6:1; // XR2[6:6]
+
+ BYTE CTO7:1; // XR2[7:7]
+
+ } bitreg;
+ } xr2;
+
+ union // XOP - XR3 Register
+ {
+ BYTE reg;
+ struct _XR3_BITREGS {
+ BYTE DCR0:1; // XR3[0:0]
+
+ BYTE DCR1:1; // XR3[1:1]
+
+ BYTE DCI:1; // XR3[2:2]
+
+ BYTE DCU0:1; // XR3[3:3]
+
+ BYTE DCU1:1; // XR3[4:4]
+
+ BYTE B_off:1; // XR3[5:5]
+
+ BYTE AGB0:1; // XR3[6:6]
+
+ BYTE AGB1:1; // XR3[7:7]
+
+ } bitreg;
+ } xr3;
+
+ union // XOP - XR4 Register
+ {
+ BYTE reg;
+ struct _XR4_BITREGS {
+ BYTE C_0:1; // XR4[0:0]
+
+ BYTE C_1:1; // XR4[1:1]
+
+ BYTE C_2:1; // XR4[2:2]
+
+ BYTE C_3:1; // XR4[3:3]
+
+ BYTE C_4:1; // XR4[4:4]
+
+ BYTE C_5:1; // XR4[5:5]
+
+ BYTE C_6:1; // XR4[6:6]
+
+ BYTE C_7:1; // XR4[7:7]
+
+ } bitreg;
+ } xr4;
+
+ union // XOP - XR5 Register
+ {
+ BYTE reg;
+ struct _XR5_BITREGS {
+ BYTE T_0:1; // XR5[0:0]
+
+ BYTE T_1:1; // XR5[1:1]
+
+ BYTE T_2:1; // XR5[2:2]
+
+ BYTE T_3:1; // XR5[3:3]
+
+ BYTE T_4:1; // XR5[4:4]
+
+ BYTE T_5:1; // XR5[5:5]
+
+ BYTE T_6:1; // XR5[6:6]
+
+ BYTE T_7:1; // XR5[7:7]
+
+ } bitreg;
+ } xr5;
+
+ union // XOP - XR6 Register - Read Values
+ {
+ BYTE reg;
+ struct _XR6_BITREGS {
+ BYTE CPS0:1; // XR6[0:0]
+
+ BYTE CPS1:1; // XR6[1:1]
+
+ BYTE unused1:2; // XR6[2:3]
+
+ BYTE CLK_OFF:1; // XR6[4:4]
+
+ BYTE unused2:3; // XR6[5:7]
+
+ } bitreg;
+ } xr6;
+
+ union // XOP - XR7 Register
+ {
+ BYTE reg;
+ struct _XR7_BITREGS {
+ BYTE unused1:1; // XR7[0:0]
+
+ BYTE Vdd0:1; // XR7[1:1]
+
+ BYTE Vdd1:1; // XR7[2:2]
+
+ BYTE unused2:5; // XR7[3:7]
+
+ } bitreg;
+ } xr7;
+ } XOP;
+
+ BYTE ByteRegs[sizeof(struct _XOP)];
+
+ } XOP_REGS;
+
+ // DAA_REGS.XOP_REGS.XOP.XR7.reg
+ // DAA_REGS.XOP_REGS.XOP.XR7.bitreg
+ // DAA_REGS.XOP_REGS.XOP.XR7.bitreg.Vdd0
+ // DAA_REGS.XOP_REGS.ByteRegs[7]
+
+ //-----------------------------------------------
+ // COP Registers
+ //
+ BYTE byCOP;
+
+ union _COP_REGS {
+ struct _COP {
+ BYTE THFilterCoeff_1[8]; // COP - TH Filter Coefficients, CODE=0, Part 1
+
+ BYTE THFilterCoeff_2[8]; // COP - TH Filter Coefficients, CODE=1, Part 2
+
+ BYTE THFilterCoeff_3[8]; // COP - TH Filter Coefficients, CODE=2, Part 3
+
+ BYTE RingerImpendance_1[8]; // COP - Ringer Impendance Coefficients, CODE=3, Part 1
+
+ BYTE IMFilterCoeff_1[8]; // COP - IM Filter Coefficients, CODE=4, Part 1
+
+ BYTE IMFilterCoeff_2[8]; // COP - IM Filter Coefficients, CODE=5, Part 2
+
+ BYTE RingerImpendance_2[8]; // COP - Ringer Impendance Coefficients, CODE=6, Part 2
+
+ BYTE FRRFilterCoeff[8]; // COP - FRR Filter Coefficients, CODE=7
+
+ BYTE FRXFilterCoeff[8]; // COP - FRX Filter Coefficients, CODE=8
+
+ BYTE ARFilterCoeff[4]; // COP - AR Filter Coefficients, CODE=9
+
+ BYTE AXFilterCoeff[4]; // COP - AX Filter Coefficients, CODE=10
+
+ BYTE Tone1Coeff[4]; // COP - Tone1 Coefficients, CODE=11
+
+ BYTE Tone2Coeff[4]; // COP - Tone2 Coefficients, CODE=12
+
+ BYTE LevelmeteringRinging[4]; // COP - Levelmetering Ringing, CODE=13
+
+ BYTE CallerID1stTone[8]; // COP - Caller ID 1st Tone, CODE=14
+
+ BYTE CallerID2ndTone[8]; // COP - Caller ID 2nd Tone, CODE=15
+
+ } COP;
+
+ BYTE ByteRegs[sizeof(struct _COP)];
+
+ } COP_REGS;
+
+ // DAA_REGS.COP_REGS.COP.XR7.Tone1Coeff[3]
+ // DAA_REGS.COP_REGS.COP.XR7.bitreg
+ // DAA_REGS.COP_REGS.COP.XR7.bitreg.Vdd0
+ // DAA_REGS.COP_REGS.ByteRegs[57]
+
+ //-----------------------------------------------
+ // CAO Registers
+ //
+ BYTE byCAO;
+
+ union _CAO_REGS {
+ struct _CAO {
+ BYTE CallerID[512]; // CAO - Caller ID Bytes
+
+ } CAO;
+
+ BYTE ByteRegs[sizeof(struct _CAO)];
+ } CAO_REGS;
+
+ union // XOP - XR0 Register - Write values
+ {
+ BYTE reg;
+ struct _XR0_BITREGSW {
+ BYTE SO_0:1; // XR1[0:0] - Write
+
+ BYTE SO_1:1; // XR1[1:1] - Write
+
+ BYTE SO_2:1; // XR1[2:2] - Write
+
+ BYTE unused:5; // XR1[3:7] - Write
+
+ } bitreg;
+ } XOP_xr0_W;
+
+ union // XOP - XR6 Register - Write values
+ {
+ BYTE reg;
+ struct _XR6_BITREGSW {
+ BYTE unused1:4; // XR6[0:3]
+
+ BYTE CLK_OFF:1; // XR6[4:4]
+
+ BYTE unused2:3; // XR6[5:7]
+
+ } bitreg;
+ } XOP_xr6_W;
+
+} DAA_REGS;
+
+#define ALISDAA_ID_BYTE 0x81
+#define ALISDAA_CALLERID_SIZE 512
+
+//------------------------------
+//
+// Misc definitions
+//
+
+// Power Up Operation
+#define SOP_PU_SLEEP 0
+#define SOP_PU_RINGING 1
+#define SOP_PU_CONVERSATION 2
+#define SOP_PU_PULSEDIALING 3
+
+#define ALISDAA_CALLERID_SIZE 512
+
+#define PLAYBACK_MODE_COMPRESSED 0 // Selects: Compressed modes, TrueSpeech 8.5-4.1, G.723.1, G.722, G.728, G.729
+#define PLAYBACK_MODE_TRUESPEECH_V40 0 // Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps
+#define PLAYBACK_MODE_TRUESPEECH 8 // Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps Version 5.1
+#define PLAYBACK_MODE_ULAW 2 // Selects: 64 Kbit/sec MuA-law PCM
+#define PLAYBACK_MODE_ALAW 10 // Selects: 64 Kbit/sec A-law PCM
+#define PLAYBACK_MODE_16LINEAR 6 // Selects: 128 Kbit/sec 16-bit linear
+#define PLAYBACK_MODE_8LINEAR 4 // Selects: 64 Kbit/sec 8-bit signed linear
+#define PLAYBACK_MODE_8LINEAR_WSS 5 // Selects: 64 Kbit/sec WSS 8-bit unsigned linear
+
+#define RECORD_MODE_COMPRESSED 0 // Selects: Compressed modes, TrueSpeech 8.5-4.1, G.723.1, G.722, G.728, G.729
+#define RECORD_MODE_TRUESPEECH 0 // Selects: TrueSpeech 8.5, 6.3, 5.3, 4.8 or 4.1 Kbps
+#define RECORD_MODE_ULAW 4 // Selects: 64 Kbit/sec Mu-law PCM
+#define RECORD_MODE_ALAW 12 // Selects: 64 Kbit/sec A-law PCM
+#define RECORD_MODE_16LINEAR 5 // Selects: 128 Kbit/sec 16-bit linear
+#define RECORD_MODE_8LINEAR 6 // Selects: 64 Kbit/sec 8-bit signed linear
+#define RECORD_MODE_8LINEAR_WSS 7 // Selects: 64 Kbit/sec WSS 8-bit unsigned linear
+
+enum SLIC_STATES {
+ PLD_SLIC_STATE_OC = 0,
+ PLD_SLIC_STATE_RINGING,
+ PLD_SLIC_STATE_ACTIVE,
+ PLD_SLIC_STATE_OHT,
+ PLD_SLIC_STATE_TIPOPEN,
+ PLD_SLIC_STATE_STANDBY,
+ PLD_SLIC_STATE_APR,
+ PLD_SLIC_STATE_OHTPR
+};
+
+enum SCI_CONTROL {
+ SCI_End = 0,
+ SCI_Enable_DAA,
+ SCI_Enable_Mixer,
+ SCI_Enable_EEPROM
+};
+
+enum Mode {
+ T63, T53, T48, T40
+};
+enum Dir {
+ V3_TO_V4, V4_TO_V3, V4_TO_V5, V5_TO_V4
+};
+
+typedef struct Proc_Info_Tag {
+ enum Mode convert_mode;
+ enum Dir convert_dir;
+ int Prev_Frame_Type;
+ int Current_Frame_Type;
+} Proc_Info_Type;
+
+enum PREVAL {
+ NORMAL = 0,
+ NOPOST,
+ POSTONLY,
+ PREERROR
+};
+
+enum IXJ_EXTENSIONS {
+ G729LOADER = 0,
+ TS85LOADER,
+ PRE_READ,
+ POST_READ,
+ PRE_WRITE,
+ POST_WRITE,
+ PRE_IOCTL,
+ POST_IOCTL
+};
+
+typedef struct {
+ unsigned int busytone:1;
+ unsigned int dialtone:1;
+ unsigned int ringback:1;
+ unsigned int ringing:1;
+ unsigned int cringing:1;
+ unsigned int play_first_frame:1;
+ unsigned int pstn_present:1;
+ unsigned int pstn_ringing:1;
+ unsigned int pots_correct:1;
+ unsigned int pots_pstn:1;
+ unsigned int g729_loaded:1;
+ unsigned int ts85_loaded:1;
+ unsigned int dtmf_oob:1; // DTMF Out-Of-Band
+
+} IXJ_FLAGS;
+
+/******************************************************************************
+*
+* This structure represents the Internet PhoneJACK and Internet LineJACK
+*
+******************************************************************************/
+
+typedef struct {
+ struct phone_device p;
+ unsigned int board;
+ unsigned int DSPbase;
+ unsigned int XILINXbase;
+ unsigned int serial;
+ struct phone_capability caplist[30];
+ unsigned int caps;
+ struct pci_dev *dev;
+ unsigned int cardtype;
+ unsigned int rec_codec;
+ char rec_mode;
+ unsigned int play_codec;
+ char play_mode;
+ IXJ_FLAGS flags;
+ unsigned int rec_frame_size;
+ unsigned int play_frame_size;
+ int aec_level;
+ int readers, writers;
+ wait_queue_head_t poll_q;
+ wait_queue_head_t read_q;
+ char *read_buffer, *read_buffer_end;
+ char *read_convert_buffer;
+ unsigned int read_buffer_size;
+ unsigned int read_buffer_ready;
+ wait_queue_head_t write_q;
+ char *write_buffer, *write_buffer_end;
+ char *write_convert_buffer;
+ unsigned int write_buffer_size;
+ unsigned int write_buffers_empty;
+ unsigned long drybuffer;
+ char *write_buffer_rp, *write_buffer_wp;
+ char dtmfbuffer[80];
+ char dtmf_current;
+ int dtmf_wp, dtmf_rp, dtmf_state, dtmf_proc;
+ int tone_off_time, tone_on_time;
+ struct fasync_struct *async_queue;
+ unsigned long tone_start_jif;
+ char tone_index;
+ char tone_state;
+ char maxrings;
+ IXJ_CADENCE *cadence_t;
+ int tone_cadence_state;
+ DTMF dtmf;
+ CPTF cptf;
+ BYTES dsp;
+ BYTES ver;
+ BYTES scr;
+ BYTES ssr;
+ BYTES baseframe;
+ HSR hsr;
+ GPIO gpio;
+ PLD_SCRR pld_scrr;
+ PLD_SCRW pld_scrw;
+ PLD_SLICW pld_slicw;
+ PLD_SLICR pld_slicr;
+ PLD_CLOCK pld_clock;
+ MIX mix;
+ unsigned short ring_cadence;
+ int ring_cadence_t;
+ unsigned long ring_cadence_jif;
+ int intercom;
+ int m_hook;
+ int r_hook;
+ char pstn_envelope;
+ char pstn_cid_intr;
+ unsigned pstn_cid_recieved;
+ IXJ_CID cid;
+ unsigned long pstn_ring_start;
+ unsigned long pstn_winkstart;
+ unsigned int winktime;
+ char port;
+ union telephony_exception ex;
+ char daa_mode;
+ unsigned long pstn_sleeptil;
+ DAA_REGS m_DAAShadowRegs;
+ Proc_Info_Type Info_read;
+ Proc_Info_Type Info_write;
+ unsigned short frame_count;
+ unsigned int filter_cadence;
+ unsigned int filter_hist[4];
+ unsigned short proc_load;
+ unsigned long framesread;
+ unsigned long frameswritten;
+ unsigned long read_wait;
+ unsigned long write_wait;
+ unsigned long timerchecks;
+ unsigned long txreadycheck;
+ unsigned long rxreadycheck;
+} IXJ;
+
+typedef int (*IXJ_REGFUNC) (IXJ * j, unsigned long arg);
+
+int ixj_register(int index, IXJ_REGFUNC regfunc);
+int ixj_unregister(int index);
--- /dev/null
+/*
+ * Telephony registration for Linux
+ *
+ * (c) Copyright 1999 Red Hat Software 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.
+ *
+ * Author: Alan Cox, <alan@redhat.com>
+ *
+ * Fixes:
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/phonedev.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kmod.h>
+
+
+#define PHONE_NUM_DEVICES 256
+
+/*
+ * Active devices
+ */
+
+static struct phone_device *phone_device[PHONE_NUM_DEVICES];
+
+/*
+ * Open a phone device.
+ */
+
+static int phone_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ int err;
+ struct phone_device *p;
+
+ if (minor >= PHONE_NUM_DEVICES)
+ return -ENODEV;
+
+ p = phone_device[minor];
+ if (p == NULL) {
+ char modname[32];
+
+ sprintf(modname, "char-major-%d-%d", PHONE_MAJOR, minor);
+ request_module(modname);
+ p = phone_device[minor];
+ if (p == NULL)
+ return -ENODEV;
+ }
+ if (p->open) {
+ err = p->open(p, file); /* Tell the device it is open */
+ if (err)
+ return err;
+ }
+ file->f_op = p->f_op;
+ return 0;
+}
+
+/*
+ * Telephony For Linux device drivers request registration here.
+ */
+
+int phone_register_device(struct phone_device *p, int unit)
+{
+ int base;
+ int end;
+ int i;
+
+ base = 0;
+ end = PHONE_NUM_DEVICES - 1;
+
+ if (unit != PHONE_UNIT_ANY) {
+ base = unit;
+ end = unit;
+ }
+ for (i = base; i < end; i++) {
+ if (phone_device[i] == NULL) {
+ phone_device[i] = p;
+ p->minor = i;
+ MOD_INC_USE_COUNT;
+ return 0;
+ }
+ }
+ return -ENFILE;
+}
+
+/*
+ * Unregister an unused Telephony for linux device
+ */
+
+void phone_unregister_device(struct phone_device *pfd)
+{
+ if (phone_device[pfd->minor] != pfd)
+ panic("phone: bad unregister");
+ phone_device[pfd->minor] = NULL;
+ MOD_DEC_USE_COUNT;
+}
+
+
+static struct file_operations phone_fops =
+{
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* readdir */
+ NULL,
+ NULL,
+ NULL,
+ phone_open,
+ NULL, /* flush */
+ NULL
+};
+
+/*
+ * Board init functions
+ */
+
+extern int ixj_init(void);
+
+/*
+ * Initialise Telephony for linux
+ */
+
+int telephony_init(void)
+{
+ printk(KERN_INFO "Linux telephony interface: v1.00\n");
+ if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
+ printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
+ return -EIO;
+ }
+ /*
+ * Init kernel installed drivers
+ */
+#ifdef CONFIG_PHONE_IXJ
+ ixj_init();
+#endif
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return telephony_init();
+}
+
+void cleanup_module(void)
+{
+ unregister_chrdev(PHONE_MAJOR, "telephony");
+}
+
+#endif
+
+EXPORT_SYMBOL(phone_register_device);
+EXPORT_SYMBOL(phone_unregister_device);
O_OBJS := inode.o uncompress.o inflate/zlib.o
+M_OBJS := $(O_TARGET)
+
include $(TOPDIR)/Rules.make
inflate/zlib.o:
return r;
}
+/*
+ * This routine is used to map in a page into an address space: needed by
+ * execve() for the initial stack and environment pages.
+ */
+static void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
+{
+ pgd_t * pgd;
+ pmd_t * pmd;
+ pte_t * pte;
+
+ if (page_count(page) != 1)
+ printk("mem_map disagrees with %p at %08lx\n", page, address);
+ pgd = pgd_offset(tsk->mm, address);
+ pmd = pmd_alloc(pgd, address);
+ if (!pmd) {
+ __free_page(page);
+ oom(tsk);
+ return;
+ }
+ pte = pte_alloc(pmd, address);
+ if (!pte) {
+ __free_page(page);
+ oom(tsk);
+ return;
+ }
+ if (!pte_none(*pte)) {
+ pte_ERROR(*pte);
+ __free_page(page);
+ return;
+ }
+ flush_page_to_ram(page);
+ set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
+/* no need for flush_tlb */
+}
+
int setup_arg_pages(struct linux_binprm *bprm)
{
unsigned long stack_base;
return register_filesystem(&ext2_fs_type);
}
-static int __exit exit_ext2_fs(void)
+static void __exit exit_ext2_fs(void)
{
unregister_filesystem(&ext2_fs_type);
}
extern void ext2_write_super (struct super_block *);
extern int ext2_remount (struct super_block *, int *, char *);
extern struct super_block * ext2_read_super (struct super_block *,void *,int);
-extern int init_ext2_fs(void);
extern int ext2_statfs (struct super_block *, struct statfs *, int);
/* truncate.c */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-algo-bit.h,v 1.7 1999/12/21 23:45:58 frodo Exp $ */
+
#ifndef I2C_ALGO_BIT_H
#define I2C_ALGO_BIT_H 1
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-algo-pcf.h,v 1.6 1999/12/21 23:45:58 frodo Exp $ */
+
#ifndef I2C_ALGO_PCF_H
#define I2C_AGLO_PCF_H 1
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/* $Id: i2c-dev.h,v 1.3 1999/12/21 23:45:58 frodo Exp $ */
+
#ifndef I2C_DEV_H
#define I2C_DEV_H
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c-elektor.h,v 1.3 1999/12/21 23:45:58 frodo Exp $ */
+
#ifndef I2C_PCF_ELEKTOR_H
#define I2C_PCF_ELEKTOR_H 1
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* $Revision: 1.4 $ $Date: 1999/12/02 02:05:34 $*/
-/* ------------------------------------------------------------------------- */
+
+/* $Id: i2c-id.h,v 1.6 1999/12/21 23:45:58 frodo Exp $ */
#ifndef I2C_ID_H
#define I2C_ID_H
#define I2C_DRIVERID_EXP2 0xF2
#define I2C_DRIVERID_EXP3 0xF3
+#define I2C_DRIVERID_MGATVO 0x0101 /* Matrox TVOut */
+
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_I2CPROC 901
#define I2C_HW_B_WNV 0x06 /* Winnov Videums */
#define I2C_HW_B_VIA 0x07 /* Via vt82c586b */
#define I2C_HW_B_HYDRA 0x08 /* Apple Hydra Mac I/O */
+#define I2C_HW_B_G400 0x09 /* Matrox G400 */
/* --- PCF 8584 based algorithms */
#define I2C_HW_P_LP 0x00 /* Parallel port interface */
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* $Revision: 1.30 $ $Date: 1999/11/16 08:12:38 $*/
-/* ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
Frodo Looijaard <frodol@dds.nl> */
+/* $Id: i2c.h,v 1.32 1999/12/21 23:45:58 frodo Exp $ */
+
#ifndef I2C_H
#define I2C_H
extern void i2c_inc_use_client(struct i2c_client *);
extern void i2c_dec_use_client(struct i2c_client *);
+/* returns -EBUSY if address has been taken, 0 if not. Note that the only
+ other place at which this is called is within i2c_attach_client; so
+ you can cheat by simply not registering. Not recommended, of course! */
+extern int i2c_check_addr (struct i2c_adapter *adapter, int addr);
/* Detect function. It itterates over all possible addresses itself.
* It will only call found_proc if some client is connected at the
/* this is for i2c-dev.c */
#define I2C_SLAVE 0x0703 /* Change slave address */
/* Attn.: Slave address is 7 or 10 bits */
+#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */
+ /* Attn.: Slave address is 7 or 10 bits */
+ /* This changes the address, even if it */
+ /* is already taken! */
#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
#define I2C_FUNCS 0x0705 /* Get the adapter functionality */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Mar 8 14:06:12 1999
- * Modified at: Sun Dec 12 12:23:11 1999
+ * Modified at: Tue Dec 21 09:00:59 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
#define IRLMP_ENUMDEVICES 1
#define IRLMP_IAS_SET 2
-#define IRLMP_IAS_GET 3
-#define IRLMP_IAS_QUERY 4
-#define IRLMP_HINTS_SET 5
+#define IRLMP_IAS_QUERY 3
+#define IRLMP_HINTS_SET 4
+#define IRLMP_QOS_SET 5
+#define IRLMP_QOS_GET 6
+#define IRLMP_MAX_SDU_SIZE 7
+#define IRLMP_IAS_GET 8
-#define IRTTP_QOS_SET 6
-#define IRTTP_QOS_GET 7
-#define IRTTP_MAX_SDU_SIZE 8
+#define IRTTP_MAX_SDU_SIZE IRLMP_MAX_SDU_SIZE /* Compatibility */
#define IAS_MAX_STRING 256
#define IAS_MAX_OCTET_STRING 1024
#define IAS_MAX_CLASSNAME 64
#define IAS_MAX_ATTRIBNAME 256
-#define LSAP_ANY 0xff
+#define LSAP_ANY 0xff
struct sockaddr_irda {
sa_family_t sir_family; /* AF_IRDA */
--- /dev/null
+/*
+ * ixjuser.h
+ *
+ * User-space include file for the Internet PhoneJACK and
+ * Internet LineJACK Telephony Cards.
+ *
+ * (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Author: Ed Okerson, <eokerson@quicknet.net>
+ *
+ * Contributors: Greg Herlein, <gherlein@quicknet.net>
+ * David W. Erhart, <derhart@quicknet.net>
+ * John Sellers, <jsellers@quicknet.net>
+ * Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website: http://www.quicknet.net
+ *
+ * Fixes:
+ */
+
+static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#include <linux/telephony.h>
+
+/***************************************************************************
+
+ If you use the IXJCTL_TESTRAM command, the card must be power
+ cycled to reset the SRAM values before futher use.
+
+***************************************************************************/
+#define IXJCTL_DSP_RESET _IO ('q', 0xC0)
+
+#define IXJCTL_RING PHONE_RING
+#define IXJCTL_HOOKSTATE PHONE_HOOKSTATE
+#define IXJCTL_MAXRINGS PHONE_MAXRINGS
+#define IXJCTL_RING_CADENCE PHONE_RING_CADENCE
+#define IXJCTL_RING_START PHONE_RING_START
+#define IXJCTL_RING_STOP PHONE_RING_STOP
+
+#define IXJCTL_CARDTYPE _IOR ('q', 0xC1, int)
+#define IXJCTL_SERIAL _IOR ('q', 0xC2, int)
+#define IXJCTL_DSP_TYPE _IOR ('q', 0xC3, int)
+#define IXJCTL_DSP_VERSION _IOR ('q', 0xC4, int)
+#define IXJCTL_DSP_IDLE _IO ('q', 0xC5)
+#define IXJCTL_TESTRAM _IO ('q', 0xC6)
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the record settings of the DSP
+*
+* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP.
+* Setting a lower depth reduces latency, but increases the demand of the
+* application to service the driver without frame loss. The DSP has 480
+* bytes of physical buffer memory for the record channel so the true
+* maximum limit is determined by how many frames will fit in the buffer.
+*
+* 1 uncompressed (480 byte) 16-bit linear frame.
+* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames.
+* 15 TrueSpeech 8.5 frames.
+* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames.
+*
+* The default in the driver is currently set to 2 frames.
+*
+* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8
+* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the
+* signal by 2.0, 0x80 scales the signal by 0.5. No protection is given
+* against over-scaling, if the multiplication factor times the input
+* signal exceeds 16 bits, overflow distortion will occur. The default
+* setting is 0x100 (1.0).
+*
+* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on
+* the most recently recorded frame as a 16 bit value.
+******************************************************************************/
+
+#define IXJCTL_REC_CODEC PHONE_REC_CODEC
+#define IXJCTL_REC_START PHONE_REC_START
+#define IXJCTL_REC_STOP PHONE_REC_STOP
+#define IXJCTL_REC_DEPTH PHONE_REC_DEPTH
+#define IXJCTL_FRAME PHONE_FRAME
+#define IXJCTL_REC_VOLUME PHONE_REC_VOLUME
+#define IXJCTL_REC_LEVEL PHONE_REC_LEVEL
+
+typedef enum {
+ f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50,
+ f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400,
+ f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450,
+ f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450,
+ f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587,
+ f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850,
+ f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400,
+ f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336,
+ lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860
+} IXJ_FILTER_FREQ;
+
+typedef struct {
+ unsigned int filter;
+ IXJ_FILTER_FREQ freq;
+ char enable;
+} IXJ_FILTER;
+
+#define IXJCTL_SET_FILTER _IOW ('q', 0xC7, IXJ_FILTER *)
+#define IXJCTL_GET_FILTER_HIST _IOW ('q', 0xC8, int)
+/******************************************************************************
+*
+* This IOCTL allows you to reassign values in the tone index table. The
+* tone table has 32 entries (0 - 31), but the driver only allows entries
+* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are
+* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D.
+* The positions used internally for Call Progress Tones are as follows:
+* Dial Tone - 25
+* Ring Back - 26
+* Busy Signal - 27
+*
+* The freq values are calculated as:
+* freq = cos(2 * PI * frequency / 8000)
+*
+* The most commonly needed values are already calculated and listed in the
+* enum IXJ_TONE_FREQ. Each tone index can have two frequencies with
+* different gains, if you are only using a single frequency set the unused
+* one to 0.
+*
+* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB
+* increments.
+*
+******************************************************************************/
+
+typedef enum {
+ hz20 = 0x7ffa,
+ hz50 = 0x7fe5,
+ hz133 = 0x7f4c,
+ hz200 = 0x7e6b,
+ hz261 = 0x7d50, /* .63 C1 */
+ hz277 = 0x7cfa, /* .18 CS1 */
+ hz293 = 0x7c9f, /* .66 D1 */
+ hz300 = 0x7c75,
+ hz311 = 0x7c32, /* .13 DS1 */
+ hz329 = 0x7bbf, /* .63 E1 */
+ hz330 = 0x7bb8,
+ hz340 = 0x7b75,
+ hz349 = 0x7b37, /* .23 F1 */
+ hz350 = 0x7b30,
+ hz360 = 0x7ae9,
+ hz369 = 0x7aa8, /* .99 FS1 */
+ hz380 = 0x7a56,
+ hz392 = 0x79fa, /* .00 G1 */
+ hz400 = 0x79bb,
+ hz415 = 0x7941, /* .30 GS1 */
+ hz420 = 0x7918,
+ hz425 = 0x78ee,
+ hz435 = 0x7899,
+ hz440 = 0x786d, /* .00 A1 */
+ hz445 = 0x7842,
+ hz450 = 0x7815,
+ hz452 = 0x7803,
+ hz466 = 0x7784, /* .16 AS1 */
+ hz475 = 0x7731,
+ hz480 = 0x7701,
+ hz493 = 0x7685, /* .88 B1 */
+ hz494 = 0x767b,
+ hz500 = 0x7640,
+ hz520 = 0x7578,
+ hz523 = 0x7559, /* .25 C2 */
+ hz525 = 0x7544,
+ hz540 = 0x74a7,
+ hz554 = 0x7411, /* .37 CS2 */
+ hz587 = 0x72a1, /* .33 D2 */
+ hz590 = 0x727f,
+ hz600 = 0x720b,
+ hz620 = 0x711e,
+ hz622 = 0x7106, /* .25 DS2 */
+ hz659 = 0x6f3b, /* .26 E2 */
+ hz660 = 0x6f2e,
+ hz698 = 0x6d3d, /* .46 F2 */
+ hz700 = 0x6d22,
+ hz739 = 0x6b09, /* .99 FS2 */
+ hz740 = 0x6afa,
+ hz750 = 0x6a6c,
+ hz770 = 0x694b,
+ hz783 = 0x688b, /* .99 G2 */
+ hz800 = 0x678d,
+ hz816 = 0x6698,
+ hz830 = 0x65bf, /* .61 GS2 */
+ hz850 = 0x6484,
+ hz857 = 0x6414,
+ hz880 = 0x629f, /* .00 A2 */
+ hz900 = 0x6154,
+ hz932 = 0x5f35, /* .33 AS2 */
+ hz935 = 0x5f01,
+ hz941 = 0x5e9a,
+ hz942 = 0x5e88,
+ hz950 = 0x5dfd,
+ hz975 = 0x5c44,
+ hz1000 = 0x5a81,
+ hz1020 = 0x5912,
+ hz1050 = 0x56e2,
+ hz1100 = 0x5320,
+ hz1140 = 0x5007,
+ hz1200 = 0x4b3b,
+ hz1209 = 0x4a80,
+ hz1215 = 0x4a02,
+ hz1250 = 0x471c,
+ hz1300 = 0x42e0,
+ hz1330 = 0x4049,
+ hz1336 = 0x3fc4,
+ hz1366 = 0x3d22,
+ hz1380 = 0x3be4,
+ hz1400 = 0x3a1b,
+ hz1450 = 0x3596,
+ hz1477 = 0x331c,
+ hz1500 = 0x30fb,
+ hz1600 = 0x278d,
+ hz1633 = 0x2462,
+ hz1638 = 0x23e7,
+ hz1645 = 0x233a,
+ hz1750 = 0x18f8,
+ hz1800 = 0x1405,
+ hz1860 = 0xe0b,
+ hz2100 = 0xf5f6,
+ hz2450 = 0xd3b3
+} IXJ_FREQ;
+
+typedef enum {
+ C1 = hz261,
+ CS1 = hz277,
+ D1 = hz293,
+ DS1 = hz311,
+ E1 = hz329,
+ F1 = hz349,
+ FS1 = hz369,
+ G1 = hz392,
+ GS1 = hz415,
+ A1 = hz440,
+ AS1 = hz466,
+ B1 = hz493,
+ C2 = hz523,
+ CS2 = hz554,
+ D2 = hz587,
+ DS2 = hz622,
+ E2 = hz659,
+ F2 = hz698,
+ FS2 = hz739,
+ G2 = hz783,
+ GS2 = hz830,
+ A2 = hz880,
+ AS2 = hz932,
+} IXJ_NOTE;
+
+typedef struct {
+ int tone_index;
+ int freq0;
+ int gain0;
+ int freq1;
+ int gain1;
+} IXJ_TONE;
+
+#define IXJCTL_INIT_TONE _IOW ('q', 0xC9, IXJ_TONE *)
+
+/******************************************************************************
+*
+* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various
+* Call Progress Tones (CPT). This is accomplished by setting up an array of
+* IXJ_CADENCE_ELEMENT structures that sequentially define the states of
+* the tone sequence. The tone_on_time and tone_off time are in
+* 250 microsecond intervals. A pointer to this array is passed to the
+* driver as the ce element of an IXJ_CADENCE structure. The elements_used
+* must be set to the number of IXJ_CADENCE_ELEMENTS in the array. The
+* termination variable defines what to do at the end of a cadence, the
+* options are to play the cadence once and stop, to repeat the last
+* element of the cadence indefinatly, or to repeat the entire cadence
+* indefinatly. The ce variable is a pointer to the array of IXJ_TONE
+* structures. If the freq0 variable is non-zero, the tone table contents
+* for the tone_index are updated to the frequencies and gains defined. It
+* should be noted that DTMF tones cannot be reassigned, so if DTMF tone
+* table indexs are used in a cadence the frequency and gain variables will
+* be ignored.
+*
+* If the array elements contain frequency parameters the driver will
+* initialize the needed tone table elements and begin playing the tone,
+* there is no preset limit on the number of elements in the cadence. If
+* there is more than one frequency used in the cadence, sequential elements
+* of different frequencies MUST use different tone table indexes. Only one
+* cadence can be played at a time. It is possible to build complex
+* cadences with multiple frequencies using 2 tone table indexes by
+* alternating between them.
+*
+******************************************************************************/
+
+typedef struct {
+ int index;
+ int tone_on_time;
+ int tone_off_time;
+ int freq0;
+ int gain0;
+ int freq1;
+ int gain1;
+} IXJ_CADENCE_ELEMENT;
+
+typedef enum {
+ PLAY_ONCE,
+ REPEAT_LAST_ELEMENT,
+ REPEAT_ALL
+} IXJ_CADENCE_TERM;
+
+typedef struct {
+ int elements_used;
+ IXJ_CADENCE_TERM termination;
+ IXJ_CADENCE_ELEMENT *ce;
+} IXJ_CADENCE;
+
+#define IXJCTL_TONE_CADENCE _IOW ('q', 0xCA, IXJ_CADENCE *)
+/******************************************************************************
+*
+* This group of IOCTLs deal with the playback settings of the DSP
+*
+******************************************************************************/
+
+#define IXJCTL_PLAY_CODEC PHONE_PLAY_CODEC
+#define IXJCTL_PLAY_START PHONE_PLAY_START
+#define IXJCTL_PLAY_STOP PHONE_PLAY_STOP
+#define IXJCTL_PLAY_DEPTH PHONE_PLAY_DEPTH
+#define IXJCTL_PLAY_VOLUME PHONE_PLAY_VOLUME
+#define IXJCTL_PLAY_LEVEL PHONE_PLAY_LEVEL
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the Acoustic Echo Cancellation settings
+* of the DSP
+*
+* Issueing the IXJCTL_AEC_START command with a value of AEC_OFF has the
+* same effect as IXJCTL_AEC_STOP. This is to simplify slider bar
+* controls. IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
+******************************************************************************/
+#define IXJCTL_AEC_START _IOW ('q', 0xCB, int)
+#define IXJCTL_AEC_STOP _IO ('q', 0xCC)
+#define IXJCTL_AEC_GET_LEVEL _IO ('q', 0xCD)
+
+#define AEC_OFF 0
+#define AEC_LOW 1
+#define AEC_MED 2
+#define AEC_HIGH 3
+/******************************************************************************
+*
+* Call Progress Tones, DTMF, etc.
+* IXJCTL_DTMF_OOB determines if dtmf signaling is sent as Out-Of-Band
+* only. If you pass a 1, dtmf is suppressed from the audio stream.
+* Tone on and off times are in 250 microsecond intervals so
+* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
+* will set the tone on time of board ixj1 to 360 * 250us = 90ms
+* the default values of tone on and off times is 840 or 210ms
+******************************************************************************/
+
+#define IXJCTL_DTMF_READY PHONE_DTMF_READY
+#define IXJCTL_GET_DTMF PHONE_GET_DTMF
+#define IXJCTL_GET_DTMF_ASCII PHONE_GET_DTMF_ASCII
+#define IXJCTL_DTMF_OOB PHONE_DTMF_OOB
+#define IXJCTL_EXCEPTION PHONE_EXCEPTION
+#define IXJCTL_PLAY_TONE PHONE_PLAY_TONE
+#define IXJCTL_SET_TONE_ON_TIME PHONE_SET_TONE_ON_TIME
+#define IXJCTL_SET_TONE_OFF_TIME PHONE_SET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_ON_TIME PHONE_GET_TONE_ON_TIME
+#define IXJCTL_GET_TONE_OFF_TIME PHONE_GET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_STATE PHONE_GET_TONE_STATE
+#define IXJCTL_BUSY PHONE_BUSY
+#define IXJCTL_RINGBACK PHONE_RINGBACK
+#define IXJCTL_DIALTONE PHONE_DIALTONE
+#define IXJCTL_CPT_STOP PHONE_CPT_STOP
+
+/******************************************************************************
+* LineJack specific IOCTLs
+*
+* The lsb 4 bits of the LED argument represent the state of each of the 4
+* LED's on the LineJack
+******************************************************************************/
+
+#define IXJCTL_SET_LED _IOW ('q', 0xCE, int)
+#define IXJCTL_MIXER _IOW ('q', 0xCF, int)
+
+/******************************************************************************
+*
+* The master volume controls use attenuation with 32 levels from 0 to -62dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+*
+******************************************************************************/
+#define MIXER_MASTER_L 0x0100
+#define MIXER_MASTER_R 0x0200
+#define ATT00DB 0x00
+#define ATT02DB 0x01
+#define ATT04DB 0x02
+#define ATT06DB 0x03
+#define ATT08DB 0x04
+#define ATT10DB 0x05
+#define ATT12DB 0x06
+#define ATT14DB 0x07
+#define ATT16DB 0x08
+#define ATT18DB 0x09
+#define ATT20DB 0x0A
+#define ATT22DB 0x0B
+#define ATT24DB 0x0C
+#define ATT26DB 0x0D
+#define ATT28DB 0x0E
+#define ATT30DB 0x0F
+#define ATT32DB 0x10
+#define ATT34DB 0x11
+#define ATT36DB 0x12
+#define ATT38DB 0x13
+#define ATT40DB 0x14
+#define ATT42DB 0x15
+#define ATT44DB 0x16
+#define ATT46DB 0x17
+#define ATT48DB 0x18
+#define ATT50DB 0x19
+#define ATT52DB 0x1A
+#define ATT54DB 0x1B
+#define ATT56DB 0x1C
+#define ATT58DB 0x1D
+#define ATT60DB 0x1E
+#define ATT62DB 0x1F
+#define MASTER_MUTE 0x80
+
+/******************************************************************************
+*
+* The input volume controls use gain with 32 levels from +12dB to -50dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+*
+******************************************************************************/
+#define MIXER_PORT_CD_L 0x0600
+#define MIXER_PORT_CD_R 0x0700
+#define MIXER_PORT_LINE_IN_L 0x0800
+#define MIXER_PORT_LINE_IN_R 0x0900
+#define MIXER_PORT_POTS_REC 0x0C00
+#define MIXER_PORT_MIC 0x0E00
+
+#define GAIN12DB 0x00
+#define GAIN10DB 0x01
+#define GAIN08DB 0x02
+#define GAIN06DB 0x03
+#define GAIN04DB 0x04
+#define GAIN02DB 0x05
+#define GAIN00DB 0x06
+#define GAIN_02DB 0x07
+#define GAIN_04DB 0x08
+#define GAIN_06DB 0x09
+#define GAIN_08DB 0x0A
+#define GAIN_10DB 0x0B
+#define GAIN_12DB 0x0C
+#define GAIN_14DB 0x0D
+#define GAIN_16DB 0x0E
+#define GAIN_18DB 0x0F
+#define GAIN_20DB 0x10
+#define GAIN_22DB 0x11
+#define GAIN_24DB 0x12
+#define GAIN_26DB 0x13
+#define GAIN_28DB 0x14
+#define GAIN_30DB 0x15
+#define GAIN_32DB 0x16
+#define GAIN_34DB 0x17
+#define GAIN_36DB 0x18
+#define GAIN_38DB 0x19
+#define GAIN_40DB 0x1A
+#define GAIN_42DB 0x1B
+#define GAIN_44DB 0x1C
+#define GAIN_46DB 0x1D
+#define GAIN_48DB 0x1E
+#define GAIN_50DB 0x1F
+#define INPUT_MUTE 0x80
+
+/******************************************************************************
+*
+* The POTS volume control use attenuation with 8 levels from 0dB to -28dB
+* with steps of 4dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+*
+******************************************************************************/
+#define MIXER_PORT_POTS_PLAY 0x0F00
+
+#define POTS_ATT_00DB 0x00
+#define POTS_ATT_04DB 0x01
+#define POTS_ATT_08DB 0x02
+#define POTS_ATT_12DB 0x03
+#define POTS_ATT_16DB 0x04
+#define POTS_ATT_20DB 0x05
+#define POTS_ATT_24DB 0x06
+#define POTS_ATT_28DB 0x07
+#define POTS_MUTE 0x80
+
+/******************************************************************************
+*
+* The DAA controls the interface to the PSTN port. The driver loads the
+* US coefficients by default, so if you live in a different country you
+* need to load the set for your countries phone system.
+*
+******************************************************************************/
+#define IXJCTL_DAA_COEFF_SET _IOW ('q', 0xD0, int)
+
+#define DAA_US 1 //PITA 8kHz
+#define DAA_UK 2 //ISAR34 8kHz
+#define DAA_FRANCE 3 //
+#define DAA_GERMANY 4
+#define DAA_AUSTRALIA 5
+#define DAA_JAPAN 6
+
+/******************************************************************************
+*
+* Use IXJCTL_PORT to set or query the port the card is set to. If the
+* argument is set to PORT_QUERY, the return value of the ioctl will
+* indicate which port is currently in use, otherwise it will change the
+* port.
+*
+******************************************************************************/
+#define IXJCTL_PORT _IOW ('q', 0xD1, int)
+
+#define PORT_QUERY 0
+#define PORT_POTS 1
+#define PORT_PSTN 2
+#define PORT_SPEAKER 3
+#define PORT_HANDSET 4
+
+#define IXJCTL_PSTN_SET_STATE PHONE_PSTN_SET_STATE
+#define IXJCTL_PSTN_GET_STATE PHONE_PSTN_GET_STATE
+
+#define PSTN_ON_HOOK 0
+#define PSTN_RINGING 1
+#define PSTN_OFF_HOOK 2
+#define PSTN_PULSE_DIAL 3
+
+/******************************************************************************
+*
+* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR),
+* and the transmit gain (AGX). OR together the components and pass them
+* as the parameter to IXJCTL_DAA_AGAIN. The default setting is both at 0dB.
+*
+******************************************************************************/
+#define IXJCTL_DAA_AGAIN _IOW ('q', 0xD2, int)
+
+#define AGRR00DB 0x00 // Analog gain in receive direction 0dB
+#define AGRR3_5DB 0x10 // Analog gain in receive direction 3.5dB
+#define AGRR06DB 0x30 // Analog gain in receive direction 6dB
+
+#define AGX00DB 0x00 // Analog gain in transmit direction 0dB
+#define AGX_6DB 0x04 // Analog gain in transmit direction -6dB
+#define AGX3_5DB 0x08 // Analog gain in transmit direction 3.5dB
+#define AGX_2_5B 0x0C // Analog gain in transmit direction -2.5dB
+
+#define IXJCTL_PSTN_LINETEST _IO ('q', 0xD3)
+
+typedef struct {
+ char month[3];
+ char day[3];
+ char hour[3];
+ char min[3];
+ int numlen;
+ char number[11];
+ int namelen;
+ char name[80];
+} IXJ_CID;
+
+#define IXJCTL_CID _IOR ('q', 0xD4, IXJ_CID *)
+/******************************************************************************
+*
+* The wink duration is tunable with this ioctl. The default wink duration
+* is 320ms. You do not need to use this ioctl if you do not require a
+* different wink duration.
+*
+******************************************************************************/
+#define IXJCTL_WINK_DURATION PHONE_WINK_DURATION
+
+/******************************************************************************
+*
+* This ioctl will connect the POTS port to the PSTN port on the LineJACK
+* In order for this to work properly the port selection should be set to
+* the PSTN port with IXJCTL_PORT prior to calling this ioctl. This will
+* enable conference calls between PSTN callers and network callers.
+* Passing a 1 to this ioctl enables the POTS<->PSTN connection while
+* passing a 0 turns it back off.
+*
+******************************************************************************/
+#define IXJCTL_POTS_PSTN _IOW ('q', 0xD5, int)
+
+/******************************************************************************
+*
+* IOCTLs added by request.
+*
+* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in
+* /usr/include/asm/param.h, this determines the fundamental
+* frequency of the clock ticks on your Linux system. The kernel
+* must be rebuilt if you change this value, also all modules you
+* use (except this one) must be recompiled. The default value
+* is 100, and you only need to use this IOCTL if you use some
+* other value.
+*
+*
+* IXJCTL_RATE sets the number of times per second that the driver polls
+* the DSP. This value cannot be larger than HZ. By
+* increasing both of these values, you may be able to reduce
+* latency because the max hang time that can exist between the
+* driver and the DSP will be reduced.
+*
+******************************************************************************/
+
+#define IXJCTL_HZ _IOW ('q', 0xE0, int)
+#define IXJCTL_RATE _IOW ('q', 0xE1, int)
+#define IXJCTL_FRAMES_READ _IOR ('q', 0xE2, unsigned long)
+#define IXJCTL_FRAMES_WRITTEN _IOR ('q', 0xE3, unsigned long)
+#define IXJCTL_READ_WAIT _IOR ('q', 0xE4, unsigned long)
+#define IXJCTL_WRITE_WAIT _IOR ('q', 0xE5, unsigned long)
+#define IXJCTL_DRYBUFFER_READ _IOR ('q', 0xE6, unsigned long)
+#define IXJCTL_DRYBUFFER_CLEAR _IO ('q', 0xE7)
+
+/******************************************************************************
+*
+* The intercom IOCTL's short the output from one card to the input of the
+* other and vice versa (actually done in the DSP read function). It is only
+* necessary to execute the IOCTL on one card, but it is necessary to have
+* both devices open to be able to detect hook switch changes. The record
+* codec and rate of each card must match the playback codec and rate of
+* the other card for this to work properly.
+*
+******************************************************************************/
+
+#define IXJCTL_INTERCOM_START _IOW ('q', 0xFD, int)
+#define IXJCTL_INTERCOM_STOP _IOW ('q', 0xFE, int)
#define AURORA_MAJOR 79
+#define PHONE_MAJOR 100
+
#define RTF_MAJOR 150
#define RAW_MAJOR 162
extern void show_free_areas(void);
extern void show_free_areas_node(int nid);
-extern struct page * put_dirty_page(struct task_struct * tsk, struct page *page,
- unsigned long address);
extern void clear_page_tables(struct mm_struct *, unsigned long, int);
--- /dev/null
+#ifndef __LINUX_PHONEDEV_H
+#define __LINUX_PHONEDEV_H
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+struct phone_device {
+ struct phone_device *next;
+ struct file_operations *f_op;
+ int (*open) (struct phone_device *, struct file *);
+ int board; /* Device private index */
+ int minor;
+};
+
+extern int phonedev_init(void);
+#define PHONE_MAJOR 100
+extern int phone_register_device(struct phone_device *, int unit);
+#define PHONE_UNIT_ANY -1
+extern void phone_unregister_device(struct phone_device *);
+
+#endif
+#endif
--- /dev/null
+/*
+ * telephony.h
+ *
+ * Basic Linux Telephony Interface
+ *
+ * (c) Copyright 1999 Quicknet Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Ed Okerson, <eokerson@quicknet.net>
+ * Greg Herlein, <gherlein@quicknet.net>
+ *
+ * Contributors: Alan Cox, <acox@redhat.com>
+ * David Erhart, <derhart@quicknet.net>
+ *
+ * Version: 0.1.0 - December 19, 1999
+ *
+ * Fixes:
+ */
+
+#ifndef TELEPHONY_H
+#define TELEPHONY_H
+
+/* vendor identification numbers */
+#define PHONE_VENDOR_IXJ 1
+#define PHONE_VENDOR_QUICKNET PHONE_IXJ
+#define PHONE_VENDOR_VOICETRONIX 2
+#define PHONE_VENDOR_ACULAB 3
+#define PHONE_VENDOR_DIGI 4
+#define PHONE_VENDOR_FRANKLIN 5
+
+/******************************************************************************
+ * Vendor Summary Information Area
+ *
+ * Quicknet Technologies, Inc. - makes low density analog telephony cards
+ * with audio compression, POTS and PSTN interfaces (www.quicknet.net)
+ *
+ * (other vendors following this API shuld add a short description of
+ * the telephony products they support under Linux)
+ *
+ *****************************************************************************/
+
+
+/******************************************************************************
+*
+* The capabilities ioctls can inform you of the capabilities of each phone
+* device installed in your system. The PHONECTL_CAPABILITIES ioctl
+* returns an integer value indicating the number of capabilities the
+* device has. The PHONECTL_CAPABILITIES_LIST will fill an array of
+* capability structs with all of it's capabilities. The
+* PHONECTL_CAPABILITIES_CHECK takes a single capability struct and returns
+* a TRUE if the device has that capability, otherwise it returns false.
+*
+******************************************************************************/
+typedef enum {
+ vendor = 0,
+ device,
+ port,
+ codec,
+ dsp
+} phone_cap;
+
+struct phone_capability {
+ char desc[80];
+ phone_cap captype;
+ int cap;
+ int handle;
+};
+
+typedef enum {
+ pots = 0,
+ pstn,
+ handset,
+ speaker
+} phone_ports;
+
+#define PHONE_CAPABILITIES _IO ('q', 0x80)
+#define PHONE_CAPABILITIES_LIST _IOR ('q', 0x81, struct phone_capability *)
+#define PHONE_CAPABILITIES_CHECK _IOW ('q', 0x82, struct phone_capability *)
+
+#define PHONE_RING _IO ('q', 0x83)
+#define PHONE_HOOKSTATE _IO ('q', 0x84)
+#define PHONE_MAXRINGS _IOW ('q', 0x85, char)
+#define PHONE_RING_CADENCE _IOW ('q', 0x86, short)
+#define PHONE_RING_START _IO ('q', 0x87)
+#define PHONE_RING_STOP _IO ('q', 0x88)
+
+#define USA_RING_CADENCE 0xC0C0
+
+#define PHONE_REC_CODEC _IOW ('q', 0x89, int)
+#define PHONE_REC_START _IO ('q', 0x8A)
+#define PHONE_REC_STOP _IO ('q', 0x8B)
+#define PHONE_REC_DEPTH _IOW ('q', 0x8C, int)
+#define PHONE_FRAME _IOW ('q', 0x8D, int)
+#define PHONE_REC_VOLUME _IOW ('q', 0x8E, int)
+#define PHONE_REC_LEVEL _IO ('q', 0x8F)
+
+#define PHONE_PLAY_CODEC _IOW ('q', 0x90, int)
+#define PHONE_PLAY_START _IO ('q', 0x91)
+#define PHONE_PLAY_STOP _IO ('q', 0x92)
+#define PHONE_PLAY_DEPTH _IOW ('q', 0x93, int)
+#define PHONE_PLAY_VOLUME _IOW ('q', 0x94, int)
+#define PHONE_PLAY_LEVEL _IO ('q', 0x95)
+#define PHONE_DTMF_READY _IOR ('q', 0x96, int)
+#define PHONE_GET_DTMF _IOR ('q', 0x97, int)
+#define PHONE_GET_DTMF_ASCII _IOR ('q', 0x98, int)
+#define PHONE_DTMF_OOB _IOW ('q', 0x99, int)
+#define PHONE_EXCEPTION _IOR ('q', 0x9A, int)
+#define PHONE_PLAY_TONE _IOW ('q', 0x9B, char)
+#define PHONE_SET_TONE_ON_TIME _IOW ('q', 0x9C, int)
+#define PHONE_SET_TONE_OFF_TIME _IOW ('q', 0x9D, int)
+#define PHONE_GET_TONE_ON_TIME _IO ('q', 0x9E)
+#define PHONE_GET_TONE_OFF_TIME _IO ('q', 0x9F)
+#define PHONE_GET_TONE_STATE _IO ('q', 0xA0)
+#define PHONE_BUSY _IO ('q', 0xA1)
+#define PHONE_RINGBACK _IO ('q', 0xA2)
+#define PHONE_DIALTONE _IO ('q', 0xA3)
+#define PHONE_CPT_STOP _IO ('q', 0xA4)
+
+#define PHONE_PSTN_SET_STATE _IOW ('q', 0xA4, int)
+#define PHONE_PSTN_GET_STATE _IO ('q', 0xA5)
+
+#define PSTN_ON_HOOK 0
+#define PSTN_RINGING 1
+#define PSTN_OFF_HOOK 2
+#define PSTN_PULSE_DIAL 3
+
+/******************************************************************************
+*
+* The wink duration is tunable with this ioctl. The default wink duration
+* is 320ms. You do not need to use this ioctl if you do not require a
+* different wink duration.
+*
+******************************************************************************/
+#define PHONE_WINK_DURATION _IOW ('q', 0xA6, int)
+
+
+/******************************************************************************
+*
+* Codec Definitions
+*
+******************************************************************************/
+typedef enum {
+ G723_63 = 1,
+ G723_53 = 2,
+ TS85 = 3,
+ TS48 = 4,
+ TS41 = 5,
+ G728 = 6,
+ G729 = 7,
+ ULAW = 8,
+ ALAW = 9,
+ LINEAR16 = 10,
+ LINEAR8 = 11,
+ WSS = 12
+} phone_codec;
+
+/******************************************************************************
+*
+* The exception structure allows us to multiplex multiple events onto the
+* select() exception set. If any of these flags are set select() will
+* return with a positive indication on the exception set. The dtmf_ready
+* bit indicates if there is data waiting in the DTMF buffer. The
+* hookstate bit is set if there is a change in hookstate status, it does not
+* indicate the current state of the hookswitch. The pstn_ring bit
+* indicates that the DAA on a LineJACK card has detected ring voltage on
+* the PSTN port. The caller_id bit indicates that caller_id data has been
+* recieved and is available. The pstn_wink bit indicates that the DAA on
+* the LineJACK has recieved a wink from the telco switch. The f0, f1, f2
+* and f3 bits indicate that the filter has been triggered by detecting the
+* frequency programmed into that filter.
+*
+* The remaining bits should be set to zero. They will become defined over time
+* for other interface cards and their needs.
+*
+******************************************************************************/
+struct phone_except
+{
+ unsigned int dtmf_ready:1;
+ unsigned int hookstate:1;
+ unsigned int pstn_ring:1;
+ unsigned int caller_id:1;
+ unsigned int pstn_wink:1;
+ unsigned int f0:1;
+ unsigned int f1:1;
+ unsigned int f2:1;
+ unsigned int f3:1;
+ unsigned int reserved:23;
+};
+
+union telephony_exception {
+ struct phone_except bits;
+ unsigned int bytes;
+};
+
+
+#endif /* TELEPHONY_H */
int teletext; /* Teletext minor */
};
+struct vbi_format {
+ __u32 sampling_rate; /* in Hz */
+ __u32 samples_per_line;
+ __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */
+ __s32 start[2]; /* starting line for each frame */
+ __u32 count[2]; /* count of lines for each frame */
+ __u32 flags;
+#define VBI_UNSYNC 1 /* can distingues between top/bottom field */
+#define VBI_INTERLACED 2 /* lines are interlaced */
+};
+
/* video_info is biased towards hardware mpeg encode/decode */
/* but it could apply generically to any hardware compressor/decompressor */
struct video_info
#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
-#define VIDIOCGMBUF _IOR('v', 20, struct video_mbuf) /* Memory map buffer info */
-#define VIDIOCGUNIT _IOR('v', 21, struct video_unit) /* Get attached units */
-#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get frame buffer */
-#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set frame buffer - root only */
+#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */
+#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */
+#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */
+#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */
#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */
#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */
#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */
#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */
+#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */
+#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */
+
#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Wed Dec 8 10:49:17 1999
+ * Modified at: Tue Dec 21 11:20:30 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
RECV_TEST_RSP,
RECV_UA_RSP,
RECV_DM_RSP,
+ RECV_RD_RSP,
RECV_I_CMD,
RECV_I_RSP,
RECV_UI_FRAME,
RECV_FRMR_RSP,
RECV_RR_CMD,
RECV_RR_RSP,
- RECV_RNR_FRAME,
- RECV_DISC_FRAME,
+ RECV_RNR_CMD,
+ RECV_RNR_RSP,
+ RECV_REJ_CMD,
+ RECV_REJ_RSP,
+ RECV_SREJ_CMD,
+ RECV_SREJ_RSP,
+ RECV_DISC_CMD,
/* Timer events */
SLOT_TIMER_EXPIRED,
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Aug 19 10:27:26 1997
- * Modified at: Thu Dec 9 15:50:09 1999
+ * Modified at: Tue Dec 21 11:10:12 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>,
void irlap_send_test_frame(struct irlap_cb *self, __u32 daddr,
struct sk_buff *cmd);
void irlap_send_ua_response_frame(struct irlap_cb *, struct qos_info *);
-void irlap_send_dm_frame(struct irlap_cb *);
-void irlap_send_disc_frame(struct irlap_cb *);
-void irlap_send_rr_frame(struct irlap_cb *, int command);
+void irlap_send_dm_frame(struct irlap_cb *self);
+void irlap_send_rd_frame(struct irlap_cb *self);
+void irlap_send_disc_frame(struct irlap_cb *self);
+void irlap_send_rr_frame(struct irlap_cb *self, int command);
void irlap_send_data_primary(struct irlap_cb *, struct sk_buff *);
void irlap_send_data_primary_poll(struct irlap_cb *, struct sk_buff *);
void irlap_send_data_secondary(struct irlap_cb *, struct sk_buff *);
void irlap_send_data_secondary_final(struct irlap_cb *, struct sk_buff *);
void irlap_resend_rejected_frames(struct irlap_cb *, int command);
+void irlap_resend_rejected_frame(struct irlap_cb *self, int command);
void irlap_send_i_frame(struct irlap_cb *, struct sk_buff *, int command);
void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
tsk = cpu_curr(this_cpu);
if (preemption_goodness(tsk, p, this_cpu) > 0)
tsk->need_resched = 1;
+ spin_unlock_irqrestore(&runqueue_lock, flags);
#endif
}
} else
bh->b_end_io = bounce_end_io_read;
bh->b_dev_id = (void *)bh_orig;
- bh->b_rsector = -1;
+ bh->b_rsector = bh_orig->b_rsector;
memset(&bh->b_wait, -1, sizeof(bh->b_wait));
bh->b_kiobuf = NULL;
return error;
}
-/*
- * This routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
- */
-struct page * put_dirty_page(struct task_struct * tsk, struct page *page,
- unsigned long address)
-{
- pgd_t * pgd;
- pmd_t * pmd;
- pte_t * pte;
-
- if (page_count(page) != 1)
- printk("mem_map disagrees with %p at %08lx\n", page, address);
- pgd = pgd_offset(tsk->mm, address);
- pmd = pmd_alloc(pgd, address);
- if (!pmd) {
- __free_page(page);
- oom(tsk);
- return 0;
- }
- pte = pte_alloc(pmd, address);
- if (!pte) {
- __free_page(page);
- oom(tsk);
- return 0;
- }
- if (!pte_none(*pte)) {
- pte_ERROR(*pte);
- __free_page(page);
- return 0;
- }
- flush_page_to_ram(page);
- set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_COPY)));
-/* no need for flush_tlb */
- return page;
-}
-
/*
* This routine handles present pages, when users try to write
* to a shared page. It is done by copying the page to a new address
#include <linux/rtnetlink.h>
#include <net/br.h>
#include <linux/proc_fs.h>
+#include <linux/br.h>
#ifndef min
#define min(a, b) (((a) <= (b)) ? (a) : (b))
/* Set up MAC address based on BogoMIPs figure for first CPU and time
*/
- bogomips = (boot_cpu_data.loops_per_sec+2500)/500000 ;
+ bogomips = (loops_per_sec+2500)/500000 ;
get_fast_time(&utime);
/* Ummmm.... YES! */
struct sock *sk = sock->sk;
struct irda_sock *self;
struct irda_ias_set ias_opt;
- struct ias_object * ias_obj;
+ struct ias_object *ias_obj;
int opt;
self = sk->protinfo.irda;
IRDA_DEBUG(0, __FUNCTION__ "(), sorry not impl. yet!\n");
return -ENOPROTOOPT;
- case IRTTP_MAX_SDU_SIZE:
+ case IRLMP_MAX_SDU_SIZE:
if (optlen < sizeof(int))
return -EINVAL;
sizeof(struct irda_device_info)))
return -EFAULT;
break;
- case IRTTP_MAX_SDU_SIZE:
+ case IRLMP_MAX_SDU_SIZE:
val = self->max_data_size;
len = sizeof(int);
if (put_user(len, optlen))
ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
/* Remove TSAP */
- if (self->tsap)
+ if (self->tsap) {
irttp_close_tsap(self->tsap);
- self->tsap = NULL;
+ self->tsap = NULL;
+ }
/* Remove LSAP */
if (self->lsap) {
/*
* If we receive data when hardware is stopped then something is wrong.
* We try to poll the peers line settings to check if we are up todate.
+ * Devices like WinCE can do this, and since they don't send any
+ * params, we can just as well declare the hardware for running.
*/
if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
IRDA_DEBUG(0, __FUNCTION__ "(), polling for line settings!\n");
ircomm_param_request(self, IRCOMM_POLL, TRUE);
+
+ /* We can just as well declare the hardware for running */
+ ircomm_tty_send_initial_parameters(self);
+ ircomm_tty_link_established(self);
}
/*
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Oct 9 09:22:27 1999
- * Modified at: Sun Dec 12 12:24:32 1999
+ * Modified at: Tue Dec 21 21:53:45 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
dev->hard_header_len = 0;
dev->addr_len = 0;
- /* dev->new_style = 1; */
+ dev->new_style = 1;
/* dev->destructor = irda_device_destructor; */
dev->type = ARPHRD_IRDA;
{
struct iriap_cb *self;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC);
if (!self) {
del_timer(&self->watchdog_timer);
+ if (self->skb)
+ dev_kfree_skb(self->skb);
+
self->magic = 0;
kfree(self);
{
struct iriap_cb *entry;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
{
notify_t notify;
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
irda_notify_init(¬ify);
notify.connect_confirm = iriap_connect_confirm;
IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as server\n");
iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION,
NULL);
+ iriap_close(self);
}
if (userdata)
break;
}
iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb);
-
- iriap_close(self);
}
/*
memcpy(attr, fp+n, attr_len); n+=attr_len;
attr[attr_len] = '\0';
+ /* We do not need the buffer anymore */
dev_kfree_skb(skb);
- /*
- * Now, do some advanced parsing! :-)
- */
IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
obj = irias_find_object(name);
if (obj == NULL) {
- IRDA_DEBUG(2, "LM-IAS: Object not found\n");
+ IRDA_DEBUG(2, "LM-IAS: Object %s not found\n", name);
iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN,
&missing);
return;
attrib = irias_find_attrib(obj, attr);
if (attrib == NULL) {
- IRDA_DEBUG(0, "LM-IAS: Attribute %s not found\n", attr);
+ IRDA_DEBUG(2, "LM-IAS: Attribute %s not found\n", attr);
iriap_getvaluebyclass_response(self, obj->id,
IAS_ATTRIB_UNKNOWN, &missing);
return;
}
- IRDA_DEBUG(4, "LM-IAS: found %s\n", attrib->name);
-
- /*
- * We have a match; send the value.
- */
+ /* We have a match; send the value. */
iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS,
attrib->value);
-
+
return;
}
switch (event) {
case IAP_CALL_REQUEST_GVBC:
iriap_next_client_state(self, S_CONNECTING);
+ ASSERT(self->skb == NULL, return;);
self->skb = skb;
ret = irlmp_connect_request(self->lsap, LSAP_IAS,
self->saddr, self->daddr,
/*********************************************************************
*
* Filename: irlap_event.c
- * Version: 0.8
+ * Version: 0.9
* Description: IrLAP state machine implementation
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Tue Dec 14 18:58:28 1999
+ * Modified at: Tue Dec 21 11:27:22 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
"RECV_TEST_RSP",
"RECV_UA_RSP",
"RECV_DM_RSP",
+ "RECV_RD_RSP",
"RECV_I_CMD",
"RECV_I_RSP",
"RECV_UI_FRAME",
"RECV_FRMR_RSP",
"RECV_RR_CMD",
"RECV_RR_RSP",
- "RECV_RNR_FRAME",
- "RECV_DISC_FRAME",
+ "RECV_RNR_CMD",
+ "RECV_RNR_RSP",
+ "RECV_REJ_CMD",
+ "RECV_REJ_RSP",
+ "RECV_SREJ_CMD",
+ "RECV_SREJ_RSP",
+ "RECV_DISC_CMD",
"SLOT_TIMER_EXPIRED",
"QUERY_TIMER_EXPIRED",
"FINAL_TIMER_EXPIRED",
irlap_connect_indication(self, skb);
} else {
- IRDA_DEBUG(0, __FUNCTION__
- "(), SNRM frame does not contain"
- " and I field!\n");
+ IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame does not "
+ "contain an I field!\n");
dev_kfree_skb(skb);
}
break;
irlap_connect_confirm(self, skb);
break;
- case RECV_DISC_FRAME:
+ case RECV_DM_RSP: /* FALLTHROUGH */
+ case RECV_DISC_CMD:
del_timer(&self->final_timer);
irlap_next_state(self, LAP_NDM);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
dev_kfree_skb(skb);
break;
- /* DM handled in irlap_frame.c, irlap_driver_rcv() */
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
irlap_event[event]);
ASSERT(self->magic == LAP_MAGIC, return -1;);
switch (event) {
- case RECV_UA_RSP:
+ case RECV_UA_RSP: /* FALLTHROUGH */
+ case RECV_DM_RSP:
del_timer(&self->final_timer);
irlap_apply_default_connection_parameters(self);
} else {
irlap_apply_default_connection_parameters(self);
- /*
- * Always switch state before calling upper layers
- */
+ /* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
}
dev_kfree_skb(skb);
break;
- case RECV_RNR_FRAME:
- IRDA_DEBUG(4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
- "nr=%d, va=%d, vs=%d, vr=%d\n",
- self->retry_count, info->nr, self->va, self->vs,
- self->vr);
-
+ case RECV_RNR_RSP:
ASSERT(info != NULL, return -1;);
/* Stop final timer */
* of receiving a frame (page 45, IrLAP). Check that
* we only do this once for each frame.
*/
- if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
+ if (irda_device_is_receiving(self->netdev) &&
+ !self->add_wait)
+ {
IRDA_DEBUG(1, "FINAL_TIMER_EXPIRED when receiving a "
"frame! Waiting a little bit more!\n");
irlap_start_final_timer(self, MSECS_TO_JIFFIES(300));
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
}
break;
- case RECV_DISC_FRAME: /* FIXME: Check how this is in the standard! */
- IRDA_DEBUG(1, __FUNCTION__ "(), RECV_DISC_FRAME()\n");
-
- /* Always switch state before calling upper layers */
- irlap_next_state(self, LAP_NDM);
-
- irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_ua_response_frame(self, NULL);
-
- del_timer(&self->final_timer);
- /* del_timer( &self->poll_timer); */
+ case RECV_REJ_RSP:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frames(self, CMD_FRAME);
+ irlap_start_final_timer(self, self->final_timeout);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_SREJ_RSP:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frame(self, CMD_FRAME);
+ irlap_start_final_timer(self, self->final_timeout);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_RD_RSP:
+ IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n");
+ irlap_next_state(self, LAP_PCLOSE);
+ irlap_send_disc_frame(self);
irlap_flush_all_queues(self);
- irlap_apply_default_connection_parameters(self);
-
- irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- dev_kfree_skb(skb);
+ irlap_start_final_timer(self, self->final_timeout);
+ self->retry_count = 0;
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
-
if (skb)
dev_kfree_skb(skb);
ASSERT(self->magic == LAP_MAGIC, return -1;);
switch (event) {
- case RECV_DISC_FRAME:
+ case RECV_DISC_CMD:
del_timer(&self->final_timer);
irlap_apply_default_connection_parameters(self);
} else {
IRDA_DEBUG(0, __FUNCTION__
"(), SNRM frame contained an I field!\n");
-
}
dev_kfree_skb(skb);
break;
ret = -EPROTO;
}
break;
+ case DISCONNECT_REQUEST:
+ irlap_send_rd_frame(self);
+ irlap_flush_all_queues(self);
+ irlap_start_wd_timer(self, self->wd_timeout);
+ irlap_next_state(self, LAP_SCLOSE);
+ break;
default:
IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
* Starting WD-timer here is optional, but
* not recommended. Note 6 IrLAP p. 83
*/
- /* irda_start_timer(WD_TIMER, self->wd_timeout); */
-
+#if 0
+ irda_start_timer(WD_TIMER, self->wd_timeout);
+#endif
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_S);
}
dev_kfree_skb(skb);
break;
+ case RECV_REJ_CMD:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frames(self, CMD_FRAME);
+ irlap_start_wd_timer(self, self->wd_timeout);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_SREJ_CMD:
+ irlap_update_nr_received(self, info->nr);
+ if (self->remote_busy) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rr_frame(self, CMD_FRAME);
+ } else
+ irlap_resend_rejected_frame(self, CMD_FRAME);
+ irlap_start_wd_timer(self, self->wd_timeout);
+ dev_kfree_skb(skb);
+ break;
case WD_TIMER_EXPIRED:
/*
* Wait until retry_count * n matches negotiated threshold/
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
}
break;
- case RECV_DISC_FRAME:
+ case RECV_DISC_CMD:
/* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
struct sk_buff *skb, struct irlap_info *info)
{
- IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n");
+ int ret = 0;
+
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ ASSERT(self != NULL, return -ENODEV;);
+ ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+
+ switch (event) {
+ case RECV_DISC_CMD:
+ /* Always switch state before calling upper layers */
+ irlap_next_state(self, LAP_NDM);
+
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_ua_response_frame(self, NULL);
+ del_timer(&self->wd_timer);
+ irlap_apply_default_connection_parameters(self);
+
+ irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+ dev_kfree_skb(skb);
+ break;
+ case RECV_DM_RSP:
+ /* Always switch state before calling upper layers */
+ irlap_next_state(self, LAP_NDM);
- if (skb)
+ del_timer(&self->wd_timer);
+ irlap_apply_default_connection_parameters(self);
+
+ irlap_disconnect_indication(self, LAP_DISC_INDICATION);
dev_kfree_skb(skb);
+ break;
+ case WD_TIMER_EXPIRED:
+ irlap_apply_default_connection_parameters(self);
+
+ irlap_disconnect_indication(self, LAP_DISC_INDICATION);
+ break;
+ default:
+ IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
+ event, irlap_event[event]);
+ if (skb)
+ dev_kfree_skb(skb);
+
+ ret = -EINVAL;
+ break;
+ }
return -1;
}
irlap_next_state(self, LAP_NRM_S);
break;
case DISCONNECT_REQUEST:
- irlap_wait_min_turn_around( self, &self->qos_tx);
- /* irlap_send_rd_frame(self); */
- irlap_start_wd_timer( self, WD_TIMEOUT);
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+ irlap_send_rd_frame(self);
+ irlap_start_wd_timer(self, WD_TIMEOUT);
+ irlap_next_state(self, LAP_SCLOSE);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
- event, irlap_event[event]);
-
+ event, irlap_event[event]);
if (skb)
dev_kfree_skb(skb);
* Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Aug 19 10:27:26 1997
- * Modified at: Tue Dec 14 09:45:25 1999
+ * Modified at: Tue Dec 21 11:19:19 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
self->mtt_required = 0;
/*
- * Delay equals negotiated BOFs count plus the number of BOFs to
+ * Delay equals negotiated BOFs count, plus the number of BOFs to
* force the negotiated minimum turnaround time
*/
cb->xbofs = self->bofs_count+self->xbofs_delay;
irlap_queue_xmit(self, skb);
}
+/*
+ * Function irlap_send_rd_frame (self)
+ *
+ * Request disconnect. Used by a secondary station to request the
+ * disconnection of the link.
+ */
+void irlap_send_rd_frame(struct irlap_cb *self)
+{
+ struct sk_buff *skb;
+ __u8 *frame;
+
+ skb = dev_alloc_skb(16);
+ if (!skb)
+ return;
+
+ frame = skb_put(skb, 2);
+
+ frame[0] = self->caddr;
+ frame[1] = RD_RSP | PF_BIT;
+
+ irlap_queue_xmit(self, skb);
+}
+
/*
* Function irlap_recv_rr_frame (skb, info)
*
*
*/
static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info)
+ struct irlap_info *info, int command)
{
- ASSERT(skb != NULL, return;);
- ASSERT(info != NULL, return;);
-
info->nr = skb->data[1] >> 5;
IRDA_DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
- irlap_do_event(self, RECV_RNR_FRAME, skb, info);
+ if (command)
+ irlap_do_event(self, RECV_RNR_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_RNR_RSP, skb, info);
+}
+
+static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ info->nr = skb->data[1] >> 5;
+
+ /* Check if this is a command or a response frame */
+ if (command)
+ irlap_do_event(self, RECV_REJ_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_REJ_RSP, skb, info);
+}
+
+static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ info->nr = skb->data[1] >> 5;
+
+ /* Check if this is a command or a response frame */
+ if (command)
+ irlap_do_event(self, RECV_SREJ_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_SREJ_RSP, skb, info);
+}
+
+static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
+{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+ /* Check if this is a command or a response frame */
+ if (command)
+ irlap_do_event(self, RECV_DISC_CMD, skb, info);
+ else
+ irlap_do_event(self, RECV_RD_RSP, skb, info);
}
/*
* Received UA (Unnumbered Acknowledgement) frame
*
*/
-static void irlap_recv_ua_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info)
+static inline void irlap_recv_ua_frame(struct irlap_cb *self,
+ struct sk_buff *skb,
+ struct irlap_info *info)
{
irlap_do_event(self, RECV_UA_RSP, skb, info);
}
irlap_send_i_frame( self, tx_skb, CMD_FRAME);
} else {
- IRDA_DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
+ IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
self->window -= 1;
}
/*
* Function irlap_resend_rejected_frames (nr)
*
- * Resend frames which has not been acknowledged. TODO: check that the
- * traversal of the list is atomic, i.e that no-one tries to insert or
- * remove frames from the list while we travers it!
- *
- * FIXME: It is not safe to traverse a this list without locking it!
+ * Resend frames which has not been acknowledged. Should be safe to
+ * traverse the list without locking it since this function will only be
+ * called from interrupt context (BH)
*/
-void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
+void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
{
struct sk_buff *tx_skb;
struct sk_buff *skb;
/* Initialize variables */
skb = tx_skb = NULL;
- /*
- * Resend all unacknowledged frames
- */
count = skb_queue_len(&self->wx_list);
+
+ /* Resend unacknowledged frame(s) */
skb = skb_peek(&self->wx_list);
while (skb != NULL) {
irlap_wait_min_turn_around(self, &self->qos_tx);
*/
/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
tx_skb = skb_copy(skb, GFP_ATOMIC);
- if (tx_skb == NULL) {
- /* Unlink tx_skb from list */
- tx_skb->next = tx_skb->prev = NULL;
- tx_skb->list = NULL;
-
- dev_kfree_skb(skb);
- return;
+ if (!tx_skb) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+ return;
}
/* Unlink tx_skb from list */
tx_skb->next = tx_skb->prev = NULL;
* If our skb is the last buffer in the list, then
* we are finished, if not, move to the next sk-buffer
*/
- if (skb == skb_peek_tail( &self->wx_list))
+ if (skb == skb_peek_tail(&self->wx_list))
skb = NULL;
else
skb = skb->next;
}
+#if 0 /* Not yet */
/*
* We can now fill the window with additinal data frames
*/
- return; /* Skip this for now, DB */
-
while (skb_queue_len( &self->txq) > 0) {
IRDA_DEBUG(0, __FUNCTION__ "(), sending additional frames!\n");
}
}
}
+#endif
+}
+
+void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
+{
+ struct sk_buff *tx_skb;
+ struct sk_buff *skb;
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+
+ /* Initialize variables */
+ skb = tx_skb = NULL;
+
+ /* Resend unacknowledged frame(s) */
+ skb = skb_peek(&self->wx_list);
+ if (skb != NULL) {
+ irlap_wait_min_turn_around(self, &self->qos_tx);
+
+ /* We copy the skb to be retransmitted since we will have to
+ * modify it. Cloning will confuse packet sniffers
+ */
+ /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+ tx_skb = skb_copy(skb, GFP_ATOMIC);
+ if (!tx_skb) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), unable to copy\n");
+ return;
+ }
+ /* Unlink tx_skb from list */
+ tx_skb->next = tx_skb->prev = NULL;
+ tx_skb->list = NULL;
+
+ /*
+ * make sure the skb->sk accounting of memory usage is sane
+ */
+ if (skb->sk != NULL)
+ skb_set_owner_w(tx_skb, skb->sk);
+
+ /* Clear old Nr field + poll bit */
+ tx_skb->data[1] &= 0x0f;
+
+ /* Set poll/final bit */
+ tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
+
+ irlap_send_i_frame(self, tx_skb, command);
+ }
}
/*
frame = skb->data;
info->nr = frame[2] >> 5; /* Next to receive */
- info->pf = frame[2] & PF_BIT; /* Final bit */
+ info->pf = frame[2] & PF_BIT; /* Final bit */
info->ns = (frame[2] >> 1) & 0x07; /* Next to send */
w = frame[3] & 0x01;
* Receive a test frame
*
*/
-void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
- struct irlap_info *info, int command)
+static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
+ struct irlap_info *info, int command)
{
struct test_frame *frame;
irlap_recv_rr_frame(self, skb, &info, command);
break;
case RNR:
- irlap_recv_rnr_frame(self, skb, &info);
+ irlap_recv_rnr_frame(self, skb, &info, command);
break;
case REJ:
- IRDA_DEBUG( 0, "*** REJ frame received! ***\n");
- dev_kfree_skb(skb);
+ irlap_recv_rej_frame(self, skb, &info, command);
break;
case SREJ:
- IRDA_DEBUG( 0, "*** SREJ frame received! ***\n");
- dev_kfree_skb(skb);
+ irlap_recv_srej_frame(self, skb, &info, command);
break;
default:
WARNING(__FUNCTION__
irlap_recv_snrm_cmd(self, skb, &info);
break;
case DM_RSP:
- IRDA_DEBUG( 0, "DM rsp frame received!\n");
- irlap_next_state(self, LAP_NDM);
- dev_kfree_skb(skb);
+ irlap_do_event(self, RECV_DM_RSP, skb, &info);
break;
- case DISC_CMD:
- irlap_do_event(self, RECV_DISC_FRAME, skb, &info);
+ case DISC_CMD: /* And RD_RSP */
+ irlap_recv_disc_frame(self, skb, &info, command);
break;
case TEST_CMD:
irlap_recv_test_frame(self, skb, &info, command);
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Dec 15 13:55:39 1997
- * Modified at: Thu Dec 16 21:46:38 1999
+ * Modified at: Tue Dec 21 21:39:31 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
int __init irda_init(void)
{
- MESSAGE("IrDA (tm) Protocols for Linux-2.2 (Dag Brattli)\n");
+ MESSAGE("IrDA (tm) Protocols for Linux-2.3 (Dag Brattli)\n");
irlmp_init();
irlap_init();
self->connected = FALSE;
+ /* Check if client has already tried to close the TSAP */
+ if (self->close_pend) {
+ irttp_close_tsap(self);
+ return;
+ }
+
+ /* No need to notify the client if has already tried to disconnect */
+ if (self->disconnect_pend)
+ return;
+
if (self->notify.disconnect_indication)
- self->notify.disconnect_indication(self->notify.instance,
- self, reason, skb);
- else {
+ self->notify.disconnect_indication(self->notify.instance, self,
+ reason, skb);
+ else
if (skb)
dev_kfree_skb(skb);
- }
}
/*
{
int err;
+ /* Check if client has already tried to close the TSAP */
+ if (self->close_pend || self->disconnect_pend) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
err = self->notify.data_indication(self->notify.instance, self, skb);
/* Usually the layer above will notify that it's input queue is