diff -u --recursive --new-file v2.3.35/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.35/linux/Documentation/Configure.help Wed Dec 29 13:13:12 1999 +++ linux/Documentation/Configure.help Sun Jan 2 12:14:44 2000 @@ -7878,22 +7878,26 @@ The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB host controller). If your USB host controller conforms to this - standard, say Y. All recent boards with Intel PCI chipsets conform - to this standard. If unsure, say Y. + standard, say Y. All recent boards with Intel PCI chipsets (like + intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard. + Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo + Pro II or Apollo Pro 133). + If unsure, say Y. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usb-uhci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -OHCI-HCD (Compaq, iMacs, OPTi, SiS, and others) support? +OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, and others) support? CONFIG_USB_OHCI_HCD The Open Host Controller Interface is a standard by Compaq/Microsoft/National for accessing the USB PC hardware (also called USB host controller). If your USB host controller conforms to this standard, say Y. The USB host controllers on most - non-Intel architectures and on several x86 compatibles with - non-Intel chipsets conform to this standard. + non-Intel architectures and on several x86 compatibles with non-Intel + chipsets - like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V, + Aladin Pro..) - conform to this standard. You may want to read the file drivers/usb/README.ohci_hcd. @@ -7902,15 +7906,62 @@ The module will be called usb-ohci-hcd.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB mouse support +USB Human Interface Device (HID) support +CONFIG_USB_HID + Say Y here if you want to connect a keyboard, mouse, joystick, + graphic tablet, UPS or any other HID based devices to your computer + via USB. + +USB HIDBP Keyboard support +CONFIG_USB_KBD + Say Y here if you don't want to use the generic HID driver for your + USB keyboard and prefer to use the keyboard in its limited Boot + Protocol mode. This driver is much smaller than the HID one. + +USB HIDBP Mouse support CONFIG_USB_MOUSE - Say Y here if you want to connect a USB mouse to your computer's USB - port. + Say Y here if you don't want to use the generic HID driver for your + USB mouse and prefer to use the mouse in its limited Boot Protocol + mode. This driver is much smaller than the HID one. + +Keyboard support +CONFIG_INPUT_KEYBDEV + Say Y here if you want your USB HID keyboard to be able to serve as + a system keyboard. + +Mouse support +CONFIG_INPUT_MOUSEDEV + Say Y here if you want your USB HID mouse to be accessible as + misc devices 32+ under /dev/, as an emulated PS/2 mouse. + +Mix all mice into one device +CONFIG_INPUT_MOUSEDEV_MIX + Say Y here if you want input from all your USB HID mice to be mixed + into one misc device. If you say N, you'll have a separate + device for each your USB mouse. - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called mouse.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. +Joystick support +CONFIG_INPUT_JOYDEV + Say Y here if you want your USB HID joystick or gamepad to be + accessible as /dev/js device. You can't use a normal joystick + if you select this. + +Event interface support +CONFIG_INPUT_EVDEV + Say Y here if you want your USB HID device events be accessible + under /dev/inputX (misc 64+) in a generic way. + This is the future ... + +USB HID debug output +CONFIG_USB_HID_DEBUG + Say Y here if you want to see what the HID driver is doing, + perhaps it's doing something wrong with your device. + +USB HID lots of debug output +CONFIG_USB_HID_DEBUG_LOTS + Say Y here if you don't fear to read all the HID dumps the + HID driver will generate when you switch this on. Really LOTS + of debug output. USB scanner support CONFIG_USB_SCANNER @@ -7923,16 +7974,6 @@ The module will be called hp_scanner.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB keyboard support -CONFIG_USB_KBD - Say Y here if you want to connect a USB keyboard to your computer's - USB port. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called usb-keyboard.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. - USB audio parsing support CONFIG_USB_AUDIO Say Y here if you want to connect USB audio equipment such as @@ -7957,9 +7998,9 @@ USB serial converter support CONFIG_USB_SERIAL Say Y here if you want to connect a Connect Tech WhiteHEAT - multi-port USB to serial converter, or a Belkin, Peracom, or eTek - single port USB to serial converter. - + multi-port USB to serial converter; a Belkin, Peracom, or eTek + single port USB to serial converter; or a Handspring Visor. + This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called usb-serial.o. If you want to compile it @@ -7985,6 +8026,20 @@ The module will be called cpia.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +USB OV511 Camera support +CONFIG_USB_OV511 + Say Y here if you want to connect this type of camera to your + computer's USB port. See drivers/usb/README.ov511 for more + information and for a list of supported cameras. + + NOTE: This code is experimental and you will not get video with it + yet. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ov511.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + USB Kodak DC-2xx Camera support CONFIG_USB_DC2XX Say Y here if you want to connect this type of still camera to @@ -12621,6 +12676,25 @@ 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 # @@ -13474,4 +13548,4 @@ # LocalWords: adbmouse DRI DRM dlabs GMX PLCs Applicom fieldbus applicom int # LocalWords: VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU # LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator -# LocalWords: LOGIBUSMOUSE +# LocalWords: LOGIBUSMOUSE OV511 ov511 diff -u --recursive --new-file v2.3.35/linux/Documentation/i2c/writing-clients linux/Documentation/i2c/writing-clients --- v2.3.35/linux/Documentation/i2c/writing-clients Mon Dec 20 18:48:21 1999 +++ linux/Documentation/i2c/writing-clients Wed Dec 29 17:08:55 1999 @@ -356,7 +356,8 @@ 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 @@ -666,12 +667,6 @@ { 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 diff -u --recursive --new-file v2.3.35/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.3.35/linux/Documentation/parport.txt Sun Nov 7 16:37:33 1999 +++ linux/Documentation/parport.txt Thu Dec 30 10:11:57 1999 @@ -38,12 +38,16 @@ If you use kmod, you will find it useful to edit /etc/modules.conf. Here is an example of the lines that need to be added: - post-install parport modprobe -k parport_pc + alias parport_lowlevel parport_pc options parport_pc io=0x378,0x278 irq=7,auto KMod will then automatically load parport_pc (with the options "io=0x378,0x278 irq=7,auto") whenever a parallel port device driver (such as lp) is loaded. + +Note that these are example lines only! You shouldn't in general need +to specify any options to parport_pc in order to be able to use a +parallel port. Parport probe [optional] diff -u --recursive --new-file v2.3.35/linux/Documentation/telephony/ixj.txt linux/Documentation/telephony/ixj.txt --- v2.3.35/linux/Documentation/telephony/ixj.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/telephony/ixj.txt Wed Dec 29 17:13:59 1999 @@ -0,0 +1,406 @@ +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 + Ed Okerson + +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 + +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 + + + +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 + # + + 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. + + + + + + + + + + + + + + + + + diff -u --recursive --new-file v2.3.35/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST --- v2.3.35/linux/Documentation/video4linux/bttv/CARDLIST Mon Dec 20 18:48:21 1999 +++ linux/Documentation/video4linux/bttv/CARDLIST Wed Dec 29 17:08:55 1999 @@ -1,4 +1,3 @@ -make[1]: Entering directory `/home/kraxel/2/src/bttv-0.7.10/driver' bttv.o card=0 - unknown card=1 - MIRO PCTV @@ -34,6 +33,7 @@ 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 @@ -50,4 +50,3 @@ 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' diff -u --recursive --new-file v2.3.35/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options --- v2.3.35/linux/Documentation/video4linux/bttv/Insmod-options Mon Dec 20 18:48:21 1999 +++ linux/Documentation/video4linux/bttv/Insmod-options Wed Dec 29 17:08:55 1999 @@ -17,6 +17,8 @@ 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). diff -u --recursive --new-file v2.3.35/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README --- v2.3.35/linux/Documentation/video4linux/bttv/README Mon Dec 20 18:48:21 1999 +++ linux/Documentation/video4linux/bttv/README Wed Dec 29 17:08:55 1999 @@ -7,7 +7,9 @@ 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 diff -u --recursive --new-file v2.3.35/linux/Documentation/video4linux/bttv/Sound-FAQ linux/Documentation/video4linux/bttv/Sound-FAQ --- v2.3.35/linux/Documentation/video4linux/bttv/Sound-FAQ Mon Dec 20 18:48:21 1999 +++ linux/Documentation/video4linux/bttv/Sound-FAQ Wed Dec 29 17:08:55 1999 @@ -17,11 +17,11 @@ 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 @@ -78,13 +78,19 @@ 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 diff -u --recursive --new-file v2.3.35/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.35/linux/MAINTAINERS Wed Dec 29 13:13:12 1999 +++ linux/MAINTAINERS Wed Dec 29 17:08:55 1999 @@ -410,6 +410,15 @@ 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 diff -u --recursive --new-file v2.3.35/linux/Makefile linux/Makefile --- v2.3.35/linux/Makefile Wed Dec 29 13:13:12 1999 +++ linux/Makefile Thu Dec 30 11:51:26 1999 @@ -1,6 +1,6 @@ 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/) @@ -146,6 +146,10 @@ DRIVERS := $(DRIVERS) drivers/net/wan/wan.a endif +ifeq ($(CONFIG_ARCNET),y) +DRIVERS := $(DRIVERS) drivers/net/arcnet/arcnet.a +endif + ifdef CONFIG_ATM DRIVERS := $(DRIVERS) drivers/atm/atm.a endif @@ -236,6 +240,10 @@ ifeq ($(CONFIG_I2C),y) DRIVERS := $(DRIVERS) drivers/i2c/i2c.a +endif + +ifeq ($(CONFIG_PHONE),y) +DRIVERS := $(DRIVERS) drivers/telephony/telephony.a endif include arch/$(ARCH)/Makefile diff -u --recursive --new-file v2.3.35/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.3.35/linux/arch/alpha/kernel/entry.S Mon Dec 20 18:48:21 1999 +++ linux/arch/alpha/kernel/entry.S Wed Dec 29 17:00:54 1999 @@ -985,7 +985,7 @@ .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 @@ -1150,3 +1150,4 @@ .quad sys_setresgid .quad sys_getresgid .quad sys_ni_syscall /* sys_dipc */ + .quad sys_shmctl diff -u --recursive --new-file v2.3.35/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.3.35/linux/arch/alpha/kernel/osf_sys.c Thu Jul 29 13:37:22 1999 +++ linux/arch/alpha/kernel/osf_sys.c Wed Dec 29 17:00:54 1999 @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include #include @@ -38,6 +41,7 @@ #include #include #include +#include extern int do_mount(kdev_t, const char *, const char *, char *, int, void *); extern int do_pipe(int *); @@ -1441,4 +1445,104 @@ return -EFAULT; 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); } diff -u --recursive --new-file v2.3.35/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.35/linux/arch/i386/config.in Wed Dec 29 13:13:12 1999 +++ linux/arch/i386/config.in Wed Dec 29 17:13:02 1999 @@ -145,6 +145,8 @@ source net/Config.in fi +source drivers/telephony/Config.in + mainmenu_option next_comment comment 'SCSI support' diff -u --recursive --new-file v2.3.35/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.35/linux/arch/i386/defconfig Wed Dec 29 13:13:12 1999 +++ linux/arch/i386/defconfig Thu Dec 30 10:55:53 1999 @@ -155,6 +155,12 @@ # CONFIG_ATALK is not set # +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set + +# # SCSI support # CONFIG_SCSI=y diff -u --recursive --new-file v2.3.35/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.35/linux/arch/i386/kernel/irq.c Wed Dec 29 13:13:12 1999 +++ linux/arch/i386/kernel/irq.c Thu Dec 30 11:42:26 1999 @@ -731,6 +731,7 @@ { unsigned int i; unsigned long delay; + unsigned long val; /* * first, enable any unassigned irqs @@ -754,6 +755,7 @@ /* * Now filter out any obviously spurious interrupts */ + val = 0; spin_lock_irq(&irq_controller_lock); for (i=0; ishutdown(i); } + + if (i < 32) + val |= 1 << i; } spin_unlock_irq(&irq_controller_lock); - return 0x12345678; + return val; } /* * Return a mask of triggered interrupts (this * can handle only legacy ISA interrupts). */ -unsigned int probe_irq_mask(unsigned long unused) +unsigned int probe_irq_mask(unsigned long val) { int i; unsigned int mask; - if (unused != 0x12345678) - printk("Bad IRQ probe from %lx\n", (&unused)[-1]); - mask = 0; spin_lock_irq(&irq_controller_lock); for (i = 0; i < 16; i++) { @@ -800,19 +802,16 @@ } spin_unlock_irq(&irq_controller_lock); - return mask; + return mask & val; } /* * Return the one interrupt that triggered (this can * handle any interrupt source) */ -int probe_irq_off(unsigned long unused) +int probe_irq_off(unsigned long val) { int i, irq_found, nr_irqs; - - if (unused != 0x12345678) - printk("Bad IRQ probe from %lx\n", (&unused)[-1]); nr_irqs = 0; irq_found = 0; diff -u --recursive --new-file v2.3.35/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c --- v2.3.35/linux/arch/i386/kernel/pci-i386.c Wed Dec 29 13:13:12 1999 +++ linux/arch/i386/kernel/pci-i386.c Mon Jan 3 11:15:05 2000 @@ -256,25 +256,31 @@ struct resource *r; for(dev=pci_devices; dev; dev=dev->next) { + int class = dev->class >> 8; + + /* Don't touch classless devices and host bridges */ + if (!class || class == PCI_CLASS_BRIDGE_HOST) + continue; + for(idx=0; idx<6; idx++) { r = &dev->resource[idx]; - if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || - ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)) || - !dev->class || (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) - /* - * Don't touch IDE controllers and I/O ports of video cards! - * Also avoid classless devices and host bridges. - */ + + /* + * Don't touch IDE controllers and I/O ports of video cards! + */ + if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || + (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) continue; - if (!r->start && r->end) { - /* - * We shall assign a new address to this resource, either because - * the BIOS forgot to do so or because we have decided the old - * address was unusable for some reason. - */ + + /* + * We shall assign a new address to this resource, either because + * the BIOS forgot to do so or because we have decided the old + * address was unusable for some reason. + */ + if (!r->start && r->end) pci_assign_resource(dev, idx); - } } + if (pci_probe & PCI_ASSIGN_ROMS) { r = &dev->resource[PCI_ROM_RESOURCE]; r->end -= r->start; diff -u --recursive --new-file v2.3.35/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.3.35/linux/arch/i386/kernel/pci-pc.c Tue Dec 14 01:27:23 1999 +++ linux/arch/i386/kernel/pci-pc.c Tue Jan 4 12:16:48 2000 @@ -1063,6 +1063,7 @@ case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0): case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0): case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0): + case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533): /* Intel PIIX: PIRQ holds configuration register address */ pci_read_config_byte(router, pirq, &x); if (x < 16) { diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v2.3.35/linux/arch/sparc/kernel/ioport.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/ioport.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.27 1999/11/14 06:23:04 zaitcev Exp $ +/* $Id: ioport.c,v 1.28 1999/12/27 06:08:28 anton Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -20,6 +20,7 @@ #include #include #include +#include #include struct resource *sparc_find_resource_bystart(struct resource *, unsigned long); @@ -228,7 +229,7 @@ if (allocate_resource(&sparc_iomap, res, (offset + sz + PAGE_SIZE-1) & PAGE_MASK, - sparc_iomap.start, sparc_iomap.end, PAGE_SIZE) != 0) { + sparc_iomap.start, sparc_iomap.end, PAGE_SIZE, NULL, NULL) != 0) { /* Usually we cannot see printks in this case. */ prom_printf("alloc_io_res(%s): cannot occupy\n", (res->name != NULL)? res->name: "???"); @@ -320,7 +321,7 @@ } if (allocate_resource(&sparc_dvma, res, len_total, - sparc_dvma.start, sparc_dvma.end, PAGE_SIZE) != 0) { + sparc_dvma.start, sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { printk("sbus_alloc_consistant: cannot occupy 0x%lx", len); free_pages(va, order); kfree(res); @@ -460,10 +461,16 @@ #endif } -void sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { /* BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ mmu_get_scsi_sgl(sg, n, sdev->bus); + + /* + * XXX sparc64 can return a partial length here. sun4c should do this + * but it currently panics if it can't fulfill the request - Anton + */ + return n; } void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.3.35/linux/arch/sparc/kernel/irq.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/irq.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.98 1999/11/17 07:34:05 zaitcev Exp $ +/* $Id: irq.c,v 1.99 1999/12/27 06:08:29 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.3.35/linux/arch/sparc/kernel/process.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/process.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.141 1999/10/24 06:25:02 anton Exp $ +/* $Id: process.c,v 1.142 1999/12/27 06:08:31 anton Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/semaphore.c linux/arch/sparc/kernel/semaphore.c --- v2.3.35/linux/arch/sparc/kernel/semaphore.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/kernel/semaphore.c Mon Jan 3 12:01:31 2000 @@ -1,5 +1,5 @@ -/* $Id: semaphore.c,v 1.1 1999/08/31 13:26:15 anton Exp $ - * Generic semaphore code. Buyer beware. Do your own +/* $Id: semaphore.c,v 1.2 1999/12/28 11:50:37 jj Exp $ + * Generic semaphore code. Buyer beware. Do your own * specific changes in */ @@ -62,8 +62,7 @@ #define DOWN_VAR \ struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); + DECLARE_WAITQUEUE(wait, tsk); #define DOWN_HEAD(task_state) \ \ @@ -126,4 +125,116 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); +} + +/* rw mutexes + * Implemented by Jakub Jelinek (jakub@redhat.com) based on + * i386 implementation by Ben LaHaise (bcrl@redhat.com). + */ + +extern inline int ldstub(unsigned char *p) +{ + int ret; + asm volatile("ldstub %1, %0" : "=r" (ret) : "m" (*p) : "memory"); + return ret; +} + +void down_read_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (!ldstub(&sem->read_not_granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->read_not_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void down_write_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (!ldstub(&sem->write_not_granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->write_not_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (sem->count >= 0) + wake_up(&sem->wait); +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +void down_read_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +void down_write_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->count >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + /* Due to lame ldstub we don't do here + a BUG() consistency check */ + sem->read_not_granted = 0; + wake_up(&sem->wait); + } else { + sem->write_not_granted = 0; + wake_up(&sem->write_bias_wait); + } } diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.3.35/linux/arch/sparc/kernel/signal.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/signal.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.98 1999/12/15 22:24:23 davem Exp $ +/* $Id: signal.c,v 1.99 1999/12/27 06:08:32 anton Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -22,6 +22,7 @@ #include #include #include +#include #include #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.3.35/linux/arch/sparc/kernel/smp.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/smp.c Mon Jan 3 12:01:31 2000 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v2.3.35/linux/arch/sparc/kernel/sparc-stub.c Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc/kernel/sparc-stub.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc-stub.c,v 1.25 1999/07/23 01:56:13 davem Exp $ +/* $Id: sparc-stub.c,v 1.26 1999/12/27 06:08:34 anton Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux @@ -107,6 +107,7 @@ #include #include #include +#include #include /* * diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c --- v2.3.35/linux/arch/sparc/kernel/sun4d_irq.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/sun4d_irq.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.23 1999/10/19 04:33:26 zaitcev Exp $ +/* $Id: sun4d_irq.c,v 1.24 1999/12/27 06:08:34 anton Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.3.35/linux/arch/sparc/kernel/sun4d_smp.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/sun4d_smp.c Mon Jan 3 12:01:31 2000 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c --- v2.3.35/linux/arch/sparc/kernel/sun4m_irq.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/sun4m_irq.c Mon Jan 3 12:01:31 2000 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.3.35/linux/arch/sparc/kernel/sun4m_smp.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/sun4m_smp.c Mon Jan 3 12:01:31 2000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.3.35/linux/arch/sparc/kernel/sys_sparc.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/sys_sparc.c Tue Jan 4 11:17:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.55 1999/12/21 14:09:09 jj Exp $ +/* $Id: sys_sparc.c,v 1.56 2000/01/04 11:01:26 jj Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -227,7 +227,9 @@ unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - return do_mmap2(addr, len, prot, flags, fd, pgoff); + /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE + we have. */ + return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); } asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, diff -u --recursive --new-file v2.3.35/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.3.35/linux/arch/sparc/kernel/sys_sunos.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/kernel/sys_sunos.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.106 1999/12/16 11:57:27 anton Exp $ +/* $Id: sys_sunos.c,v 1.107 1999/12/27 06:08:37 anton Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -198,7 +198,7 @@ freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT; freepages += atomic_read(&page_cache_size); freepages >>= 1; - freepages += nr_free_pages; + freepages += nr_free_pages(); freepages += nr_swap_pages; freepages -= num_physpages >> 4; freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; diff -u --recursive --new-file v2.3.35/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile --- v2.3.35/linux/arch/sparc/lib/Makefile Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/lib/Makefile Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.30 1999/12/21 04:02:18 davem Exp $ +# $Id: Makefile,v 1.31 1999/12/28 11:50:39 jj Exp $ # Makefile for Sparc library files.. # @@ -6,7 +6,7 @@ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \ - ashldi3.o + ashldi3.o rwsem.o ifdef CONFIG_SMP OBJS += irqlock.o @@ -16,85 +16,11 @@ $(AR) rcs lib.a $(OBJS) sync -checksum.o: checksum.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o checksum.o checksum.S +.S.s: + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s -memcpy.o: memcpy.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memcpy.o memcpy.S - -memcmp.o: memcmp.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memcmp.o memcmp.S - -memscan.o: memscan.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memscan.o memscan.S - -strncmp.o: strncmp.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strncmp.o strncmp.S - -strncpy_from_user.o: strncpy_from_user.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strncpy_from_user.o strncpy_from_user.S - -strlen_user.o: strlen_user.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strlen_user.o strlen_user.S - -copy_user.o: copy_user.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o copy_user.o copy_user.S - -blockops.o: blockops.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o blockops.o blockops.S - -memset.o: memset.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o memset.o memset.S - -locks.o: locks.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o locks.o locks.S - -atomic.o: atomic.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o atomic.o atomic.S - -bitops.o: bitops.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S - -ifdef CONFIG_SMP -irqlock.o: irqlock.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o irqlock.o irqlock.S -endif - -strlen.o: strlen.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o strlen.o strlen.S - -divdi3.o: divdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o divdi3.o divdi3.S - -udivdi3.o: udivdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o udivdi3.o udivdi3.S - -mul.o: mul.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o mul.o mul.S - -rem.o: rem.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o rem.o rem.S - -sdiv.o: sdiv.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o sdiv.o sdiv.S - -udiv.o: udiv.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o udiv.o udiv.S - -umul.o: umul.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o umul.o umul.S - -urem.o: urem.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -DST_DIV0=0x2 -c -o urem.o urem.S - -ashrdi3.o: ashrdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o ashrdi3.o ashrdi3.S - -ashldi3.o: ashldi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o ashldi3.o ashldi3.S - -lshrdi3.o: lshrdi3.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o lshrdi3.o lshrdi3.S +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o dep: diff -u --recursive --new-file v2.3.35/linux/arch/sparc/lib/rwsem.S linux/arch/sparc/lib/rwsem.S --- v2.3.35/linux/arch/sparc/lib/rwsem.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc/lib/rwsem.S Tue Jan 4 09:41:45 2000 @@ -0,0 +1,191 @@ +/* $Id: rwsem.S,v 1.1 1999/12/28 11:50:39 jj Exp $ + * Assembly part of rw semaphores. + * + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) + */ + +#include +#include + + .text + .align 4 + + .globl ___down_read +___down_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + subcc %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + subcc %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bneg 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_read_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_read + restore %l5, %g0, %g5 +4: call down_read_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___down_write +___down_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + subcc %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + subcc %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bne 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_write_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_write + restore %l5, %g0, %g5 +4: call down_write_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___up_read +___up_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + addcc %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + addcc %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + be 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + clr %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___up_write +___up_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef __SMP__ +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + addcc %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + addcc %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + bcs 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + mov %g7, %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 diff -u --recursive --new-file v2.3.35/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c --- v2.3.35/linux/arch/sparc/mm/asyncd.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/mm/asyncd.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.17 1999/08/14 03:51:44 anton Exp $ +/* $Id: asyncd.c,v 1.18 1999/12/27 06:30:02 anton Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -25,6 +25,7 @@ #include /* for cli()/sti() */ #include /* for memcpy_to/fromfs */ #include +#include #include #define DEBUG 0 diff -u --recursive --new-file v2.3.35/linux/arch/sparc/mm/btfixup.c linux/arch/sparc/mm/btfixup.c --- v2.3.35/linux/arch/sparc/mm/btfixup.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/mm/btfixup.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: btfixup.c,v 1.8 1999/08/31 06:54:31 davem Exp $ +/* $Id: btfixup.c,v 1.9 1999/12/27 06:30:02 anton Exp $ * btfixup.c: Boot time code fixup and relocator, so that * we can get rid of most indirect calls to achieve single * image sun4c and srmmu kernel. @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c --- v2.3.35/linux/arch/sparc/mm/generic.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/mm/generic.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.8 1999/12/20 05:01:49 davem Exp $ +/* $Id: generic.c,v 1.9 1999/12/27 06:30:03 anton Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -27,7 +28,7 @@ free_page_and_swap_cache(mem_map+nr); return; } - swap_free(page); + swap_free(pte_to_swp_entry(page)); } /* Remap IO memory, the same way as remap_page_range(), but use diff -u --recursive --new-file v2.3.35/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.3.35/linux/arch/sparc/mm/init.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/mm/init.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.71 1999/12/16 12:58:33 anton Exp $ +/* $Id: init.c,v 1.72 1999/12/27 06:30:06 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -82,7 +82,7 @@ printk("Free swap: %6dkB\n", nr_swap_pages << (PAGE_SHIFT-10)); printk("%ld pages of RAM\n", totalram_pages); - printk("%d free pages\n", nr_free_pages); + printk("%d free pages\n", nr_free_pages()); printk("%ld pages in page table cache\n",pgtable_cache_size); #ifndef __SMP__ if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d) @@ -395,15 +395,17 @@ taint_real_pages(); + max_mapnr = last_valid_pfn; + high_memory = __va(last_valid_pfn << PAGE_SHIFT); + #ifdef DEBUG_BOOTMEM prom_printf("mem_init: Calling free_all_bootmem().\n"); #endif num_physpages = totalram_pages = free_all_bootmem(); +#if 0 free_unused_mem_map(); - - max_mapnr = last_valid_pfn; - high_memory = __va(last_valid_pfn << PAGE_SHIFT); +#endif codepages = (((unsigned long) &etext) - ((unsigned long)&_start)); codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT; @@ -413,7 +415,7 @@ initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT; printk("Memory: %dk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n", - nr_free_pages << (PAGE_SHIFT-10), + nr_free_pages() << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10), @@ -423,7 +425,7 @@ * Please keep track of things and make sure this * always matches the code in mm/page_alloc.c -DaveM */ - i = nr_free_pages >> 7; + i = nr_free_pages() >> 7; if (i < 48) i = 48; if (i > 256) @@ -439,9 +441,17 @@ addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - ClearPageReserved(mem_map + MAP_NR(addr)); - set_page_count(mem_map + MAP_NR(addr), 1); - free_page(addr); + unsigned long page; + struct page *p; + + page = (addr + + ((unsigned long) __va(phys_base)) - + PAGE_OFFSET); + p = mem_map + MAP_NR(page); + + ClearPageReserved(p); + set_page_count(p, 1); + __free_page(p); totalram_pages++; num_physpages++; } @@ -451,11 +461,11 @@ { val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages; + val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); val->totalhigh = 0; - val->freehigh = nr_free_highpages; + val->freehigh = 0; val->mem_unit = PAGE_SIZE; } diff -u --recursive --new-file v2.3.35/linux/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c --- v2.3.35/linux/arch/sparc/mm/io-unit.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/mm/io-unit.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.17 1999/10/18 01:46:54 zaitcev Exp $ +/* $Id: io-unit.c,v 1.18 1999/12/28 04:28:55 anton Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c --- v2.3.35/linux/arch/sparc/mm/iommu.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/mm/iommu.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: iommu.c,v 1.15 1999/11/19 04:11:53 davem Exp $ +/* $Id: iommu.c,v 1.16 1999/12/28 04:28:54 anton Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.35/linux/arch/sparc/mm/sun4c.c Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/mm/sun4c.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.181 1999/12/16 14:34:21 anton Exp $ +/* $Id: sun4c.c,v 1.182 1999/12/27 06:30:04 anton Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -1967,10 +1968,6 @@ } else { /* Update the LRU ring of contexts. */ ctx = ctx_list_pool + mm->context; -#ifdef DEBUG_SUN4C_MM - if (!ctx->ctx_mm) - panic("context was not set up"); -#endif remove_from_ctx_list(ctx); add_to_used_ctxlist(ctx); } @@ -2027,10 +2024,6 @@ } else { /* Update the LRU ring of contexts. */ ctx = ctx_list_pool + mm->context; -#ifdef DEBUG_SUN4C_MM - if (!ctx->ctx_mm) - panic("context was not set up"); -#endif remove_from_ctx_list(ctx); add_to_used_ctxlist(ctx); } @@ -2464,7 +2457,7 @@ pgdp = sun4c_pgd_offset(vma->vm_mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE); - pte = pte_val(*ptep); + pte = *ptep; } } } @@ -2586,7 +2579,14 @@ swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3); sun4c_init_ss2_cache_bug(); sparc_context_init(num_contexts); - free_area_init(end_pfn); + + { + unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + + zones_size[ZONE_DMA] = end_pfn; + free_area_init(zones_size); + } + cnt = 0; for (i = 0; i < num_segmaps; i++) if (mmu_entry_pool[i].locked) diff -u --recursive --new-file v2.3.35/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.35/linux/arch/sparc64/defconfig Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc64/defconfig Mon Jan 3 12:01:31 2000 @@ -302,6 +302,7 @@ # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m CONFIG_EFS_FS=m +CONFIG_CRAMFS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m diff -u --recursive --new-file v2.3.35/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.35/linux/arch/sparc64/kernel/ioctl32.c Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/ioctl32.c Tue Jan 4 11:17:47 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.71 1999/12/19 23:13:13 davem Exp $ +/* $Id: ioctl32.c,v 1.72 2000/01/04 15:43:45 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -2181,7 +2181,6 @@ case PPPIOCSNPMODE: case PPPIOCGDEBUG: case PPPIOCSDEBUG: - case PPPIOCGIDLE: case PPPIOCNEWUNIT: case PPPIOCATTACH: case PPPIOCDETACH: diff -u --recursive --new-file v2.3.35/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.3.35/linux/arch/sparc64/kernel/pci.c Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/pci.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.11 1999/12/20 05:02:07 davem Exp $ +/* $Id: pci.c,v 1.12 2000/01/01 03:32:50 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -227,6 +227,11 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size) { +} + +int pci_assign_resource(struct pci_dev *dev, int i) +{ + return -ENOSYS; /* :-)... actually implement this soon */ } char * __init pcibios_setup(char *str) diff -u --recursive --new-file v2.3.35/linux/arch/sparc64/kernel/semaphore.c linux/arch/sparc64/kernel/semaphore.c --- v2.3.35/linux/arch/sparc64/kernel/semaphore.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc64/kernel/semaphore.c Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: semaphore.c,v 1.1 1999/08/30 10:00:50 davem Exp $ +/* $Id: semaphore.c,v 1.2 1999/12/23 17:12:03 jj Exp $ * Generic semaphore code. Buyer beware. Do your own * specific changes in */ @@ -62,8 +62,7 @@ #define DOWN_VAR \ struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); + DECLARE_WAITQUEUE(wait, tsk); #define DOWN_HEAD(task_state) \ \ @@ -126,4 +125,173 @@ int __down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); +} + +/* rw mutexes + * Implemented by Jakub Jelinek (jakub@redhat.com) based on + * i386 implementation by Ben LaHaise (bcrl@redhat.com). + */ + +asm(" + .text + .align 32 + .globl __down_read_failed +__down_read_failed: + save %sp, -160, %sp + membar #StoreStore + brz,pt %g5, 3f + mov %g7, %l0 +1: call down_read_failed + mov %l0, %o0 +2: lduw [%l0], %l1 + sub %l1, 1, %l2 + cas [%l0], %l1, %l2 + + cmp %l1, %l2 + bne,pn %icc, 2b + membar #StoreStore + subcc %l1, 1, %g0 + bpos,pt %icc, 4f + nop + bcc,pn %icc, 1b + nop + +3: call down_read_failed_biased + mov %l0, %o0 +4: ret + restore + .previous +"); + +asm(" + .text + .align 32 + .globl __down_write_failed +__down_write_failed: + save %sp, -160, %sp + membar #StoreStore + tst %g5 + bge,pt %icc, 3f + mov %g7, %l0 +1: call down_write_failed + mov %l0, %o0 +2: lduw [%l0], %l1 + sethi %hi (" RW_LOCK_BIAS_STR "), %l3 + sub %l1, %l3, %l2 + cas [%l0], %l1, %l2 + + cmp %l1, %l2 + bne,pn %icc, 2b + membar #StoreStore + subcc %l1, %l3, %g0 + be,pt %icc, 4f + nop + bcc,pn %icc, 1b + nop + +3: call down_write_failed_biased + mov %l0, %o0 +4: ret + restore + .previous +"); + +void down_read_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (clear_le_bit(0, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!test_le_bit(0, &sem->granted)) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void down_write_failed_biased(struct rw_semaphore *sem) +{ + DOWN_VAR + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (clear_le_bit(1, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!test_le_bit(1, &sem->granted)) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (sem->count >= 0) + wake_up(&sem->wait); +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +void down_read_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_read(sem); /* this takes care of granting the lock */ + + add_wait_queue(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +void down_write_failed(struct rw_semaphore *sem) +{ + DOWN_VAR + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->count >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + if (set_le_bit(0, &sem->granted)) + BUG(); + wake_up(&sem->wait); + } else { + if (set_le_bit(1, &sem->granted)) + BUG(); + wake_up(&sem->write_bias_wait); + } } diff -u --recursive --new-file v2.3.35/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.3.35/linux/arch/sparc64/kernel/sys_sparc.c Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/sys_sparc.c Tue Jan 4 09:41:45 2000 @@ -6,6 +6,7 @@ * platform. */ +#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/arch/sparc64/lib/VISmemset.S linux/arch/sparc64/lib/VISmemset.S --- v2.3.35/linux/arch/sparc64/lib/VISmemset.S Thu May 27 09:55:21 1999 +++ linux/arch/sparc64/lib/VISmemset.S Mon Jan 3 12:01:31 2000 @@ -1,9 +1,9 @@ -/* $Id: VISmemset.S,v 1.9 1999/05/25 16:53:01 jj Exp $ +/* $Id: VISmemset.S,v 1.10 1999/12/23 17:02:16 jj Exp $ * VISmemset.S: High speed memset operations utilizing the UltraSparc * Visual Instruction Set. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996, 1997, 1999 Jakub Jelinek (jakub@redhat.com) */ #include "VIS.h" @@ -32,12 +32,7 @@ #endif #ifdef __KERNEL__ - #include - -#define RETL clr %o0 -#else -#define RETL mov %g3, %o0 #endif /* Well, memset is a lot easier to get right than bcopy... */ @@ -55,8 +50,8 @@ #ifndef REGS_64BIT srl %o2, 0, %o2 #endif - mov %o0, %g3 #endif + mov %o0, %o4 cmp %o2, 7 bleu,pn %xcc, 17f andcc %o0, 3, %g5 @@ -188,19 +183,19 @@ andcc %o2, 7, %o2 #ifdef __KERNEL__ 14: srl %g5, 1, %o3 - sethi %hi(13f), %o4 - sub %o4, %o3, %o4 - jmpl %o4 + %lo(13f), %g0 + sethi %hi(13f), %g3 + sub %g3, %o3, %g3 + jmpl %g3 + %lo(13f), %g0 add %o0, %g5, %o0 #else -14: rd %pc, %o4 +14: rd %pc, %g3 #ifdef REGS_64BIT srl %g5, 1, %o3 - sub %o4, %o3, %o4 + sub %g3, %o3, %g3 #else - sub %o4, %g5, %o4 + sub %g3, %g5, %g3 #endif - jmpl %o4 + (13f - 14b), %g0 + jmpl %g3 + (13f - 14b), %g0 add %o0, %g5, %o0 #endif 12: SET_BLOCKS(%o0, 0x68, %o1) @@ -220,14 +215,14 @@ 1: bne,a,pn %xcc, 8f stb %o1, [%o0] 8: retl - RETL + mov %o4, %o0 17: brz,pn %o2, 0f 8: add %o0, 1, %o0 subcc %o2, 1, %o2 bne,pt %xcc, 8b stb %o1, [%o0 - 1] 0: retl - RETL + mov %o4, %o0 6: #ifdef REGS_64BIT stx %o1, [%o0] diff -u --recursive --new-file v2.3.35/linux/drivers/Makefile linux/drivers/Makefile --- v2.3.35/linux/drivers/Makefile Mon Dec 20 18:48:21 1999 +++ linux/drivers/Makefile Wed Dec 29 17:13:02 1999 @@ -11,7 +11,7 @@ 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 @@ -63,6 +63,15 @@ else ifeq ($(CONFIG_USB),m) MOD_SUB_DIRS += usb + endif +endif + +ifeq ($(CONFIG_PHONE),y) +SUB_DIRS += telephony +MOD_SUB_DIRS += telephony +else + ifeq ($(CONFIG_PHONE),m) + MOD_SUB_DIRS += telephony endif endif diff -u --recursive --new-file v2.3.35/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.3.35/linux/drivers/cdrom/cdrom.c Tue Dec 14 01:27:23 1999 +++ linux/drivers/cdrom/cdrom.c Tue Jan 4 07:53:02 2000 @@ -636,9 +636,9 @@ int opened_for_data; cdinfo(CD_CLOSE, "entering cdrom_release\n"); - if (cdi == NULL) - return 0; - if (cdi->use_count > 0) cdi->use_count--; + + if (cdi->use_count > 0) + cdi->use_count--; if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); if (cdi->use_count == 0 && @@ -812,15 +812,12 @@ return ret; } -static -int cdrom_media_changed(kdev_t dev) +static int cdrom_media_changed(kdev_t dev) { struct cdrom_device_info *cdi = cdrom_find_device(dev); /* This talks to the VFS, which doesn't like errors - just 1 or 0. * Returning "0" is always safe (media hasn't been changed). Do that * if the low-level cdrom driver dosn't support media changed. */ - if (cdi == NULL) - return 0; if (cdi->ops->media_changed == NULL) return 0; if (!CDROM_CAN(CDC_MEDIA_CHANGED)) @@ -828,6 +825,7 @@ return (media_changed(cdi, 0)); } +/* badly broken, I know. Is due for a fixup anytime. */ void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) { struct cdrom_tochdr header; @@ -913,12 +911,11 @@ *curr = requested; } -void init_cdrom_command(struct cdrom_generic_command *cgc, - void *buffer, int len) +void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len) { memset(cgc, 0, sizeof(struct cdrom_generic_command)); - memset(buffer, 0, len); - cgc->buffer = (char *) buffer; + memset(buf, 0, len); + cgc->buffer = (char *) buf; cgc->buflen = len; } @@ -1382,37 +1379,21 @@ return cdo->generic_packet(cdi, cgc); } -/* Some of the cdrom ioctls are not implemented here, because these - * appear to be either too device-specific, or it is not clear to me - * what use they are. These are (number of drivers that support them - * in parenthesis): CDROMREADMODE1 (2+ide), CDROMREADMODE2 (2+ide), - * CDROMREADAUDIO (2+ide), CDROMREADRAW (2), CDROMREADCOOKED (2), - * CDROMSEEK (2), CDROMPLAYBLK (scsi), CDROMREADALL (1). Read-audio, - * OK (although i guess the record companies aren't too happy with - * this, most drives therefore refuse to transport audio data). But - * why are there 5 different READs defined? For now, these functions - * are left over to the device-specific ioctl routine, - * cdo->dev_ioctl. Note that as a result of this, no - * memory-verification is performed for these ioctls. +/* Just about every imaginable ioctl is supported in the Uniform layer + * these days. ATAPI / SCSI specific code now mainly resides in + * mmc_ioct(). */ -static -int cdrom_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) +static int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, + unsigned long arg) { kdev_t dev = ip->i_rdev; struct cdrom_device_info *cdi = cdrom_find_device(dev); - struct cdrom_device_ops *cdo; + struct cdrom_device_ops *cdo = cdi->ops; int ret; - if (cdi == NULL) - return -ENODEV; - cdo = cdi->ops; - /* the first few commands do not deal with audio drive_info, but only with routines in cdrom device operations. */ switch (cmd) { - /* maybe we should order cases after statistics of use? */ - case CDROMMULTISESSION: { struct cdrom_multisession ms_info; u_char requested_format; @@ -1902,8 +1883,7 @@ /* get toc entry for start and end track */ if (cdo->audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)) return -EINVAL; - entry.cdte_track = ti.cdti_trk1 + 1; - if (entry.cdte_track > tochdr.cdth_trk1) + if ((entry.cdte_track = ti.cdti_trk0) > tochdr.cdth_trk1) return -EINVAL; if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) return -EINVAL; @@ -1912,7 +1892,10 @@ cgc.cmd[4] = entry.cdte_addr.msf.second; cgc.cmd[5] = entry.cdte_addr.msf.frame; - entry.cdte_track = ti.cdti_trk1; + entry.cdte_track = ti.cdti_trk1 + 1; + if (entry.cdte_track > tochdr.cdth_trk1) + entry.cdte_track = CDROM_LEADOUT; + if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) return -EINVAL; diff -u --recursive --new-file v2.3.35/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.35/linux/drivers/char/Config.in Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/Config.in Wed Dec 29 17:08:55 1999 @@ -129,7 +129,7 @@ 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 @@ -143,37 +143,15 @@ 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 @@ -196,9 +174,25 @@ 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 diff -u --recursive --new-file v2.3.35/linux/drivers/char/agp/Makefile linux/drivers/char/agp/Makefile --- v2.3.35/linux/drivers/char/agp/Makefile Tue Dec 14 01:27:23 1999 +++ linux/drivers/char/agp/Makefile Tue Jan 4 09:41:45 2000 @@ -6,9 +6,12 @@ O_TARGET := agp.o ifeq ($(CONFIG_AGP),y) - O_OBJS += agpgart.o + O_OBJS += agpgart_fe.o + OX_OBJS += agpgart_be.o else ifeq ($(CONFIG_AGP), m) + MI_OBJS += agpgart_fe.o + MIX_OBJS += agpgart_be.o M_OBJS += agpgart.o endif endif diff -u --recursive --new-file v2.3.35/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.3.35/linux/drivers/char/agp/agpgart_be.c Wed Dec 15 10:43:16 1999 +++ linux/drivers/char/agp/agpgart_be.c Tue Jan 4 09:41:45 2000 @@ -23,7 +23,6 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#define EXPORT_SYMTAB #include #include #include diff -u --recursive --new-file v2.3.35/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.35/linux/drivers/char/bttv.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/bttv.c Wed Dec 29 17:08:55 1999 @@ -74,6 +74,7 @@ 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; @@ -86,6 +87,7 @@ 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) @@ -389,16 +391,24 @@ } /* 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; } @@ -529,31 +539,31 @@ 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"); } @@ -628,7 +638,7 @@ 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, @@ -702,12 +712,15 @@ { "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); @@ -739,7 +752,8 @@ 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)); } @@ -882,7 +896,7 @@ } 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); } @@ -1418,7 +1432,7 @@ 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; @@ -1447,7 +1461,7 @@ 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); @@ -1834,7 +1848,7 @@ { struct bttv *btv=(struct bttv *)dev; int i; - + switch (cmd) { case VIDIOCGCAP: { @@ -2230,7 +2244,7 @@ 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? */ if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) { up(&btv->lock); @@ -2238,9 +2252,11 @@ } /* 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; @@ -2844,14 +2860,14 @@ */ 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 */ @@ -2860,7 +2876,7 @@ #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; @@ -2911,43 +2927,43 @@ /* 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); } @@ -3303,13 +3319,14 @@ 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++; diff -u --recursive --new-file v2.3.35/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.3.35/linux/drivers/char/bttv.h Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/bttv.h Wed Dec 29 17:08:55 1999 @@ -21,7 +21,7 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE 0x00070a +#define BTTV_VERSION_CODE 0x00070b #include #include diff -u --recursive --new-file v2.3.35/linux/drivers/char/buz.c linux/drivers/char/buz.c --- v2.3.35/linux/drivers/char/buz.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/buz.c Wed Dec 29 17:08:55 1999 @@ -3166,8 +3166,6 @@ mdelay(10); zr36060_reset(zr); mdelay(10); - zr36060_sleep(zr, 1); - mdelay(10); /* display codec revision */ if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { @@ -3204,8 +3202,6 @@ udelay(3000); zr36060_reset(zr); udelay(3000); - zr36060_sleep(zr, 1); - udelay(3000); /* display codec revision */ if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { @@ -3213,8 +3209,8 @@ 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; } diff -u --recursive --new-file v2.3.35/linux/drivers/char/drm/Makefile linux/drivers/char/drm/Makefile --- v2.3.35/linux/drivers/char/drm/Makefile Wed Dec 8 14:11:25 1999 +++ linux/drivers/char/drm/Makefile Tue Jan 4 09:41:45 2000 @@ -10,7 +10,6 @@ # parent makes.. # -L_TARGET := libdrm.a O_TARGET := drm.o L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ @@ -19,25 +18,33 @@ M_OBJS := ifeq ($(CONFIG_DRM_GAMMA),y) - O_OBJS += gamma.o + OX_OBJS += gamma_drv.o + O_OBJS += gamma_dma.o else ifeq ($(CONFIG_DRM_GAMMA),m) + MIX_OBJS += gamma_drv.o + MI_OBJS += gamma_dma.o M_OBJS += gamma.o endif endif ifeq ($(CONFIG_DRM_TDFX),y) - O_OBJS += tdfx.o + OX_OBJS += tdfx_drv.o + O_OBJS += tdfx_context.o else ifeq ($(CONFIG_DRM_TDFX),m) + MIX_OBJS += tdfx_drv.o + MI_OBJS += tdfx_context.o M_OBJS += tdfx.o endif endif +O_OBJS += $(L_OBJS) + include $(TOPDIR)/Rules.make -gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) - $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o -L. -ldrm +gamma.o : gamma_drv.o gamma_dma.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o $(L_OBJS) -tdfx.o: tdfx_drv.o tdfx_context.o $(L_TARGET) - $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o -L. -ldrm +tdfx.o: tdfx_drv.o tdfx_context.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o $(L_OBJS) diff -u --recursive --new-file v2.3.35/linux/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c --- v2.3.35/linux/drivers/char/drm/gamma_drv.c Wed Dec 8 14:11:25 1999 +++ linux/drivers/char/drm/gamma_drv.c Tue Jan 4 09:41:45 2000 @@ -29,7 +29,6 @@ * */ -#define EXPORT_SYMTAB #include #include "drmP.h" #include "gamma_drv.h" @@ -122,7 +121,7 @@ #ifndef MODULE /* gamma_setup is called by the kernel to parse command-line options passed * via the boot-loader (e.g., LILO). It calls the insmod option routine, - * drm_parse_drm. + * drm_parse_options. * * This is not currently supported, since it requires changes to * linux/init/main.c. */ diff -u --recursive --new-file v2.3.35/linux/drivers/char/drm/init.c linux/drivers/char/drm/init.c --- v2.3.35/linux/drivers/char/drm/init.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/char/drm/init.c Tue Jan 4 09:41:45 2000 @@ -35,7 +35,7 @@ int drm_flags = 0; /* drm_parse_option parses a single option. See description for - drm_parse_drm for details. */ + drm_parse_options for details. */ static void drm_parse_option(char *s) { diff -u --recursive --new-file v2.3.35/linux/drivers/char/drm/tdfx_drv.c linux/drivers/char/drm/tdfx_drv.c --- v2.3.35/linux/drivers/char/drm/tdfx_drv.c Wed Dec 8 14:11:25 1999 +++ linux/drivers/char/drm/tdfx_drv.c Tue Jan 4 09:41:45 2000 @@ -29,7 +29,6 @@ * */ -#define EXPORT_SYMTAB #include #include "drmP.h" #include "tdfx_drv.h" @@ -89,7 +88,9 @@ }; #define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls) +#ifdef MODULE static char *tdfx = NULL; +#endif MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas."); MODULE_DESCRIPTION("tdfx"); @@ -587,10 +588,11 @@ module_init(tdfx_init); module_exit(tdfx_cleanup); +#ifndef MODULE /* * tdfx_setup is called by the kernel to parse command-line options passed * via the boot-loader (e.g., LILO). It calls the insmod option routine, - * drm_parse_drm. + * drm_parse_options. */ static int __init tdfx_options(char *str) { @@ -599,3 +601,4 @@ } __setup("tdfx=", tdfx_options); +#endif diff -u --recursive --new-file v2.3.35/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.3.35/linux/drivers/char/lp.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/lp.c Thu Dec 30 10:11:57 1999 @@ -662,11 +662,30 @@ parport_negotiate (port, IEEE1284_MODE_COMPAT); do { - /* Write the data. */ - written = parport_write (port, s, count); - if (written > 0) { - s += written; - count -= written; + /* Write the data, converting LF->CRLF as we go. */ + ssize_t canwrite = count; + char *line = strchr (s, '\n'); + if (line) + canwrite = line - s; + + written = parport_write (port, s, canwrite); + if (written <= 0) + continue; + + s += written; + count -= written; + if (line) { + const char *crlf = "\r\n"; + int i = 2; + + /* Dodge the original '\n', and put '\r\n' instead. */ + s++; + count--; + while (i) { + written = parport_write (port, crlf, i); + if (written > 0) + i -= written, crlf += written; + } } } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); diff -u --recursive --new-file v2.3.35/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.3.35/linux/drivers/char/mem.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/mem.c Wed Dec 29 17:13:02 1999 @@ -61,6 +61,9 @@ #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) @@ -624,6 +627,9 @@ #ifdef CONFIG_USB usb_init(); #endif +#ifdef CONFIG_I2C + i2c_init_all(); +#endif #if defined (CONFIG_FB) fbmem_init(); #endif @@ -669,10 +675,6 @@ #ifdef CONFIG_FTAPE ftape_init(); #endif -#ifdef CONFIG_I2C - i2c_init_all(); -#endif - #ifdef CONFIG_VIDEO_BT848 i2c_init(); #endif @@ -682,5 +684,8 @@ #ifdef CONFIG_VIDEO_DEV videodev_init(); #endif +#ifdef CONFIG_PHONE + telephony_init(); +#endif return 0; } diff -u --recursive --new-file v2.3.35/linux/drivers/char/pcmcia/Config.in linux/drivers/char/pcmcia/Config.in --- v2.3.35/linux/drivers/char/pcmcia/Config.in Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/pcmcia/Config.in Thu Dec 30 23:24:22 1999 @@ -5,22 +5,19 @@ mainmenu_option next_comment comment 'PCMCIA character device support' -if [ "$CONFIG_SERIAL" = "y" ]; then - dep_tristate 'PCMCIA serial device support' \ - CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA - if [ "$CONFIG_CARDBUS" = "y" ]; then - dep_tristate 'CardBus serial device support' \ - CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA +if [ "$CONFIG_SERIAL" = "n" -o "$CONFIG_PCMCIA" = "n" ]; then + define_bool CONFIG_PCMCIA_SERIAL n +else + if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_PCMCIA" = "m" ]; then + define_bool CONFIG_PCMCIA_SERIAL m + else + define_bool CONFIG_PCMCIA_SERIAL y fi fi -if [ "$CONFIG_SERIAL" = "m" ]; then - dep_tristate 'PCMCIA serial device support' \ - CONFIG_PCMCIA_SERIAL_CS m - if [ "$CONFIG_CARDBUS" = "y" ]; then - dep_tristate 'CardBus serial device support' \ - CONFIG_PCMCIA_SERIAL_CB m - fi +dep_tristate ' PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA_SERIAL +if [ "$CONFIG_CARDBUS" = "y" ]; then + dep_tristate ' CardBus serial device support' CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA_SERIAL fi if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" -o \ diff -u --recursive --new-file v2.3.35/linux/drivers/char/saa7110.c linux/drivers/char/saa7110.c --- v2.3.35/linux/drivers/char/saa7110.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/saa7110.c Wed Dec 29 17:08:55 1999 @@ -29,7 +29,7 @@ #include #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 */ @@ -224,7 +224,7 @@ 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); } diff -u --recursive --new-file v2.3.35/linux/drivers/char/saa7111.c linux/drivers/char/saa7111.c --- v2.3.35/linux/drivers/char/saa7111.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/saa7111.c Wed Dec 29 17:08:55 1999 @@ -70,7 +70,6 @@ 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); @@ -85,9 +84,8 @@ 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); @@ -110,7 +108,6 @@ static int saa7111_read(struct saa7111 *dev, unsigned char subaddr) { int data; - unsigned long flags; LOCK_I2C_BUS(dev->bus); i2c_start(dev->bus); diff -u --recursive --new-file v2.3.35/linux/drivers/char/saa7185.c linux/drivers/char/saa7185.c --- v2.3.35/linux/drivers/char/saa7185.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/saa7185.c Wed Dec 29 17:08:55 1999 @@ -69,7 +69,6 @@ static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) { int ack; - unsigned long flags; LOCK_I2C_BUS(dev->bus); @@ -85,9 +84,8 @@ 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); diff -u --recursive --new-file v2.3.35/linux/drivers/char/tda9855.c linux/drivers/char/tda9855.c --- v2.3.35/linux/drivers/char/tda9855.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/tda9855.c Wed Dec 29 17:08:55 1999 @@ -415,7 +415,7 @@ static struct i2c_driver driver = { "i2c tda9855 driver", - I2C_DRIVERID_TDA9855, /* FIXME */ + I2C_DRIVERID_TDA9855, I2C_DF_NOTIFY, tda9855_probe, tda9855_detach, diff -u --recursive --new-file v2.3.35/linux/drivers/char/tea6300.c linux/drivers/char/tea6300.c --- v2.3.35/linux/drivers/char/tea6300.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/tea6300.c Wed Dec 29 17:08:55 1999 @@ -88,7 +88,7 @@ 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)) { @@ -303,7 +303,7 @@ static struct i2c_driver driver = { "i2c tea6300 driver", - I2C_DRIVERID_TEA6300, /* FIXME */ + I2C_DRIVERID_TEA6300, I2C_DF_NOTIFY, tea6300_probe, tea6300_detach, diff -u --recursive --new-file v2.3.35/linux/drivers/char/tuner.c linux/drivers/char/tuner.c --- v2.3.35/linux/drivers/char/tuner.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/tuner.c Wed Dec 29 17:08:55 1999 @@ -29,12 +29,16 @@ }; 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 { @@ -164,9 +168,9 @@ 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; @@ -255,6 +259,10 @@ struct tuner *t; struct i2c_client *client; + if (this_adap > 0) + return -1; + this_adap++; + client_template.adapter = adap; client_template.addr = addr; @@ -283,6 +291,11 @@ 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; diff -u --recursive --new-file v2.3.35/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.3.35/linux/drivers/char/videodev.c Tue Dec 7 09:32:43 1999 +++ linux/drivers/char/videodev.c Wed Dec 29 17:13:02 1999 @@ -54,9 +54,6 @@ #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 @@ -74,9 +71,6 @@ #endif #ifdef CONFIG_VIDEO_ZORAN {"zoran", init_zoran_cards}, -#endif -#ifdef CONFIG_VIDEO_ZR36120 - {"zr36120", init_zr36120_cards}, #endif {"end", NULL} }; diff -u --recursive --new-file v2.3.35/linux/drivers/char/zr36120.c linux/drivers/char/zr36120.c --- v2.3.35/linux/drivers/char/zr36120.c Tue Dec 7 09:32:43 1999 +++ linux/drivers/char/zr36120.c Wed Dec 29 17:08:55 1999 @@ -18,9 +18,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include +#include #include #include #include @@ -34,16 +34,19 @@ #include #include #include +#include #include #include #include -#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 @@ -52,9 +55,7 @@ /* 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 "); @@ -99,15 +100,21 @@ #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 }, @@ -116,23 +123,24 @@ /* 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; @@ -148,15 +156,15 @@ 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)); } @@ -165,114 +173,110 @@ 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; igrabinfo[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); } @@ -280,18 +284,43 @@ * 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 @@ -301,6 +330,7 @@ int count = 0; struct zoran *ztv = (struct zoran *)dev_id; + UNUSED(irq); UNUSED(regs); for (;;) { /* get/clear interrupt status bits */ stat=zrread(ZORAN_ISR); @@ -308,117 +338,35 @@ 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 @@ -444,31 +392,25 @@ 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; } } @@ -488,23 +430,15 @@ { 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; ix,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; ix,vp->y,vp->width,vp->height)); + } /* * activate the visible portion of the screen @@ -535,18 +469,18 @@ /* process clipping regions */ for (i=0; ix < 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; @@ -568,7 +502,7 @@ 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 @@ -591,6 +525,17 @@ }; #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) { @@ -598,9 +543,9 @@ 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 @@ -609,10 +554,14 @@ 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. @@ -621,7 +570,9 @@ */ 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; @@ -644,30 +595,30 @@ * 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; } @@ -677,86 +628,117 @@ /* 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 * 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); + vfec |= HorDcm<<14; - 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); + 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 @@ -764,60 +746,46 @@ static int zoran_open(struct video_device *dev, int flags) { struct zoran *ztv = (struct zoran*)dev; - int i; + struct vidinfo* item; + char* pos; - DEBUG(printk(KERN_DEBUG "%s: open(dev,%d)\n",CARD,flags)); + DEBUG(printk(CARD_DEBUG "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 */ - - /* clear buffer status */ - for (i=0; igrabinfo[i].status = FBUFFER_UNUSED; - ztv->state = 0; - ztv->prevstate = 0; - ztv->lastframe = -1; + /********************************************* + * 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, 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; } @@ -827,14 +795,20 @@ { 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) @@ -847,46 +821,139 @@ 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; - /* wait for data to arrive */ - interruptible_sleep_on(&ztv->readq); + 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; - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; + /* 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; + } + + /* 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); + + /* tell the state machine we want it filled /NOW/ */ + zoran_cap(ztv, 1); - /* give the user what he requested */ - max = ztv->readinfo.w*ztv->readinfo.bpp - ztv->readinfo.h*ztv->readinfo.bpl; + /* 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); + + /* 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) @@ -905,20 +972,9 @@ 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| @@ -926,25 +982,30 @@ 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 @@ -959,8 +1020,8 @@ #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 */ @@ -981,15 +1042,17 @@ 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 && @@ -1007,9 +1070,10 @@ 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"); @@ -1021,17 +1085,17 @@ 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 */ @@ -1047,7 +1111,7 @@ 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; @@ -1063,21 +1127,21 @@ } 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; @@ -1088,13 +1152,13 @@ /* 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; @@ -1102,23 +1166,21 @@ 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; @@ -1139,6 +1201,15 @@ 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; @@ -1150,10 +1221,6 @@ /* * 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) @@ -1165,36 +1232,38 @@ 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; @@ -1202,19 +1271,21 @@ 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) @@ -1222,48 +1293,50 @@ 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: @@ -1272,63 +1345,67 @@ 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; ivideo_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: @@ -1336,14 +1413,15 @@ 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; @@ -1351,20 +1429,25 @@ 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 @@ -1374,7 +1457,7 @@ 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) @@ -1383,11 +1466,7 @@ /* 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; @@ -1397,7 +1476,7 @@ return 0; } -static struct video_device zoran_template= +static struct video_device zr36120_template= { "UNSET", VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, @@ -1419,13 +1498,412 @@ }; 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; optrw; x++) + { + unsigned char a = iptr[x*2]; + *optr++ = a; + *optr++ = a; + } + /* and clear the rest of the line */ + for (x*=2; optrbpl; 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; optrw; x++) + *optr++ = iptr[x*2]; + /* and clear the rest of the line */ + for (;optrbpl; 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; ireadinfo[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; } @@ -1436,19 +1914,20 @@ 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 */ @@ -1456,40 +1935,37 @@ 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; igrabinfo[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; ireadinfo[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); @@ -1509,7 +1985,7 @@ 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); @@ -1523,29 +1999,37 @@ /* * 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;ii2c)); - /* 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(); @@ -1607,3 +2082,6 @@ } return 0; } + +module_init(zr36120_init); +module_exit(zr36120_exit); diff -u --recursive --new-file v2.3.35/linux/drivers/char/zr36120.h linux/drivers/char/zr36120.h --- v2.3.35/linux/drivers/char/zr36120.h Mon Dec 20 18:48:21 1999 +++ linux/drivers/char/zr36120.h Wed Dec 29 17:08:55 1999 @@ -43,12 +43,11 @@ 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 */ @@ -70,76 +69,84 @@ #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 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 interlace; /* calculated */ + 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) diff -u --recursive --new-file v2.3.35/linux/drivers/char/zr36120_i2c.c linux/drivers/char/zr36120_i2c.c --- v2.3.35/linux/drivers/char/zr36120_i2c.c Tue Dec 7 09:32:43 1999 +++ linux/drivers/char/zr36120_i2c.c Wed Dec 29 17:08:55 1999 @@ -23,9 +23,9 @@ #include #include +#include #include -#include "linux/video_decoder.h" #include "tuner.h" #include "zr36120.h" @@ -59,23 +59,38 @@ 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; } } @@ -88,14 +103,14 @@ 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; } } diff -u --recursive --new-file v2.3.35/linux/drivers/char/zr36120_mem.c linux/drivers/char/zr36120_mem.c --- v2.3.35/linux/drivers/char/zr36120_mem.c Tue Dec 7 09:32:43 1999 +++ linux/drivers/char/zr36120_mem.c Wed Dec 29 17:08:55 1999 @@ -22,6 +22,7 @@ #include #include #include +#include #include #ifdef CONFIG_BIGPHYS_AREA #include @@ -30,62 +31,21 @@ #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) +inline int __get_order(unsigned long size) { - 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) -{ - 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; @@ -96,7 +56,7 @@ * 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; @@ -122,7 +82,7 @@ #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 } } diff -u --recursive --new-file v2.3.35/linux/drivers/char/zr36120_mem.h linux/drivers/char/zr36120_mem.h --- v2.3.35/linux/drivers/char/zr36120_mem.h Tue Dec 7 09:32:43 1999 +++ linux/drivers/char/zr36120_mem.h Wed Dec 29 17:08:55 1999 @@ -1,17 +1,3 @@ -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); diff -u --recursive --new-file v2.3.35/linux/drivers/fc4/soc.c linux/drivers/fc4/soc.c --- v2.3.35/linux/drivers/fc4/soc.c Wed Dec 29 13:13:15 1999 +++ linux/drivers/fc4/soc.c Tue Jan 4 11:17:47 2000 @@ -205,7 +205,7 @@ hwrsp = (soc_rsp *)sw_cq->pool + sw_cq->out; hwrspc = NULL; - flags = hwrsp->shdr.flags; + flags = xram_get_16 ((xram_p)&hwrsp->shdr.flags); count = xram_get_8 ((xram_p)&hwrsp->count); fc = (fc_channel *)&s->port[flags & SOC_PORT_B]; SOD(("FC %08lx fcp_state_change %08lx\n", diff -u --recursive --new-file v2.3.35/linux/drivers/fc4/soc.h linux/drivers/fc4/soc.h --- v2.3.35/linux/drivers/fc4/soc.h Wed Dec 29 13:13:15 1999 +++ linux/drivers/fc4/soc.h Tue Jan 4 11:17:47 2000 @@ -96,6 +96,11 @@ return (u32) sbus_readw(x + 0x02UL); } +static inline u16 xram_get_16 (xram_p x) +{ + return sbus_readw(x); +} + static inline u8 xram_get_8 (xram_p x) { if (x & (xram_p)0x1) { diff -u --recursive --new-file v2.3.35/linux/drivers/fc4/socal.c linux/drivers/fc4/socal.c --- v2.3.35/linux/drivers/fc4/socal.c Wed Dec 29 13:13:15 1999 +++ linux/drivers/fc4/socal.c Tue Jan 4 11:17:47 2000 @@ -135,7 +135,6 @@ static void inline socal_solicited(struct socal *s, unsigned long qno) { - fc_hdr fchdr; socal_rsp *hwrsp; socal_cq *sw_cq; int token; @@ -144,11 +143,6 @@ sw_cq = &s->rsp[qno]; - if (sw_cq->pool == NULL) { - SOD(("address %08x xram %p\n", sw_cq->hw_cq->address, s->xram)) - sw_cq->pool = - (socal_req *)(s->xram + (sw_cq->hw_cq->address & 0xfffe)); - } /* Finally an improvement against old SOC :) */ sw_cq->in = sbus_readb(s->regs + RESP + qno); SOD (("socal_solicited, %d packets arrived\n", @@ -199,13 +193,12 @@ token & ((1 << 11) - 1), FC_STATUS_OK, NULL); } else { - socal_copy_from_xram(&fchdr, &hwrsp->fchdr, sizeof(fchdr)); /* We have intentionally defined FC_STATUS_* constants * to match SOCAL_* constants, otherwise we'd have to * translate status. */ fcp_receive_solicited(fc, token >> 12, - token & ((1 << 11) - 1), status, &fchdr); + token & ((1 << 11) - 1), status, &hwrsp->fchdr); } if (++sw_cq->out > sw_cq->last) { @@ -259,11 +252,6 @@ fc_channel *fc; sw_cq = &s->rsp[qno]; - if (sw_cq->pool == NULL) { - SOD(("address %08x xram %lx\n", sw_cq->hw_cq->address, s->xram)) - sw_cq->pool = - (socal_req *)(s->xram + (sw_cq->hw_cq->address & 0xfffe)); - } sw_cq->in = sbus_readb(s->regs + RESP + qno); SOD (("socal_unsolicited, %d packets arrived, in %d\n", @@ -352,7 +340,6 @@ { int r_ctl = *((u8 *)&hwrsp->fchdr); unsigned len; - char buf[64]; if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) { len = hwrsp->shdr.bytecnt; @@ -363,21 +350,19 @@ } else { if (len > 60) len = 60; - socal_copy_from_xram(buf, hwrspc, - (len + 3) & ~3); - if (*(u32 *)buf == LS_DISPLAY) { + if (*(u32 *)hwrspc == LS_DISPLAY) { int i; for (i = 4; i < len; i++) - if (buf[i] == '\n') - buf[i] = ' '; - buf[len] = 0; + if (((u8 *)hwrspc)[i] == '\n') + ((u8 *)hwrspc)[i] = ' '; + ((u8 *)hwrspc)[len] = 0; printk ("%s message: %s\n", - fc->name, buf + 4); + fc->name, ((u8 *)hwrspc) + 4); } else { printk ("%s: Unknown LS_CMD " "%08x\n", fc->name, - *(u32 *)buf); + *(u32 *)hwrspc); } } } else { diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c --- v2.3.35/linux/drivers/i2c/i2c-algo-bit.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-algo-bit.c Wed Dec 29 17:29:43 1999 @@ -21,10 +21,7 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ - -/* -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 #include diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-algo-pcf.c linux/drivers/i2c/i2c-algo-pcf.c --- v2.3.35/linux/drivers/i2c/i2c-algo-pcf.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-algo-pcf.c Wed Dec 29 17:29:43 1999 @@ -23,6 +23,8 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ +/* $Id: i2c-algo-pcf.c,v 1.15 1999/12/21 23:45:58 frodo Exp $ */ + #include #include #include diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c --- v2.3.35/linux/drivers/i2c/i2c-core.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-core.c Wed Dec 29 17:29:43 1999 @@ -16,12 +16,12 @@ 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 . All SMBus-related things are written by Frodo Looijaard */ +/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */ + #include #include #include @@ -451,12 +451,23 @@ 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; @@ -855,6 +866,10 @@ 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; @@ -1311,6 +1326,7 @@ 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); diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-dev.c linux/drivers/i2c/i2c-dev.c --- v2.3.35/linux/drivers/i2c/i2c-dev.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-dev.c Wed Dec 29 17:29:43 1999 @@ -23,6 +23,8 @@ 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 #include #include @@ -277,8 +279,11 @@ 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: diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-elektor.c linux/drivers/i2c/i2c-elektor.c --- v2.3.35/linux/drivers/i2c/i2c-elektor.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-elektor.c Wed Dec 29 17:29:43 1999 @@ -22,6 +22,8 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ +/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */ + #include #include #include diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-elv.c linux/drivers/i2c/i2c-elv.c --- v2.3.35/linux/drivers/i2c/i2c-elv.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-elv.c Wed Dec 29 17:29:43 1999 @@ -17,11 +17,11 @@ 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 and even Frodo Looijaard */ + +/* $Id: i2c-elv.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */ #include #include diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-pcf8584.h linux/drivers/i2c/i2c-pcf8584.h --- v2.3.35/linux/drivers/i2c/i2c-pcf8584.h Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-pcf8584.h Wed Dec 29 17:29:43 1999 @@ -18,9 +18,10 @@ 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 */ + +/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */ #ifndef I2C_PCF8584_H #define I2C_PCF8584_H 1 diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-philips-par.c linux/drivers/i2c/i2c-philips-par.c --- v2.3.35/linux/drivers/i2c/i2c-philips-par.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-philips-par.c Wed Dec 29 17:29:43 1999 @@ -17,11 +17,11 @@ 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 and even Frodo Looijaard */ + +/* $Id: i2c-philips-par.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */ #include #include diff -u --recursive --new-file v2.3.35/linux/drivers/i2c/i2c-velleman.c linux/drivers/i2c/i2c-velleman.c --- v2.3.35/linux/drivers/i2c/i2c-velleman.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/i2c/i2c-velleman.c Wed Dec 29 17:29:43 1999 @@ -17,8 +17,8 @@ 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 #include diff -u --recursive --new-file v2.3.35/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.3.35/linux/drivers/i2o/i2o_core.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/i2o/i2o_core.c Wed Dec 29 17:16:30 1999 @@ -45,6 +45,8 @@ // #define DRIVERDEBUG // #define DEBUG_IRQ +#define dprintk(x) + /* * Size of the I2O module table */ @@ -53,7 +55,6 @@ 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); @@ -61,9 +62,9 @@ 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 *); @@ -149,8 +150,8 @@ 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); @@ -158,7 +159,7 @@ 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); @@ -176,7 +177,7 @@ 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); } @@ -356,8 +357,7 @@ 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); @@ -427,7 +427,7 @@ 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; } @@ -443,7 +443,10 @@ 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; @@ -463,7 +466,7 @@ else { if(i2o_issue_claim(d->controller, d->lct_data->tid, h->context, 0, - &reply_flag, type)) + type)) { err = -ENXIO; } @@ -486,7 +489,7 @@ atomic_dec(&d->controller->users); if(i2o_issue_claim(d->controller,d->lct_data->tid, h->context, 0, - &reply_flag, type)) + type)) err = -ENXIO; } @@ -647,10 +650,8 @@ { 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(); @@ -673,10 +674,8 @@ { 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(); @@ -685,106 +684,6 @@ } -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(iname); -#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) */ @@ -832,25 +731,25 @@ 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; @@ -912,6 +811,7 @@ printk("\n"); rows+=length; } + #endif return 0; } @@ -938,27 +838,27 @@ 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;istatus_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; + if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) + printk(KERN_ERR "%s: Could not enable, %d\n", c->name, ret); - 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 - } - } - - 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; } @@ -1134,97 +971,82 @@ 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; } @@ -1235,127 +1057,172 @@ 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); - return i2o_post_wait(c, msg, sizeof(msg), 20); + i2o_parse_hrt(c); // just for debugging + + 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); */ + 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); + + if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120))) + printk(KERN_INFO "%s: Unable to set SysTab, %d\n", + iop->name, ret); - ret=i2o_post_wait(iop, msg, sizeof(msg), 120); - if(ret) - return ret; + return ret; - return 0; -} + } /* * Initialize I2O subsystem. @@ -1550,17 +1417,20 @@ * * 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); } } @@ -1589,8 +1459,8 @@ 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; @@ -1627,43 +1497,20 @@ 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); @@ -1675,23 +1522,26 @@ */ 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; @@ -1699,30 +1549,41 @@ 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; } @@ -1732,34 +1593,41 @@ int i2o_lct_get(struct i2o_controller *c) { u32 msg[8]; + int ret, size = c->status_block->expected_lct_size; -#ifdef DRIVERDEBUG - printk(KERN_INFO "Getting lct for iop%d\n", c->unit); -#endif + 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); - if(c->lct) - kfree(c->lct); + 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; + } - 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)); + if (c->lct->table_size << 2 > size) { + size = c->lct->table_size << 2; + kfree(c->lct); + c->lct = NULL; + } + } while (c->lct == NULL); + + return 0; } @@ -1774,69 +1642,67 @@ 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 } @@ -1844,23 +1710,19 @@ { 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; @@ -1869,8 +1731,11 @@ 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; @@ -1894,9 +1759,12 @@ } #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; @@ -1929,12 +1797,13 @@ 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; } @@ -1947,16 +1816,13 @@ 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 @@ -1964,48 +1830,29 @@ 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); @@ -2020,7 +1867,7 @@ */ 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 @@ -2035,42 +1882,75 @@ * 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 @@ -2085,10 +1965,7 @@ 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; @@ -2099,31 +1976,21 @@ 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 */ } /* @@ -2138,10 +2005,10 @@ 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; @@ -2673,6 +2540,10 @@ 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); @@ -2691,7 +2562,6 @@ 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); @@ -2699,25 +2569,23 @@ 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) diff -u --recursive --new-file v2.3.35/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c --- v2.3.35/linux/drivers/i2o/i2o_lan.c Thu Nov 11 20:11:35 1999 +++ linux/drivers/i2o/i2o_lan.c Wed Dec 29 17:16:30 1999 @@ -1,7 +1,7 @@ /* * 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 @@ -20,8 +20,7 @@ * 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 */ @@ -45,7 +44,7 @@ #include #include "i2o_lan.h" -#define DRIVERDEBUG +//#define DRIVERDEBUG #ifdef DRIVERDEBUG #define dprintk(s, args...) printk(s, ## args) #else @@ -68,16 +67,22 @@ 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); @@ -87,8 +92,11 @@ 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) @@ -116,10 +124,10 @@ 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; } @@ -128,27 +136,27 @@ 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 */ @@ -217,7 +225,7 @@ 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]); @@ -267,22 +275,20 @@ /* 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--; } } @@ -291,50 +297,35 @@ 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); @@ -344,67 +335,74 @@ 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 @@ -441,7 +439,7 @@ 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 @@ -459,12 +457,6 @@ */ 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; @@ -474,13 +466,11 @@ // 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, @@ -508,28 +498,32 @@ { 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; @@ -543,14 +537,14 @@ { 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); @@ -559,6 +553,10 @@ 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; @@ -576,6 +574,22 @@ } #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. * @@ -588,63 +602,75 @@ 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; @@ -653,7 +679,7 @@ 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 { @@ -703,8 +729,7 @@ 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) @@ -713,7 +738,6 @@ priv->stats.tx_heartbeat_errors = val64[2]; } } - } #ifdef CONFIG_TR @@ -724,7 +748,7 @@ 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]; @@ -747,7 +771,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); @@ -782,7 +806,7 @@ 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; } @@ -863,7 +887,7 @@ 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); @@ -934,6 +958,7 @@ 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; @@ -956,7 +981,7 @@ 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--; @@ -964,11 +989,11 @@ 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; @@ -989,7 +1014,12 @@ 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; @@ -1085,7 +1115,7 @@ 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"); diff -u --recursive --new-file v2.3.35/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.35/linux/drivers/net/Config.in Wed Dec 8 14:11:26 1999 +++ linux/drivers/net/Config.in Thu Dec 30 11:51:26 1999 @@ -2,20 +2,7 @@ # Network device configuration # -mainmenu_option next_comment -comment 'ARCnet devices' - -tristate 'ARCnet support' CONFIG_ARCNET -if [ "$CONFIG_ARCNET" != "n" ]; then - bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH - bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051 - dep_tristate ' ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET - dep_tristate ' ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET - dep_tristate ' ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET - dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET -fi - -endmenu +source drivers/net/arcnet/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER diff -u --recursive --new-file v2.3.35/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.35/linux/drivers/net/Makefile Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/Makefile Thu Dec 30 11:51:26 1999 @@ -17,7 +17,7 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := -ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin +ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin arcnet O_TARGET := net.o O_OBJS := @@ -27,7 +27,7 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := 8390.o arcnet.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \ +export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \ ppp_generic.o slhc.o ifeq ($(CONFIG_PCMCIA),y) @@ -96,6 +96,15 @@ endif endif +ifeq ($(CONFIG_ARCNET),y) +SUB_DIRS += arcnet +MOD_IN_SUB_DIRS += arcnet +else + ifeq ($(CONFIG_ARCNET),m) + MOD_IN_SUB_DIRS += arcnet + endif +endif + obj-$(CONFIG_AIRONET4500) += aironet4500_core.o @@ -215,11 +224,6 @@ obj-$(CONFIG_MVME16x_NET) += 82596.o obj-$(CONFIG_BVME6000_NET) += 82596.o obj-$(CONFIG_DEC_ELCP) += tulip.o -obj-$(CONFIG_ARCNET) += arcnet.o -obj-$(CONFIG_ARCNET_COM90xx) += com90xx.o -obj-$(CONFIG_ARCNET_COM90xxIO) += com90io.o -obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o -obj-$(CONFIG_ARCNET_COM20020) += com20020.o obj-$(CONFIG_ETH16I) += eth16i.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o diff -u --recursive --new-file v2.3.35/linux/drivers/net/aironet4500_core.c linux/drivers/net/aironet4500_core.c --- v2.3.35/linux/drivers/net/aironet4500_core.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/net/aironet4500_core.c Tue Jan 4 09:41:45 2000 @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -3265,4 +3266,4 @@ } #endif - \ No newline at end of file + diff -u --recursive --new-file v2.3.35/linux/drivers/net/arc-rimi.c linux/drivers/net/arc-rimi.c --- v2.3.35/linux/drivers/net/arc-rimi.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/arc-rimi.c Wed Dec 31 16:00:00 1969 @@ -1,844 +0,0 @@ -/* $Id: arc-rimi.c,v 1.5 1997/11/09 11:04:57 mj Exp $ - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** -*/ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/**************************************************************************/ - -/* On a fast computer, the buffer copy from memory to the ARCnet card during - * a transmit can hog the bus just a little too long. SLOW_XMIT_COPY - * replaces the fast memcpy() with a slower for() loop that seems to solve - * my problems with ftape. - * - * Probably a better solution would be to use memcpy_toio (more portable - * anyway) and modify that routine to support REALLY_SLOW_IO-style - * defines; ARCnet probably is not the only driver that can screw up an - * ftape DMA transfer. - * - * Turn this on if you have timing-sensitive DMA (ie. a tape drive) and - * would like to sacrifice a little bit of network speed to reduce tape - * write retries or some related problem. - */ -#undef SLOW_XMIT_COPY - - -/* Internal function declarations */ - -static int arcrimi_probe(struct net_device *dev); -static void arcrimi_rx(struct net_device *dev,int recbuf); -static int arcrimi_found(struct net_device *dev,int ioaddr,int airq,u_long shmem); -static void arcrimi_inthandler (struct net_device *dev); -static int arcrimi_reset (struct net_device *dev, int reset_delay); -static void arcrimi_setmask (struct net_device *dev, u_char mask); -static void arcrimi_command (struct net_device *dev, u_char command); -static u_char arcrimi_status (struct net_device *dev); -static void arcrimi_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset); -static void arcrimi_openclose(int open); - - -/* Module parameters */ - -#ifdef MODULE -static int shmem=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq=0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ -static int node=0; /* you must specify the node ID for RIM I cards */ - -MODULE_PARM(shmem, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM (node, "i"); -#else -void __init arcrimi_setup (char *str, int *ints); -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - -/* Handy defines for ARCnet specific stuff */ - -/* COM 9026 controller chip --> ARCnet register addresses */ -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _RESET (ioaddr+8) /* software reset (on read) */ -#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+15) /* Control registers for said */ -#define _ADDR_LO (ioaddr+14) -#define _CONFIG (ioaddr+2) /* Configuration register */ - -#define RDDATAflag 0x00 /* Next access is a read/~write */ - -#define ARCSTATUS readb(_STATUS) -#define ACOMMAND(cmd) writeb((cmd),_COMMAND) -#define ARCRESET writeb(TESTvalue,ioaddr-0x800) /* fake reset */ -#define AINTMASK(msk) writeb((msk),_INTMASK) -#define SETCONF writeb(lp->config,_CONFIG) - -static const char *version = -"arc-rimi.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - - -/* We cannot probe for a RIM I card; one reason is I don't know how to reset - * them. In fact, we can't even get their node ID automatically. So, we - * need to be passed a specific shmem address, IRQ, and node ID. - */ -int __init arcrimi_probe(struct net_device *dev) -{ - BUGLVL(D_NORMAL) printk(version); - BUGMSG(D_NORMAL,"Given: node %02Xh, shmem %lXh, irq %d\n", - dev->dev_addr[0],dev->mem_start,dev->irq); - - if (dev->mem_start<=0 || dev->irq<=0) - { - BUGMSG(D_NORMAL,"No autoprobe for RIM I; you " - "must specify the shmem and irq!\n"); - return -ENODEV; - } - - if (dev->dev_addr[0]==0) - { - BUGMSG(D_NORMAL,"You need to specify your card's station " - "ID!\n"); - return -ENODEV; - } - - return arcrimi_found(dev,dev->dev_addr[0],dev->irq,dev->mem_start); -} - - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -int __init arcrimi_found(struct net_device *dev,int node,int airq, u_long shmem) -{ - struct arcnet_local *lp; - u_long first_mirror,last_mirror; - int mirror_size; - - /* reserve the irq */ - if (request_irq(airq,&arcnet_interrupt,0,"arcnet (RIM I)",dev)) - { - BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq); - return -ENODEV; - } - dev->irq=airq; - - dev->base_addr=0; - writeb(TESTvalue,shmem); - writeb(node,shmem+1); /* actually the node ID */ - - /* find the real shared memory start/end points, including mirrors */ -#define BUFFER_SIZE (512) -#define MIRROR_SIZE (BUFFER_SIZE*4) - - /* guess the actual size of one "memory mirror" - the number of - * bytes between copies of the shared memory. On most cards, it's - * 2k (or there are no mirrors at all) but on some, it's 4k. - */ - mirror_size=MIRROR_SIZE; - if (readb(shmem)==TESTvalue - && readb(shmem-mirror_size)!=TESTvalue - && readb(shmem-2*mirror_size)==TESTvalue) - mirror_size*=2; - - first_mirror=last_mirror=shmem; - while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size; - first_mirror+=mirror_size; - - while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size; - last_mirror-=mirror_size; - - dev->mem_start=first_mirror; - dev->mem_end=last_mirror+MIRROR_SIZE-1; - dev->rmem_start=dev->mem_start+BUFFER_SIZE*0; - dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) - { - free_irq(airq,dev); - return -ENOMEM; - } - memset(dev->priv,0,sizeof(struct arcnet_local)); - lp=(struct arcnet_local *)(dev->priv); - lp->card_type = ARC_RIM_I; - lp->card_type_str = "RIM I"; - lp->arcnet_reset=arcrimi_reset; - lp->asetmask=arcrimi_setmask; - lp->astatus=arcrimi_status; - lp->acommand=arcrimi_command; - lp->openclose_device=arcrimi_openclose; - lp->prepare_tx=arcrimi_prepare_tx; - lp->inthandler=arcrimi_inthandler; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu=1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len=sizeof(struct ClientData); - lp->sequence=1; - lp->recbuf=0; - - BUGMSG(D_DURING,"ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING,"HardHeader size is %d.\n", - sizeof(struct archdr)); - - /* get and check the station ID from offset 1 in shmem */ - lp->stationid = readb(first_mirror+1); - - if (lp->stationid==0) - BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid==255) - BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0]=lp->stationid; - - BUGMSG(D_NORMAL,"ARCnet RIM I: station %02Xh found at IRQ %d, " - "ShMem %lXh (%ld*%d bytes).\n", - lp->stationid, - dev->irq, dev->mem_start, - (dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size); - - return 0; -} - - -/* Do a hardware reset on the card, and set up necessary registers. - * - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arcrimi_reset(struct net_device *dev,int reset_delay) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - short ioaddr=dev->mem_start + 0x800; - int recbuf=lp->recbuf; - - if (reset_delay==3) - { - ARCRESET; - return 0; - } - - /* no IRQ's, please! */ - lp->intmask=0; - SETMASK; - - BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", - dev->name,ARCSTATUS); - - ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd|CONFIGclear); - - /* clear out status variables */ - recbuf=lp->recbuf=0; - lp->txbuf=2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd|EXTconf); - -#ifndef SLOW_XMIT_COPY - /* clean out all the memory to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start,0x42,2048); -#endif - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask|=NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask|=RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -static void arcrimi_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - -static void arcrimi_setmask(struct net_device *dev, u_char mask) -{ - int ioaddr=dev->mem_start+0x800; - - AINTMASK(mask); -} - -static u_char arcrimi_status(struct net_device *dev) -{ - int ioaddr=dev->mem_start+0x800; - - return ARCSTATUS; -} - -static void arcrimi_command(struct net_device *dev, u_char cmd) -{ - int ioaddr=dev->mem_start+0x800; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void -arcrimi_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->mem_start+0x800, status, boguscount = 3, didsomething; - - AINTMASK(0); - - BUGMSG(D_DURING,"in arcrimi_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS,lp->intmask); - - do - { - status = ARCSTATUS; - didsomething=0; - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) - { - BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", - status); - arcrimi_reset(dev,0); - - /* all other flag values are just garbage */ - break; - } - - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) - { - int recbuf=lp->recbuf=!lp->recbuf; - - BUGMSG(D_DURING,"receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - /* Got a packet. */ - arcrimi_rx(dev,!recbuf); - - didsomething++; - } - - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ - if (status & lp->intmask & TXFREEflag) - { - struct Outgoing *out=&(lp->outgoing); - int was_sending=lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) lp->sending--; - - BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status,out->numsegs,out->segnum,out->skb); - - if (was_sending && !(status&TXACKflag)) - { - if (lp->lasttrans_dest != 0) - { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } - else - { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - - /* send packet if there is one */ - arcnet_go_tx(dev,0); - didsomething++; - - if (lp->intx) - { - BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS,lp->intx); - lp->in_txhandler--; - continue; - } - - if (!lp->outgoing.skb) - { - BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnumnumsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum>=out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb=NULL; - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } - else if (lp->txready && !lp->sending && !lp->intx) - { - BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev,0); - didsomething++; - } - -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) - { - ACOMMAND(CFLAGScmd|CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n", - status); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); - lp->first_recon=lp->last_recon=jiffies; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"recon: clearing counters.\n"); - } - else /* add to current RECON counter */ - { - lp->last_recon=jiffies; - lp->num_recons++; - - BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon-lp->first_recon)/HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon-lp->first_recon)<=HZ*60 - && lp->num_recons >= RECON_THRESHOLD) - { - lp->network_down=1; - BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); - } - else if (!lp->network_down - && lp->last_recon-lp->first_recon > HZ*60) - { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon=lp->last_recon; - lp->num_recons=1; - } - } - } - else if (lp->network_down && jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"cabling restored?\n"); - lp->first_recon=lp->last_recon=0; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS,boguscount); - BUGMSG(D_DURING,"\n"); - - SETMASK; /* put back interrupt mask */ -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void -arcrimi_rx(struct net_device *dev,int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=dev->mem_start+0x800; - union ArcPacket *arcpacket= - (union ArcPacket *)phys_to_virt(dev->mem_start+recbuf*512); - u_char *arcsoft; - short length,offset; - u_char daddr,saddr; - - lp->stats.rx_packets++; - - saddr=arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr==0) - { - BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - arcpacket->hardheader.source=0; - - daddr=arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) /* Normal Packet */ - { - offset=arcpacket->hardheader.offset1; - arcsoft=&arcpacket->raw[offset]; - length=256-offset; - } - else /* ExtendedPacket or ExceptionPacket */ - { - offset=arcpacket->hardheader.offset2; - arcsoft=&arcpacket->raw[offset]; - - length=512-offset; - } - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx"); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset((void *)arcpacket->raw,0x42,512); -#endif -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void -arcrimi_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - union ArcPacket *arcpacket = - (union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1)); - -#ifdef SLOW_XMIT_COPY - char *iptr,*iend,*optr; -#endif - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ - - length+=hdrlen; - - BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr,length,data); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start+lp->txbuf*512,0x42,512); -#endif - - arcpacket->hardheader.destination=daddr; - - /* load packet into shared memory */ - if (length<=MTU) /* Normal (256-byte) Packet */ - arcpacket->hardheader.offset1=offset=offset?offset:256-length; - - else if (length>=MinTU || offset) /* Extended (512-byte) Packet */ - { - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=offset?offset:512-length; - } - else if (exceptA) /* RFC1201 Exception Packet */ - { - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=512-length-4; - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - arcpacket->raw[offset+0]=hdr[0]; - arcpacket->raw[offset+1]=0xFF; /* FF flag */ - arcpacket->raw[offset+2]=0xFF; /* FF padding */ - arcpacket->raw[offset+3]=0xFF; /* FF padding */ - offset+=4; - } - else /* "other" Exception packet */ - { - /* RFC1051 - set 4 trailing bytes to 0 */ - memset(&arcpacket->raw[508],0,4); - - /* now round up to MinTU */ - arcpacket->hardheader.offset1=0; - arcpacket->hardheader.offset2=offset=512-MinTU; - } - - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - memcpy((u_char*)arcpacket+offset, (u_char*)hdr,hdrlen); -#ifdef SLOW_XMIT_COPY - for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcpacket+offset+hdrlen; - iptrraw,length>MTU,"tx"); - - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static char devicename[9] = ""; -static struct net_device thiscard = { - devicename, /* device name is inserted by linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0, 0, /* I/O address, IRQ */ - 0, 0, 0, NULL, arcrimi_probe -}; - - -int init_module(void) -{ - struct net_device *dev=&thiscard; - if (device) - strcpy(dev->name,device); - else arcnet_makename(dev->name); - - if (node && node != 0xff) - dev->dev_addr[0]=node; - - dev->irq=irq; - if (dev->irq==2) dev->irq=9; - - if (shmem) - { - dev->mem_start=shmem; - dev->mem_end=thiscard.mem_start+512*4-1; - dev->rmem_start=thiscard.mem_start+512*0; - dev->rmem_end=thiscard.mem_start+512*2-1; - } - - if (register_netdev(dev) != 0) - return -EIO; - arcnet_use_count(1); - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev=&thiscard; - int ioaddr=dev->mem_start; - - if (dev->start) (*dev->stop)(dev); - - /* Flush TX and disable RX */ - if (ioaddr) - { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - } - - if (dev->irq) - { - free_irq(dev->irq,dev); - } - - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - arcnet_use_count(0); -} - -#else - -void __init arcrimi_setup (char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) - { - printk("ARCnet RIM I: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - - dev=&arcnet_devs[arcnet_num_devs]; - - if (ints[0] < 3) - { - printk("ARCnet RIM I: You must give address, IRQ and node ID.\n"); - return; - } - - dev->init=arcrimi_probe; - - switch(ints[0]) - { - case 4: /* ERROR */ - printk("ARCnet RIM I: Too many arguments.\n"); - - case 3: /* Node ID */ - dev->dev_addr[0]=(u_char)ints[3]; - - case 2: /* IRQ */ - dev->irq=ints[2]; - - case 1: /* Mem address */ - dev->mem_start=ints[1]; - } - - dev->name = (char *)&arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/Config.in linux/drivers/net/arcnet/Config.in --- v2.3.35/linux/drivers/net/arcnet/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/Config.in Thu Dec 30 11:51:26 1999 @@ -0,0 +1,23 @@ +# +# Arcnet configuration +# + +mainmenu_option next_comment +comment 'ARCnet devices' + +tristate 'ARCnet support' CONFIG_ARCNET +if [ "$CONFIG_ARCNET" != "n" ]; then + dep_tristate 'Enable standard ARCNet packet format (RFC 1201)' CONFIG_ARCNET_1201 $CONFIG_ARCNET + dep_tristate 'Enable old ARCNet packet format (RFC 1051)' CONFIG_ARCNET_1051 $CONFIG_ARCNET + dep_tristate 'Enable raw mode packet interface' CONFIG_ARCNET_RAW $CONFIG_ARCNET + dep_tristate 'ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET + dep_tristate 'ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET + dep_tristate 'ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET + dep_tristate 'ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET + if [ "$CONFIG_ARCNET_COM20020" != "n" ]; then + dep_tristate ' Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET + dep_tristate ' Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET + fi +fi + +endmenu diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/Makefile linux/drivers/net/arcnet/Makefile --- v2.3.35/linux/drivers/net/arcnet/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/Makefile Thu Dec 30 11:51:26 1999 @@ -0,0 +1,35 @@ +# Makefile for linux/drivers/net/arcnet +# +# 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). +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +obj-y := +obj-n := +obj-m := +obj- := +export-objs := arcnet.o com20020.o + +obj-$(CONFIG_ARCNET) += arcnet.o +obj-$(CONFIG_ARCNET_1201) += rfc1201.o +obj-$(CONFIG_ARCNET_1051) += rfc1051.o +obj-$(CONFIG_ARCNET_RAW) += arc-rawmode.o +obj-$(CONFIG_ARCNET_COM90xx) += com90xx.o +obj-$(CONFIG_ARCNET_COM90xxIO) += com90io.o +obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o +obj-$(CONFIG_ARCNET_COM20020) += com20020.o +obj-$(CONFIG_ARCNET_COM20020_ISA) += com20020-isa.o +obj-$(CONFIG_ARCNET_COM20020_PCI) += com20020-pci.o + +L_TARGET := arcnet.a +L_OBJS := $(filter-out $(export-objs), $(obj-y)) +LX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/arc-rawmode.c linux/drivers/net/arcnet/arc-rawmode.c --- v2.3.35/linux/drivers/net/arcnet/arc-rawmode.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/arc-rawmode.c Tue Jan 4 09:41:45 2000 @@ -0,0 +1,204 @@ +/* + * Linux ARCnet driver - "raw mode" packet encapsulation (no soft headers) + * + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ + +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "arcnet: raw mode (`r') encapsulation support loaded.\n" + + +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum); + + +struct ArcProto rawmode_proto = +{ + 'r', + XMTU, + rx, + build_header, + prepare_tx +}; + + +void arcnet_raw_init(void) +{ + int count; + + for (count = 0; count < 256; count++) + if (arc_proto_map[count] == arc_proto_default) + arc_proto_map[count] = &rawmode_proto; + + /* for raw mode, we only set the bcast proto if there's no better one */ + if (arc_bcast_proto == arc_proto_default) + arc_bcast_proto = &rawmode_proto; + + arc_proto_default = &rawmode_proto; +} + + +#ifdef MODULE + +int __init init_module(void) +{ + printk(VERSION); + arcnet_raw_init(); + return 0; +} + +void cleanup_module(void) +{ + arcnet_unregister_proto(&rawmode_proto); +} + +#endif /* MODULE */ + + + +/* packet receiver */ +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct sk_buff *skb; + struct archdr *pkt = pkthdr; + int ofs; + + BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); + + if (length >= MinTU) + ofs = 512 - length; + else + ofs = 256 - length; + + skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb_put(skb, length + ARC_HDR_SIZE); + skb->dev = dev; + + pkt = (struct archdr *) skb->data; + + skb->mac.raw = skb->data; + skb_pull(skb, ARC_HDR_SIZE); + + /* up to sizeof(pkt->soft) has already been copied from the card */ + memcpy(pkt, pkthdr, sizeof(struct archdr)); + if (length > sizeof(pkt->soft)) + lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), + pkt->soft.raw + sizeof(pkt->soft), + length - sizeof(pkt->soft)); + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = 0; + netif_rx(skb); +} + + +/* + * Create the ARCnet hard/soft headers for raw mode. + * There aren't any soft headers in raw mode - not even the protocol id. + */ +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + int hdr_size = ARC_HDR_SIZE; + struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help in + * debugging. ARCnet does not allow us to change the source address in + * the actual packet sent) + */ + pkt->hard.source = *dev->dev_addr; + + /* see linux/net/ethernet/eth.c to see where I got the following */ + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + /* + * FIXME: fill in the last byte of the dest ipaddr here to better + * comply with RFC1051 in "noarp" mode. + */ + pkt->hard.dest = 0; + return hdr_size; + } + /* otherwise, just fill it in and go! */ + pkt->hard.dest = daddr; + + return hdr_size; /* success */ +} + + +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arc_hardware *hard = &pkt->hard; + int ofs; + + BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", + lp->next_tx, lp->cur_tx, bufnum); + + length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ + + if (length > XMTU) { + /* should never happen! other people already check for this. */ + BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n", + length, XMTU); + length = XMTU; + } + if (length > MinTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length; + } else if (length > MTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length - 3; + } else + hard->offset[0] = ofs = 256 - length; + + lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); + lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length); + + lp->lastload_dest = hard->dest; + + return 1; /* done */ +} diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/arc-rimi.c linux/drivers/net/arcnet/arc-rimi.c --- v2.3.35/linux/drivers/net/arcnet/arc-rimi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/arc-rimi.c Sun Jan 2 00:46:32 2000 @@ -0,0 +1,383 @@ +/* + * Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards + * + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VERSION "arcnet: RIM I (entirely mem-mapped) support\n" + + +/* Internal function declarations */ + +static int arcrimi_probe(struct net_device *dev); +static int arcrimi_found(struct net_device *dev); +static void arcrimi_command(struct net_device *dev, int command); +static int arcrimi_status(struct net_device *dev); +static void arcrimi_setmask(struct net_device *dev, int mask); +static int arcrimi_reset(struct net_device *dev, int really_reset); +static void arcrimi_openclose(struct net_device *dev, bool open); +static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); +static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); + +/* Handy defines for ARCnet specific stuff */ + +/* Amount of I/O memory used by the card */ +#define BUFFER_SIZE (512) +#define MIRROR_SIZE (BUFFER_SIZE*4) + +/* COM 9026 controller chip --> ARCnet register addresses */ +#define _INTMASK (ioaddr+0) /* writable */ +#define _STATUS (ioaddr+0) /* readable */ +#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ +#define _RESET (ioaddr+8) /* software reset (on read) */ +#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ +#define _ADDR_HI (ioaddr+15) /* Control registers for said */ +#define _ADDR_LO (ioaddr+14) +#define _CONFIG (ioaddr+2) /* Configuration register */ + +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ASTATUS() readb(_STATUS) +#define ACOMMAND(cmd) writeb((cmd),_COMMAND) +#define AINTMASK(msk) writeb((msk),_INTMASK) +#define SETCONF() writeb(lp->config,_CONFIG) + + +/* + * We cannot probe for a RIM I card; one reason is I don't know how to reset + * them. In fact, we can't even get their node ID automatically. So, we + * need to be passed a specific shmem address, IRQ, and node ID. + */ +static int __init arcrimi_probe(struct net_device *dev) +{ + BUGLVL(D_NORMAL) printk(VERSION); + BUGLVL(D_NORMAL) printk("E-mail me if you actually test the RIM I driver, please!\n"); + + BUGMSG(D_NORMAL, "Given: node %02Xh, shmem %lXh, irq %d\n", + dev->dev_addr[0], dev->mem_start, dev->irq); + + if (dev->mem_start <= 0 || dev->irq <= 0) { + BUGMSG(D_NORMAL, "No autoprobe for RIM I; you " + "must specify the shmem and irq!\n"); + return -ENODEV; + } + if (check_mem_region(dev->mem_start, BUFFER_SIZE)) { + BUGMSG(D_NORMAL, "Card memory already allocated\n"); + return -ENODEV; + } + if (dev->dev_addr[0] == 0) { + BUGMSG(D_NORMAL, "You need to specify your card's station " + "ID!\n"); + return -ENODEV; + } + return arcrimi_found(dev); +} + + +/* + * Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +static int __init arcrimi_found(struct net_device *dev) +{ + struct arcnet_local *lp; + u_long first_mirror, last_mirror, shmem; + int mirror_size; + + /* reserve the irq */ { + if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); + return -ENODEV; + } + + shmem = dev->mem_start; + isa_writeb(TESTvalue, shmem); + isa_writeb(dev->dev_addr[0], shmem + 1); /* actually the node ID */ + + /* find the real shared memory start/end points, including mirrors */ + + /* guess the actual size of one "memory mirror" - the number of + * bytes between copies of the shared memory. On most cards, it's + * 2k (or there are no mirrors at all) but on some, it's 4k. + */ + mirror_size = MIRROR_SIZE; + if (isa_readb(shmem) == TESTvalue + && isa_readb(shmem - mirror_size) != TESTvalue + && isa_readb(shmem - 2 * mirror_size) == TESTvalue) + mirror_size *= 2; + + first_mirror = last_mirror = shmem; + while (isa_readb(first_mirror) == TESTvalue) + first_mirror -= mirror_size; + first_mirror += mirror_size; + + while (isa_readb(last_mirror) == TESTvalue) + last_mirror += mirror_size; + last_mirror -= mirror_size; + + dev->mem_start = first_mirror; + dev->mem_end = last_mirror + MIRROR_SIZE - 1; + dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0; + dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1; + + /* initialize the rest of the device structure. */ + + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) { + BUGMSG(D_NORMAL, "Can't allocate device data!\n"); + goto err_free_irq; + } + lp->hw.command = arcrimi_command; + lp->hw.status = arcrimi_status; + lp->hw.intmask = arcrimi_setmask; + lp->hw.reset = arcrimi_reset; + lp->hw.open_close = arcrimi_openclose; + lp->hw.copy_to_card = arcrimi_copy_to_card; + lp->hw.copy_from_card = arcrimi_copy_from_card; + lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); + if (!lp->mem_start) { + BUGMSG(D_NORMAL, "Can't remap device memory!\n"); + goto err_free_dev_priv; + } + /* Fill in the fields of the device structure with generic + * values. + */ + arcdev_setup(dev); + + /* get and check the station ID from offset 1 in shmem */ + dev->dev_addr[0] = readb(lp->mem_start + 1); + + /* reserve the memory region - guaranteed to work by check_region */ + request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"); + + BUGMSG(D_NORMAL, "ARCnet RIM I: station %02Xh found at IRQ %d, " + "ShMem %lXh (%ld*%d bytes).\n", + dev->dev_addr[0], + dev->irq, dev->mem_start, + (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); + + return 0; + + err_free_dev_priv: + kfree(dev->priv); + err_free_irq: + free_irq(dev->irq, dev); + return -EIO; +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +static int arcrimi_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); + + if (really_reset) { + writeb(TESTvalue, ioaddr - 0x800); /* fake reset */ + return 0; + } + ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | CONFIGclear); + + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* done! return success. */ + return 0; +} + + +static void arcrimi_openclose(struct net_device *dev, int open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +static void arcrimi_setmask(struct net_device *dev, int mask) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + AINTMASK(mask); +} + +static int arcrimi_status(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + return ASTATUS(); +} + +static void arcrimi_command(struct net_device *dev, int cmd) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + ACOMMAND(cmd); +} + +static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); +} + + +static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; + TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); +} + +#ifdef MODULE + +static struct net_device *my_dev; + +/* Module parameters */ + +static int node = 0; +static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ +static int irq = 0; /* or use the insmod io= irq= shmem= options */ +static char *device; /* use eg. device="arc1" to change name */ + +MODULE_PARM(node, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(device, "s"); + +int init_module(void) +{ + struct net_device *dev; + int err; + + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + + if (node && node != 0xff) + dev->dev_addr[0] = node; + + dev->base_addr = io; + dev->irq = irq; + if (dev->irq == 2) + dev->irq = 9; + + if (arcrimi_probe(dev)) + return -EIO; + + my_dev = dev; + return 0; +} + +void cleanup_module(void) +{ + struct net_device *dev = my_dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *ioaddr = lp->mem_start + 0x800; + + if (dev->start) + dev->stop(dev); + + /* Flush TX and disable RX */ + AINTMASK(0); /* disable IRQ's */ + ACOMMAND(NOTXcmd); /* stop transmit */ + ACOMMAND(NORXcmd); /* disable receive */ + + free_irq(dev->irq, dev); + iounmap(lp->mem_start); + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); +} + +#else + +static int __init arcrimi_setup(char *s) +{ + struct net_device *dev; + int ints[8]; + + s = get_options(s, 8, ints); + if (!ints[0]) + return 1; + dev = alloc_bootmem(sizeof(struct net_device) + 10); + memset(dev, 0, sizeof(struct net_device) + 10); + dev->name = (char *) (dev + 1); + dev->init = arcrimi_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("arcrimi: Too many arguments.\n"); + case 3: /* Node ID */ + dev->dev_addr[0] = ints[3]; + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->mem_start = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "arc-rimi: Cannot register arcnet device\n"); + + return 1; +} + +__setup("arcrimi=", arcrimi_setup); + +#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c --- v2.3.35/linux/drivers/net/arcnet/arcnet.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/arcnet.c Tue Jan 4 09:41:45 2000 @@ -0,0 +1,1052 @@ +/* + * Linux ARCnet driver - device-independent routines + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * The change log is now in a file called ChangeLog in this directory. + * + * Sources: + * - Crynwr arcnet.com/arcether.com packet drivers. + * - arcnet.c v0.00 dated 1/1/94 and apparently by + * Donald Becker - it didn't work :) + * - skeleton.c v0.05 dated 11/16/93 by Donald Becker + * (from Linux Kernel 1.1.45) + * - RFC's 1201 and 1051 - re: TCP/IP over ARCnet + * - The official ARCnet COM9026 data sheets (!) thanks to + * Ken Cornetet + * - The official ARCnet COM20020 data sheets. + * - Information on some more obscure ARCnet controller chips, thanks + * to the nice people at SMSC. + * - net/inet/eth.c (from kernel 1.1.50) for header-building info. + * - Alternate Linux ARCnet source by V.Shergin + * - Textual information and more alternate source from Joachim Koenig + * + */ + +#define VERSION "arcnet: v3.91 BETA 99/12/18 - by Avery Pennarun et al.\n" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* "do nothing" functions for protocol drivers */ +static void null_rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int null_build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, + int length, int bufnum); + + +/* + * one ArcProto per possible proto ID. None of the elements of + * arc_proto_map are allowed to be NULL; they will get set to + * arc_proto_default instead. It also must not be NULL; if you would like + * to set it to NULL, set it to &arc_proto_null instead. + */ +struct ArcProto *arc_proto_map[256], *arc_proto_default, *arc_bcast_proto; + +struct ArcProto arc_proto_null = +{ + '?', + XMTU, + null_rx, + null_build_header, + null_prepare_tx +}; + + +/* Exported function prototypes */ +int arcnet_debug = ARCNET_DEBUG; + +EXPORT_SYMBOL(arc_proto_map); +EXPORT_SYMBOL(arc_proto_default); +EXPORT_SYMBOL(arc_bcast_proto); +EXPORT_SYMBOL(arc_proto_null); +EXPORT_SYMBOL(arcnet_unregister_proto); +EXPORT_SYMBOL(arcnet_debug); +EXPORT_SYMBOL(arcdev_setup); +EXPORT_SYMBOL(arcnet_interrupt); + +/* Internal function prototypes */ +static int arcnet_open(struct net_device *dev); +static int arcnet_close(struct net_device *dev); +static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev); +static int arcnet_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len); +static int arcnet_rebuild_header(struct sk_buff *skb); +static struct net_device_stats *arcnet_get_stats(struct net_device *dev); +static int go_tx(struct net_device *dev); + +void __init arcnet_init(void) +{ + static int arcnet_inited __initdata = 0; + int count; + + if (arcnet_inited++) + return; + + printk(VERSION); + +#ifdef ALPHA_WARNING + BUGLVL(D_EXTRA) { + printk("arcnet: ***\n" + "arcnet: * Read arcnet.txt for important release notes!\n" + "arcnet: *\n" + "arcnet: * This is an ALPHA version! (Last stable release: v3.02) E-mail\n" + "arcnet: * me if you have any questions, comments, or bug reports.\n" + "arcnet: ***\n"); + } +#endif + + /* initialize the protocol map */ + arc_proto_default = arc_bcast_proto = &arc_proto_null; + for (count = 0; count < 256; count++) + arc_proto_map[count] = arc_proto_default; + + BUGLVL(D_DURING) + printk("arcnet: struct sizes: %d %d %d %d %d\n", + sizeof(struct arc_hardware), sizeof(struct arc_rfc1201), + sizeof(struct arc_rfc1051), sizeof(struct arc_eth_encap), + sizeof(struct archdr)); + +#ifdef CONFIG_ARCNET /* We're not built as a module */ + printk("arcnet: Available protocols:"); +#ifdef CONFIG_ARCNET_1201 + printk(" RFC1201"); + arcnet_rfc1201_init(); +#endif +#ifdef CONFIG_ARCNET_1051 + printk(" RFC1051"); + arcnet_rfc1051_init(); +#endif +#ifdef CONFIG_ARCNET_RAW + printk(" RAW"); + arcnet_raw_init(); +#endif + printk("\n"); +#ifdef CONFIG_ARCNET_COM90xx + com90xx_probe(NULL); +#endif +#ifdef CONFIG_ARCNET_COM20020_PCI + com20020pci_probe_all(); +#endif +#endif +} + + +#ifdef MODULE + +static int debug = ARCNET_DEBUG; +MODULE_PARM(debug, "i"); + +int __init init_module(void) +{ + arcnet_debug = debug; + arcnet_init(); + return 0; +} + +void cleanup_module(void) +{ +} + +#endif + + +/* + * Dump the contents of an sk_buff + */ +#if ARCNET_DEBUG_MAX & D_SKB +void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) +{ + int i; + long flags; + + save_flags(flags); + cli(); + printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc); + for (i = 0; i < skb->len; i++) { + if (i % 16 == 0) + printk("\n" KERN_DEBUG "[%04X] ", i); + printk("%02X ", ((u_char *) skb->data)[i]); + } + printk("\n"); + restore_flags(flags); +} + +EXPORT_SYMBOL(arcnet_dump_skb); +#endif + + +/* + * Dump the contents of an ARCnet buffer + */ +#if (ARCNET_DEBUG_MAX & (D_RX | D_TX)) +void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int i, length; + long flags; + static uint8_t buf[512]; + + save_flags(flags); + cli(); + + lp->hw.copy_from_card(dev, bufnum, 0, buf, 512); + + /* if the offset[0] byte is nonzero, this is a 256-byte packet */ + length = (buf[2] ? 256 : 512); + + printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc); + for (i = 0; i < length; i++) { + if (i % 16 == 0) + printk("\n" KERN_DEBUG "[%04X] ", i); + printk("%02X ", buf[i]); + } + printk("\n"); + + restore_flags(flags); +} + +EXPORT_SYMBOL(arcnet_dump_packet); +#endif + + +/* + * Unregister a protocol driver from the arc_proto_map. Protocol drivers + * are responsible for registering themselves, but the unregister routine + * is pretty generic so we'll do it here. + */ +void arcnet_unregister_proto(struct ArcProto *proto) +{ + int count; + + if (arc_proto_default == proto) + arc_proto_default = &arc_proto_null; + if (arc_bcast_proto == proto) + arc_bcast_proto = arc_proto_default; + + for (count = 0; count < 256; count++) { + if (arc_proto_map[count] == proto) + arc_proto_map[count] = arc_proto_default; + } +} + + +/* + * Add a buffer to the queue. Only the interrupt handler is allowed to do + * this, unless interrupts are disabled. + * + * Note: we don't check for a full queue, since there aren't enough buffers + * to more than fill it. + */ +static void release_arcbuf(struct net_device *dev, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int i; + + lp->buf_queue[lp->first_free_buf++] = bufnum; + lp->first_free_buf %= 5; + + BUGLVL(D_DURING) { + BUGMSG(D_DURING, "release_arcbuf: freed #%d; buffer queue is now: ", + bufnum); + for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5) + BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); + BUGMSG2(D_DURING, "\n"); + } +} + + +/* + * Get a buffer from the queue. If this returns -1, there are no buffers + * available. + */ +static int get_arcbuf(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int buf = -1, i; + + if (!atomic_dec_and_test(&lp->buf_lock)) /* already in this function */ + BUGMSG(D_NORMAL, "get_arcbuf: overlap (%d)!\n", lp->buf_lock.counter); + else { /* we can continue */ + if (lp->next_buf >= 5) + lp->next_buf -= 5; + + if (lp->next_buf == lp->first_free_buf) + BUGMSG(D_NORMAL, "get_arcbuf: BUG: no buffers are available??\n"); + else { + buf = lp->buf_queue[lp->next_buf++]; + lp->next_buf %= 5; + } + } + + + BUGLVL(D_DURING) { + BUGMSG(D_DURING, "get_arcbuf: got #%d; buffer queue is now: ", buf); + for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5) + BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]); + BUGMSG2(D_DURING, "\n"); + } + + atomic_inc(&lp->buf_lock); + return buf; +} + + +static int choose_mtu(void) +{ + int count, mtu = 65535; + + /* choose the smallest MTU of all available encaps */ + for (count = 0; count < 256; count++) { + if (arc_proto_map[count] != &arc_proto_null + && arc_proto_map[count]->mtu < mtu) { + mtu = arc_proto_map[count]->mtu; + } + } + + return mtu == 65535 ? XMTU : mtu; +} + + +/* Setup a struct device for ARCnet. */ +void arcdev_setup(struct net_device *dev) +{ + dev->type = ARPHRD_ARCNET; + dev->hard_header_len = sizeof(struct archdr); + dev->mtu = choose_mtu(); + + dev->addr_len = 1; + dev->tx_queue_len = 30; + dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ + + /* New-style flags. */ + dev->flags = IFF_BROADCAST; + + /* + * Put in this stuff here, so we don't have to export the symbols to + * the chipset drivers. + */ + dev->open = arcnet_open; + dev->stop = arcnet_close; + dev->hard_start_xmit = arcnet_send_packet; + dev->get_stats = arcnet_get_stats; + dev->hard_header = arcnet_header; + dev->rebuild_header = arcnet_rebuild_header; + + dev_init_buffers(dev); +} + + +/* + * Open/initialize the board. This is called sometime after booting when + * the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even registers + * that "should" only need to be set once at boot, so that there is + * non-reboot way to recover if something goes wrong. + */ +static int arcnet_open(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int count, newmtu; + + BUGLVL(D_PROTO) { + int count; + BUGMSG(D_PROTO, "protocol map (default is '%c'): ", + arc_proto_default->suffix); + for (count = 0; count < 256; count++) + BUGMSG2(D_PROTO, "%c", arc_proto_map[count]->suffix); + BUGMSG2(D_PROTO, "\n"); + } + + + BUGMSG(D_INIT, "arcnet_open: resetting card.\n"); + + /* try to put the card in a defined state - if it fails the first + * time, actually reset it. + */ + if (ARCRESET(0) && ARCRESET(1)) + return -ENODEV; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 0; + + newmtu = choose_mtu(); + if (newmtu < dev->mtu) + dev->mtu = newmtu; + + /* autodetect the encapsulation for each host. */ + memset(lp->default_proto, 0, sizeof(lp->default_proto)); + + /* the broadcast address is special - use the 'bcast' protocol */ + for (count = 0; count < 256; count++) { + if (arc_proto_map[count] == arc_bcast_proto) { + lp->default_proto[0] = count; + break; + } + } + + /* initialize buffers */ + atomic_set(&lp->buf_lock, 1); + lp->next_buf = lp->first_free_buf = 0; + release_arcbuf(dev, 0); + release_arcbuf(dev, 1); + release_arcbuf(dev, 2); + release_arcbuf(dev, 3); + lp->cur_tx = lp->next_tx = -1; + lp->cur_rx = -1; + + lp->rfc1201.sequence = 1; + + /* bring up the hardware driver */ + ARCOPEN(1); + + if (dev->dev_addr[0] == 0) + BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " + "for broadcasts!\n"); + else if (dev->dev_addr[0] == 255) + BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse " + "DOS networking programs!\n"); + + if (ASTATUS() & RESETflag) + ACOMMAND(CFLAGScmd | RESETclear); + + /* we're started */ + dev->start = 1; + + /* make sure we're ready to receive IRQ's. */ + AINTMASK(0); + udelay(1); /* give it time to set the mask before + * we reset it again. (may not even be + * necessary) + */ + lp->intmask = NORXflag | RECONflag; + AINTMASK(lp->intmask); + + return 0; +} + + +/* The inverse routine to arcnet_open - shuts down the card. */ +static int arcnet_close(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + + /* flush TX and disable RX */ + AINTMASK(0); + ACOMMAND(NOTXcmd); /* stop transmit */ + ACOMMAND(NORXcmd); /* disable receive */ + mdelay(1); + + dev->tbusy = 1; + dev->start = 0; + dev->interrupt = 0; + + /* shut down the card */ + ARCOPEN(0); + + return 0; +} + + +static int arcnet_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + uint8_t _daddr, proto_num; + struct ArcProto *proto; + + BUGMSG(D_DURING, + "create header from %d to %d; protocol %d (%Xh); size %u.\n", + saddr ? *(uint8_t *) saddr : -1, + daddr ? *(uint8_t *) daddr : -1, + type, type, len); + + if (len != skb->len) + BUGMSG(D_NORMAL, "arcnet_header: Yikes! skb->len(%d) != len(%d)!\n", + skb->len, len); + + /* + * if the dest addr isn't provided, we can't choose an encapsulation! + * Store the packet type (eg. ETH_P_IP) for now, and we'll push on a + * real header when we do rebuild_header. + */ + if (!daddr) { + *(uint16_t *) skb_push(skb, 2) = type; + if (skb->nh.raw - skb->mac.raw != 2) + BUGMSG(D_NORMAL, "arcnet_header: Yikes! diff (%d) is not 2!\n", + skb->nh.raw - skb->mac.raw); + return -2; /* return error -- can't transmit yet! */ + } + /* otherwise, we can just add the header as usual. */ + _daddr = *(uint8_t *) daddr; + proto_num = lp->default_proto[_daddr]; + proto = arc_proto_map[proto_num]; + BUGMSG(D_DURING, "building header for %02Xh using protocol '%c'\n", + proto_num, proto->suffix); + if (proto == &arc_proto_null && arc_bcast_proto != proto) { + BUGMSG(D_DURING, "actually, let's use '%c' instead.\n", + arc_bcast_proto->suffix); + proto = arc_bcast_proto; + } + return proto->build_header(skb, type, _daddr); +} + + +/* + * Rebuild the ARCnet hard header. This is called after an ARP (or in the + * future other address resolution) has completed on this sk_buff. We now + * let ARP fill in the destination field. + */ +static int arcnet_rebuild_header(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int status = 0; /* default is failure */ + unsigned short type; + uint8_t daddr; + + if (skb->nh.raw - skb->mac.raw != 2) { + BUGMSG(D_NORMAL, + "rebuild_header: shouldn't be here! (hdrsize=%d)\n", + skb->nh.raw - skb->mac.raw); + return 0; + } + type = *(uint16_t *) skb_pull(skb, 2); + + if (type == ETH_P_IP) { +#ifdef CONFIG_INET + BUGMSG(D_DURING, "rebuild header for ethernet protocol %Xh\n", type); + status = arp_find(&daddr, skb) ? 1 : 0; + BUGMSG(D_DURING, " rebuilt: dest is %d; protocol %Xh\n", + daddr, type); +#endif + } else { + BUGMSG(D_NORMAL, + "I don't understand ethernet protocol %Xh addresses!\n", type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + } + + /* if we couldn't resolve the address... give up. */ + if (!status) + return 0; + + /* add the _real_ header this time! */ + arc_proto_map[lp->default_proto[daddr]]->build_header(skb, type, daddr); + + return 1; /* success */ +} + + + +/* Called by the kernel in order to transmit a packet. */ +static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct archdr *pkt; + struct arc_rfc1201 *soft; + struct ArcProto *proto; + int txbuf; + + BUGMSG(D_DURING, + "transmit requested (status=%Xh, txbufs=%d/%d, len=%d)\n", + ASTATUS(), lp->cur_tx, lp->next_tx, skb->len); + + if (dev->tbusy) { + /* + * If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + unsigned long flags; + int tickssofar = jiffies - dev->trans_start, status = ASTATUS(); + + if (tickssofar < TX_TIMEOUT) { + BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d)\n", + status, tickssofar); + return 1; /* means "try again" */ + } + save_flags(flags); + cli(); + + if (status & TXFREEflag) { /* transmit _DID_ finish */ + BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", + status, tickssofar, lp->intmask, lp->lasttrans_dest); + lp->stats.tx_errors++; + } else { + BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", + status, tickssofar, lp->intmask, lp->lasttrans_dest); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + + ACOMMAND(NOTXcmd | (lp->cur_tx << 3)); + } + + /* + * interrupt handler will set dev->tbusy = 0 when it notices the + * transmit has been canceled. + */ + + /* make sure we didn't miss a TX IRQ */ + AINTMASK(0); + lp->intmask |= TXFREEflag; + AINTMASK(lp->intmask); + + restore_flags(flags); + return 1; + } + pkt = (struct archdr *) skb->data; + soft = &pkt->soft.rfc1201; + proto = arc_proto_map[soft->proto]; + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx"); + + /* fits in one packet? */ + if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) { + BUGMSG(D_NORMAL, "fixme: packet too large: compensating badly!\n"); + dev_kfree_skb(skb); + return 0; /* don't try again */ + } + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + if (test_and_set_bit(0, (int *) &dev->tbusy)) { + BUGMSG(D_NORMAL, "transmitter called with busy bit set! " + "(status=%Xh, tickssofar=%ld)\n", + ASTATUS(), jiffies - dev->trans_start); + lp->stats.tx_errors++; + lp->stats.tx_fifo_errors++; + return 0; /* don't try again */ + } + AINTMASK(0); + + txbuf = get_arcbuf(dev); + if (txbuf != -1) { + if (proto->prepare_tx(dev, pkt, skb->len, txbuf)) { + /* done right away */ + lp->stats.tx_bytes += skb->len; + dev_kfree_skb(skb); + } else { + /* do it the 'split' way */ + lp->outgoing.proto = proto; + lp->outgoing.skb = skb; + lp->outgoing.pkt = pkt; + + if (!proto->continue_tx) + BUGMSG(D_NORMAL, "bug! prep_tx==0, but no continue_tx!\n"); + else if (proto->continue_tx(dev, txbuf)) { + BUGMSG(D_NORMAL, + "bug! continue_tx finished the first time! " + "(proto='%c')\n", proto->suffix); + } + } + + lp->next_tx = txbuf; + } else + dev_kfree_skb(skb); + + /* make sure we didn't ignore a TX IRQ while we were in here */ + AINTMASK(0); + lp->intmask |= TXFREEflag; + AINTMASK(lp->intmask); + + return 0; /* no need to try again */ +} + + +/* + * Actually start transmitting a packet that was loaded into a buffer + * by prepare_tx. This should _only_ be called by the interrupt handler. + */ +static int go_tx(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + + BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n", + ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx); + + if (lp->cur_tx != -1 || lp->next_tx == -1) + return 0; + + BUGLVL(D_TX) arcnet_dump_packet(dev, lp->next_tx, "go_tx"); + + lp->cur_tx = lp->next_tx; + lp->next_tx = -1; + + /* start sending */ + ACOMMAND(TXcmd | (lp->cur_tx << 3)); + + dev->trans_start = jiffies; + lp->stats.tx_packets++; + lp->lasttrans_dest = lp->lastload_dest; + lp->lastload_dest = 0; + lp->intmask |= TXFREEflag; + + return 1; +} + + +/* + * The typical workload of the driver: Handle the network interface + * interrupts. Establish which device needs attention, and call the correct + * chipset interrupt handler. + */ +void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct arcnet_local *lp; + int recbuf, status, didsomething, boguscount; + + BUGMSG(D_DURING, "\n"); + + if (dev == NULL) { + BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq); + return; + } + BUGMSG(D_DURING, "in arcnet_interrupt\n"); + + lp = (struct arcnet_local *) dev->priv; + if (!lp) { + BUGMSG(D_DURING, "arcnet: irq ignored due to missing lp.\n"); + return; + } + /* + * RESET flag was enabled - if !dev->start, we must clear it right + * away (but nothing else). + */ + if (!dev->start) { + if (ASTATUS() & RESETflag) + ACOMMAND(CFLAGScmd | RESETclear); + AINTMASK(0); + return; + } + if (dev->interrupt) { + BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n"); + return; /* don't even try. */ + } + dev->interrupt = 1; + + BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", + ASTATUS(), lp->intmask); + + boguscount = 3; + do { + status = ASTATUS(); + didsomething = 0; + + /* + * RESET flag was enabled - card is resetting and if RX is + * disabled, it's NOT because we just got a packet. + * + * The card is in an undefined state. Clear it out and start over. + */ + if (status & RESETflag) { + BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n", status); + arcnet_close(dev); + arcnet_open(dev); + + /* get out of the interrupt handler! */ + break; + } + /* + * RX is inhibited - we must have received something. Prepare to + * receive into the next buffer. + * + * We don't actually copy the received packet from the card until + * after the transmit handler runs (and possibly launches the next + * tx); this should improve latency slightly if we get both types + * of interrupts at once. + */ + recbuf = -1; + if (status & lp->intmask & NORXflag) { + recbuf = lp->cur_rx; + BUGMSG(D_DURING, "Buffer #%d: receive irq (status=%Xh)\n", + recbuf, status); + + lp->cur_rx = get_arcbuf(dev); + if (lp->cur_rx != -1) { + BUGMSG(D_DURING, "enabling receive to buffer #%d\n", + lp->cur_rx); + ACOMMAND(RXcmd | (lp->cur_rx << 3) | RXbcasts); + } + didsomething++; + } + /* a transmit finished, and we're interested in it. */ + if (status & lp->intmask & TXFREEflag) { + lp->intmask &= ~TXFREEflag; + + BUGMSG(D_DURING, "TX IRQ (stat=%Xh)\n", status); + + if (lp->cur_tx != -1 && !(status & TXACKflag)) { + if (lp->lasttrans_dest != 0) { + BUGMSG(D_EXTRA, "transmit was not acknowledged! " + "(status=%Xh, dest=%02Xh)\n", + status, lp->lasttrans_dest); + lp->stats.tx_errors++; + lp->stats.tx_carrier_errors++; + } else { + BUGMSG(D_DURING, + "broadcast was not acknowledged; that's normal " + "(status=%Xh, dest=%02Xh)\n", + status, lp->lasttrans_dest); + } + } + if (lp->cur_tx != -1) + release_arcbuf(dev, lp->cur_tx); + + lp->cur_tx = -1; + didsomething++; + + /* send another packet if there is one */ + go_tx(dev); + + /* continue a split packet, if any */ + if (lp->outgoing.proto && lp->outgoing.proto->continue_tx) { + int txbuf = get_arcbuf(dev); + if (txbuf != -1) { + if (lp->outgoing.proto->continue_tx(dev, txbuf)) { + /* that was the last segment */ + lp->stats.tx_bytes += lp->outgoing.skb->len; + dev_kfree_skb(lp->outgoing.skb); + lp->outgoing.proto = NULL; + } + lp->next_tx = txbuf; + } + } + /* inform upper layers of idleness, if necessary */ + if (lp->cur_tx == -1) { + dev->tbusy = 0; + mark_bh(NET_BH); + } + } + /* now process the received packet, if any */ + if (recbuf != -1) { + BUGLVL(D_RX) arcnet_dump_packet(dev, recbuf, "rx irq"); + + arcnet_rx(dev, recbuf); + release_arcbuf(dev, recbuf); + + didsomething++; + } + if (status & lp->intmask & RECONflag) { + ACOMMAND(CFLAGScmd | CONFIGclear); + lp->stats.tx_carrier_errors++; + + BUGMSG(D_RECON, "Network reconfiguration detected (status=%Xh)\n", + status); + + /* is the RECON info empty or old? */ + if (!lp->first_recon || !lp->last_recon || + jiffies - lp->last_recon > HZ * 10) { + if (lp->network_down) + BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n"); + lp->first_recon = lp->last_recon = jiffies; + lp->num_recons = lp->network_down = 0; + + BUGMSG(D_DURING, "recon: clearing counters.\n"); + } else { /* add to current RECON counter */ + lp->last_recon = jiffies; + lp->num_recons++; + + BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n", + lp->num_recons, + (lp->last_recon - lp->first_recon) / HZ, + lp->network_down); + + /* if network is marked up; + * and first_recon and last_recon are 60+ apart; + * and the average no. of recons counted is + * > RECON_THRESHOLD/min; + * then print a warning message. + */ + if (!lp->network_down + && (lp->last_recon - lp->first_recon) <= HZ * 60 + && lp->num_recons >= RECON_THRESHOLD) { + lp->network_down = 1; + BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n"); + } else if (!lp->network_down + && lp->last_recon - lp->first_recon > HZ * 60) { + /* reset counters if we've gone for over a minute. */ + lp->first_recon = lp->last_recon; + lp->num_recons = 1; + } + } + } else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) { + if (lp->network_down) + BUGMSG(D_NORMAL, "cabling restored?\n"); + lp->first_recon = lp->last_recon = 0; + lp->num_recons = lp->network_down = 0; + + BUGMSG(D_DURING, "not recon: clearing counters anyway.\n"); + } + } + while (--boguscount && didsomething); + + BUGMSG(D_DURING, "arcnet_interrupt complete (status=%Xh, count=%d)\n", + ASTATUS(), boguscount); + BUGMSG(D_DURING, "\n"); + + + AINTMASK(0); + udelay(1); + AINTMASK(lp->intmask); + + dev->interrupt = 0; +} + + +/* + * This is a generic packet receiver that calls arcnet??_rx depending on the + * protocol ID found. + */ +void arcnet_rx(struct net_device *dev, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct archdr pkt; + struct arc_rfc1201 *soft; + int length, ofs; + + soft = &pkt.soft.rfc1201; + + lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE)); + if (pkt.hard.offset[0]) { + ofs = pkt.hard.offset[0]; + length = 256 - ofs; + } else { + ofs = pkt.hard.offset[1]; + length = 512 - ofs; + } + + /* get the full header, if possible */ + if (sizeof(pkt.soft) < length) + lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft)); + else { + memset(&pkt.soft, 0, sizeof(pkt.soft)); + lp->hw.copy_from_card(dev, bufnum, ofs, soft, length); + } + + BUGMSG(D_DURING, "Buffer #%d: received packet from %02Xh to %02Xh " + "(%d+4 bytes)\n", + bufnum, pkt.hard.source, pkt.hard.dest, length); + + lp->stats.rx_packets++; + lp->stats.rx_bytes += length + ARC_HDR_SIZE; + + /* call the right receiver for the protocol */ + if (arc_proto_map[soft->proto] != &arc_proto_null) { + BUGLVL(D_PROTO) { + struct ArcProto + *oldp = arc_proto_map[lp->default_proto[pkt.hard.source]], + *newp = arc_proto_map[soft->proto]; + + if (oldp != newp) { + BUGMSG(D_PROTO, + "got protocol %02Xh; encap for host %02Xh is now '%c'" + " (was '%c')\n", soft->proto, pkt.hard.source, + newp->suffix, oldp->suffix); + } + } + + /* broadcasts will always be done with the last-used encap. */ + lp->default_proto[0] = soft->proto; + + /* in striking contrast, the following isn't a hack. */ + lp->default_proto[pkt.hard.source] = soft->proto; + } + /* call the protocol-specific receiver. */ + arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length); + + /* + * If any worthwhile packets have been received, a mark_bh(NET_BH) has + * been done by netif_rx and Linux will handle them after we return. + */ +} + + + +/* + * Get the current statistics. This may be called with the card open or + * closed. + */ +static struct net_device_stats *arcnet_get_stats(struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + return &lp->stats; +} + + +static void null_rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + BUGMSG(D_PROTO, + "rx: don't know how to deal with proto %02Xh from host %02Xh.\n", + pkthdr->soft.rfc1201.proto, pkthdr->hard.source); +} + + +static int null_build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + + BUGMSG(D_PROTO, + "tx: can't build header for encap %02Xh; load a protocol driver.\n", + lp->default_proto[daddr]); + + /* always fails */ + return 0; +} + + +/* the "do nothing" prepare_tx function warns that there's nothing to do. */ +static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, + int length, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arc_hardware newpkt; + + BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n"); + + /* send a packet to myself -- will never get received, of course */ + newpkt.source = newpkt.dest = dev->dev_addr[0]; + + /* only one byte of actual data (and it's random) */ + newpkt.offset[0] = 0xFF; + + lp->hw.copy_to_card(dev, bufnum, 0, &newpkt, ARC_HDR_SIZE); + + return 1; /* done */ +} diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/com20020-isa.c linux/drivers/net/arcnet/com20020-isa.c --- v2.3.35/linux/drivers/net/arcnet/com20020-isa.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/com20020-isa.c Sun Jan 2 00:46:32 2000 @@ -0,0 +1,234 @@ +/* + * Linux ARCnet driver - COM20020 chipset support + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define VERSION "arcnet: COM20020 ISA support (by David Woodhouse et al.)\n" + + +/* + * We cannot (yet) probe for an IO mapped card, although we can check that + * it's where we were told it was, and even do autoirq. + */ +static int __init com20020isa_probe(struct net_device *dev) +{ + int ioaddr; + unsigned long airqmask; + +#ifndef MODULE + arcnet_init(); +#endif + + BUGLVL(D_NORMAL) printk(VERSION); + + ioaddr = dev->base_addr; + if (!ioaddr) { + BUGMSG(D_NORMAL, "No autoprobe (yet) for IO mapped cards; you " + "must specify the base address!\n"); + return -ENODEV; + } + if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { + BUGMSG(D_NORMAL, "IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + return -ENXIO; + } + if (ASTATUS() == 0xFF) { + BUGMSG(D_NORMAL, "IO address %x empty\n", ioaddr); + return -ENODEV; + } + if (com20020_check(dev)) + return -ENODEV; + + if (!dev->irq) { + /* if we do this, we're sure to get an IRQ since the + * card has just reset and the NORXflag is on until + * we tell it to start receiving. + */ + BUGMSG(D_INIT_REASONS, "intmask was %02Xh\n", inb(_INTMASK)); + outb(0, _INTMASK); + airqmask = probe_irq_on(); + outb(NORXflag, _INTMASK); + udelay(1); + outb(0, _INTMASK); + dev->irq = probe_irq_off(airqmask); + + if (dev->irq <= 0) { + BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed first time\n"); + airqmask = probe_irq_on(); + outb(NORXflag, _INTMASK); + udelay(5); + outb(0, _INTMASK); + dev->irq = probe_irq_off(airqmask); + if (dev->irq <= 0) { + BUGMSG(D_NORMAL, "Autoprobe IRQ failed.\n"); + return -ENODEV; + } + } + } + return com20020_found(dev, 0); +} + + +#ifdef MODULE + +static struct net_device *my_dev; + +/* Module parameters */ + +static int node = 0; +static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ +static int irq = 0; /* or use the insmod io= irq= shmem= options */ +static char *device; /* use eg. device="arc1" to change name */ +static int timeout = 3; +static int backplane = 0; +static int clock = 0; + +MODULE_PARM(node, "i"); +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(device, "s"); +MODULE_PARM(timeout, "i"); +MODULE_PARM(backplane, "i"); +MODULE_PARM(clock, "i"); + +static void com20020isa_open_close(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +int init_module(void) +{ + struct net_device *dev; + struct arcnet_local *lp; + int err; + + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) + return -ENOMEM; + memset(lp, 0, sizeof(struct arcnet_local)); + + if (node && node != 0xff) + dev->dev_addr[0] = node; + + lp->backplane = backplane; + lp->clock = clock & 7; + lp->timeout = timeout & 3; + lp->hw.open_close_ll = com20020isa_open_close; + + dev->base_addr = io; + dev->irq = irq; + + if (dev->irq == 2) + dev->irq = 9; + + if (com20020isa_probe(dev)) + return -EIO; + + my_dev = dev; + return 0; +} + +void cleanup_module(void) +{ + struct net_device *dev = my_dev; + + if (dev->start) + dev->stop(dev); + + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); +} + +#else + +static int __init com20020isa_setup(char *s) +{ + struct net_device *dev; + struct arcnet_local *lp; + int ints[8]; + + s = get_options(s, 8, ints); + if (!ints[0]) + return 1; + dev = alloc_bootmem(sizeof(struct net_device) + sizeof(struct arcnet_local) + 10); + memset(dev, 0, sizeof(struct net_device) + sizeof(struct arcnet_local) + 10); + lp = dev->priv = (struct arcnet_local *) (dev + 1); + dev->name = (char *) (lp + 1); + dev->init = com20020isa_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("com90xx: Too many arguments.\n"); + case 6: /* Timeout */ + lp->timeout = ints[6]; + case 5: /* CKP value */ + lp->clock = ints[5]; + case 4: /* Backplane flag */ + lp->backplane = ints[4]; + case 3: /* Node ID */ + dev->dev_addr[0] = ints[3]; + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->base_addr = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "com20020: Cannot register arcnet device\n"); + + return 1; +} + +__setup("com20020=", com20020isa_setup); + +#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c --- v2.3.35/linux/drivers/net/arcnet/com20020-pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/com20020-pci.c Sun Jan 2 00:46:32 2000 @@ -0,0 +1,170 @@ +/* + * Linux ARCnet driver - COM20020 PCI support (Contemporary Controls PCI20) + * + * Written 1994-1999 by Avery Pennarun, + * based on an ISA version by David Woodhouse. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define VERSION "arcnet: COM20020 PCI support\n" + +#ifdef MODULE +#define MAX_CARDS 16 +static struct net_device *cards[MAX_CARDS]; +static int numcards; +#endif + +static void com20020pci_open_close(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +/* + * No need to probe for PCI cards - just ask the PCI layer and launch all the + * ones we find. + */ +static int __init com20020pci_probe(char *name_template, int node, int backplane, int clock, int timeout) +{ + struct net_device *dev; + struct arcnet_local *lp; + struct pci_dev *pdev = NULL; + int ioaddr, gotone = 0, err; + + BUGLVL(D_NORMAL) printk(VERSION); + + while ((pdev = pci_find_device(0x1571, 0xa004, pdev))) { + if (pci_enable_device(pdev)) + continue; + dev = dev_alloc(name_template ? : "arc%d", &err); + if (!dev) + return err; + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) + return -ENOMEM; + memset(lp, 0, sizeof(struct arcnet_local)); + + ioaddr = pdev->resource[2].start; + dev->base_addr = ioaddr; + dev->irq = pdev->irq; + dev->dev_addr[0] = node; + lp->backplane = backplane; + lp->clock = clock; + lp->timeout = timeout; + lp->hw.open_close_ll = com20020pci_open_close; + + BUGMSG(D_INIT, "PCI BIOS reports a device at %Xh, IRQ %d\n", + ioaddr, dev->irq); + + if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { + BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + continue; + } + if (ASTATUS() == 0xFF) { + BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " + "but seems empty!\n", ioaddr); + continue; + } + if (com20020_check(dev)) + continue; + + if (!com20020_found(dev, SA_SHIRQ)) { +#ifdef MODULE + if(numcards==MAX_CARDS) + printk(KERN_WARNING "com20020pci: Too many cards. Ignoring.\n"); + else + cards[numcards++] = dev; +#endif + gotone++; + } + } + + return gotone ? 0 : -ENODEV; +} + + +#ifdef MODULE + +/* Module parameters */ + +static int node = 0; +static char *device; /* use eg. device="arc1" to change name */ +static int timeout = 3; +static int backplane = 0; +static int clock = 0; + +MODULE_PARM(node, "i"); +MODULE_PARM(device, "s"); +MODULE_PARM(timeout, "i"); +MODULE_PARM(backplane, "i"); +MODULE_PARM(clock, "i"); + +int init_module(void) +{ + return com20020pci_probe(device, node, backplane, clock & 7, timeout & 3); +} + +void cleanup_module(void) +{ + struct net_device *dev; + int count; + + for (count = 0; count < numcards; count++) { + dev = cards[count]; + + if (dev->start) + dev->stop(dev); + + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); + } +} + +#else + +void __init com20020pci_probe_all(void) +{ + com20020pci_probe(NULL, 0, 0, 0, 3); +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/com20020.c linux/drivers/net/arcnet/com20020.c --- v2.3.35/linux/drivers/net/arcnet/com20020.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/com20020.c Sun Jan 2 00:46:32 2000 @@ -0,0 +1,352 @@ +/* + * Linux ARCnet driver - COM20020 chipset support + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VERSION "arcnet: COM20020 chipset support (by David Woodhouse et al.)\n" + +static char *clockrates[] = +{"2.5 Mb/s", "1.25Mb/s", "625 Kb/s", "312.5 Kb/s", + "156.25 Kb/s", "Reserved", "Reserved", + "Reserved"}; + +static void com20020_command(struct net_device *dev, int command); +static int com20020_status(struct net_device *dev); +static void com20020_setmask(struct net_device *dev, int mask); +static int com20020_reset(struct net_device *dev, int really_reset); +static void com20020_openclose(struct net_device *dev, bool open); +static void com20020_copy_to_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count); +static void com20020_copy_from_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count); +static void com20020_set_mc_list(struct net_device *dev); + + +static void com20020_copy_from_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count) +{ + int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset; + + /* set up the address register */ + outb((ofs >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); + outb(ofs & 0xff, _ADDR_LO); + + /* copy the data */ + TIME("insb", count, insb(_MEMDATA, buf, count)); +} + + +static void com20020_copy_to_card(struct net_device *dev, int bufnum, + int offset, void *buf, int count) +{ + int ioaddr = dev->base_addr, ofs = 512 * bufnum + offset; + + /* set up the address register */ + outb((ofs >> 8) | AUTOINCflag, _ADDR_HI); + outb(ofs & 0xff, _ADDR_LO); + + /* copy the data */ + TIME("outsb", count, outsb(_MEMDATA, buf, count)); +} + + +/* Reset the card and check some basic stuff during the detection stage. */ +int __init com20020_check(struct net_device *dev) +{ + int ioaddr = dev->base_addr, status; + struct arcnet_local *lp = dev->priv; + + ARCRESET0; + mdelay(RESETtime); + + lp->setup = lp->clock << 1; + + REGSETUP; + SETCONF(lp->config); + outb(lp->setup, ioaddr + 7); + + lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2); + /* set node ID to 0x42 (but transmitter is disabled, so it's okay) */ + SETCONF(lp->config); + outb(0x42, ioaddr + 7); + + status = ASTATUS(); + + if ((status & 0x99) != (NORXflag | TXFREEflag | RESETflag)) { + BUGMSG(D_NORMAL, "status invalid (%Xh).\n", status); + return -ENODEV; + } + BUGMSG(D_INIT_REASONS, "status after reset: %X\n", status); + + /* Enable TX */ + outb(0x39, _CONFIG); + outb(inb(ioaddr + 8), ioaddr + 7); + + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + + status = ASTATUS(); + BUGMSG(D_INIT_REASONS, "status after reset acknowledged: %X\n", + status); + + /* Read first location of memory */ + outb(0 | RDDATAflag | AUTOINCflag, _ADDR_HI); + outb(0, _ADDR_LO); + + if ((status = inb(_MEMDATA)) != TESTvalue) { + BUGMSG(D_NORMAL, "Signature byte not found (%02Xh != D1h).\n", + status); + return -ENODEV; + } + return 0; +} + +/* Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +int __init com20020_found(struct net_device *dev, int shared) +{ + struct arcnet_local *lp; + int ioaddr = dev->base_addr; + + /* Initialize the rest of the device structure. */ + + lp = (struct arcnet_local *) dev->priv; + + lp->hw.command = com20020_command; + lp->hw.status = com20020_status; + lp->hw.intmask = com20020_setmask; + lp->hw.reset = com20020_reset; + lp->hw.open_close = com20020_openclose; + lp->hw.copy_to_card = com20020_copy_to_card; + lp->hw.copy_from_card = com20020_copy_from_card; + + dev->set_multicast_list = com20020_set_mc_list; + + /* Fill in the fields of the device structure with generic + * values. + */ + arcdev_setup(dev); + + if (!dev->dev_addr[0]) + dev->dev_addr[0] = inb(ioaddr + 8); /* FIXME: do this some other way! */ + + lp->setup = lp->clock << 1; + + REGSETUP; + SETCONF(lp->config); + outb(lp->setup, ioaddr + 7); + + lp->config = 0x20 | (lp->timeout << 3) | (lp->backplane << 2) | 1; + /* Default 0x38 + register: Node ID */ + SETCONF(lp->config); + outb(dev->dev_addr[0], ioaddr + 7); + + /* reserve the irq */ + if (request_irq(dev->irq, &arcnet_interrupt, shared, + "arcnet (COM20020)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); + return -ENODEV; + } + /* reserve the I/O region - guaranteed to work by check_region */ + request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)"); + dev->base_addr = ioaddr; + + BUGMSG(D_NORMAL, "COM20020: station %02Xh found at %03lXh, IRQ %d.\n", + dev->dev_addr[0], dev->base_addr, dev->irq); + + if (lp->backplane) + BUGMSG(D_NORMAL, "Using backplane mode.\n"); + + if (lp->timeout != 3) + BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout); + if (lp->setup) { + BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n", + lp->setup >> 1, clockrates[lp->setup >> 1]); + } + if (!dev->init && register_netdev(dev)) { + free_irq(dev->irq, dev); + release_region(ioaddr, ARCNET_TOTAL_SIZE); + return -EIO; + } + return 0; +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +static int com20020_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + short ioaddr = dev->base_addr; + u_char inbyte; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", + dev->name, ASTATUS()); + + lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2); + /* power-up defaults */ + SETCONF(lp->config); + + if (really_reset) { + /* reset the card */ + ARCRESET; + mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */ + } + /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + + /* verify that the ARCnet signature byte is present */ + + com20020_copy_from_card(dev, 0, 0, &inbyte, 1); + if (inbyte != TESTvalue) { + BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); + return 1; + } + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* done! return success. */ + return 0; +} + + +static void com20020_setmask(struct net_device *dev, int mask) +{ + short ioaddr = dev->base_addr; + AINTMASK(mask); +} + + +static void com20020_command(struct net_device *dev, int cmd) +{ + short ioaddr = dev->base_addr; + ACOMMAND(cmd); +} + + +static int com20020_status(struct net_device *dev) +{ + short ioaddr = dev->base_addr; + return ASTATUS(); +} + + +static void com20020_openclose(struct net_device *dev, bool open) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int ioaddr = dev->base_addr; + + if (open) + MOD_INC_USE_COUNT; + else { + /* disable transmitter */ + lp->config &= ~TXENcfg; + SETCONF(lp->config); + MOD_DEC_USE_COUNT; + } + lp->hw.open_close_ll(dev, open); +} + + +/* Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, and do + * best-effort filtering. + * FIXME - do multicast stuff, not just promiscuous. + */ +static void com20020_set_mc_list(struct net_device *dev) +{ + struct arcnet_local *lp = dev->priv; + int ioaddr = dev->base_addr; + + if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) { /* Enable promiscuous mode */ + if (!(lp->setup & PROMISCset)) + BUGMSG(D_NORMAL, "Setting promiscuous flag...\n"); + REGSETUP; + SETCONF(lp->config); + lp->setup |= PROMISCset; + outb(lp->setup, _SETUP); + } else + /* Disable promiscuous mode, use normal mode */ + { + if ((lp->setup & PROMISCset)) + BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n"); + REGSETUP; + SETCONF(lp->config); + lp->setup &= ~PROMISCset; + outb(lp->setup, _SETUP); + } +} + + +/* + * FIXME: put this somewhere! + * + if ((dstatus = inb(_DIAGSTAT)) & NEWNXTIDflag) + { + REGNXTID; + SETCONF(lp->config); + BUGMSG(D_EXTRA, "New NextID detected: %X\n", inb(ioaddr + 7)); + } + */ + + +#ifdef MODULE + +EXPORT_SYMBOL(com20020_check); +EXPORT_SYMBOL(com20020_found); + +int init_module(void) +{ + BUGLVL(D_NORMAL) printk(VERSION); + return 0; +} + +void cleanup_module(void) +{ +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/com90io.c linux/drivers/net/arcnet/com90io.c --- v2.3.35/linux/drivers/net/arcnet/com90io.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/com90io.c Sun Jan 2 00:46:32 2000 @@ -0,0 +1,462 @@ +/* + * Linux ARCnet driver - COM90xx chipset (IO-mapped buffers) + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VERSION "arcnet: COM90xx IO-mapped mode support (by David Woodhouse et el.)\n" + + +/* Internal function declarations */ + +static int com90io_found(struct net_device *dev); +static void com90io_command(struct net_device *dev, int command); +static int com90io_status(struct net_device *dev); +static void com90io_setmask(struct net_device *dev, int mask); +static int com90io_reset(struct net_device *dev, int really_reset); +static void com90io_openclose(struct net_device *dev, bool open); +static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); +static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); + + +/* Handy defines for ARCnet specific stuff */ + +/* The number of low I/O ports used by the card. */ +#define ARCNET_TOTAL_SIZE 16 + +/* COM 9026 controller chip --> ARCnet register addresses */ +#define _INTMASK (ioaddr+0) /* writable */ +#define _STATUS (ioaddr+0) /* readable */ +#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ +#define _RESET (ioaddr+8) /* software reset (on read) */ +#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ +#define _ADDR_HI (ioaddr+15) /* Control registers for said */ +#define _ADDR_LO (ioaddr+14) +#define _CONFIG (ioaddr+2) /* Configuration register */ + +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ASTATUS() inb(_STATUS) +#define ACOMMAND(cmd) outb((cmd),_COMMAND) +#define AINTMASK(msk) outb((msk),_INTMASK) +#define SETCONF() outb((lp->config),_CONFIG) + + +/**************************************************************************** + * * + * IO-mapped operation routines * + * * + ****************************************************************************/ + +#undef ONE_AT_A_TIME_TX +#undef ONE_AT_A_TIME_RX + +static u_char get_buffer_byte(struct net_device *dev, unsigned offset) +{ + int ioaddr = dev->base_addr; + + outb(offset >> 8, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + return inb(_MEMDATA); +} + +#ifdef ONE_AT_A_TIME_TX +static void put_buffer_byte(struct net_device *dev, unsigned offset, u_char datum) +{ + int ioaddr = dev->base_addr; + + outb(offset >> 8, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + outb(datum, _MEMDATA); +} + +#endif + + +static void get_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest) +{ + int ioaddr = dev->base_addr; + + outb((offset >> 8) | AUTOINCflag, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + while (length--) +#ifdef ONE_AT_A_TIME_RX + *(dest++) = get_buffer_byte(dev, offset++); +#else + *(dest++) = inb(_MEMDATA); +#endif +} + +static void put_whole_buffer(struct net_device *dev, unsigned offset, unsigned length, char *dest) +{ + int ioaddr = dev->base_addr; + + outb((offset >> 8) | AUTOINCflag, _ADDR_HI); + outb(offset & 0xff, _ADDR_LO); + + while (length--) +#ifdef ONE_AT_A_TIME_TX + put_buffer_byte(dev, offset++, *(dest++)); +#else + outb(*(dest++), _MEMDATA); +#endif +} + +/* + * We cannot probe for an IO mapped card either, although we can check that + * it's where we were told it was, and even autoirq + */ +static int __init com90io_probe(struct net_device *dev) +{ + int ioaddr = dev->base_addr, status; + unsigned long airqmask; + +#ifndef MODULE + arcnet_init(); +#endif + + BUGLVL(D_NORMAL) printk(VERSION); + BUGLVL(D_NORMAL) printk("E-mail me if you actually test this driver, please!\n"); + + if (!ioaddr) { + BUGMSG(D_NORMAL, "No autoprobe for IO mapped cards; you " + "must specify the base address!\n"); + return -ENODEV; + } + if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { + BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n", + ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); + return -ENXIO; + } + if (ASTATUS() == 0xFF) { + BUGMSG(D_INIT_REASONS, "IO address %x empty\n", ioaddr); + return -ENODEV; + } + inb(_RESET); + mdelay(RESETtime); + + status = ASTATUS(); + + if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { + BUGMSG(D_INIT_REASONS, "Status invalid (%Xh).\n", status); + return -ENODEV; + } + BUGMSG(D_INIT_REASONS, "Status after reset: %X\n", status); + + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + + BUGMSG(D_INIT_REASONS, "Status after reset acknowledged: %X\n", status); + + status = ASTATUS(); + + if (status & RESETflag) { + BUGMSG(D_INIT_REASONS, "Eternal reset (status=%Xh)\n", status); + return -ENODEV; + } + outb((0x16 | IOMAPflag) & ~ENABLE16flag, _CONFIG); + + /* Read first loc'n of memory */ + + outb(AUTOINCflag, _ADDR_HI); + outb(0, _ADDR_LO); + + if ((status = inb(_MEMDATA)) != 0xd1) { + BUGMSG(D_INIT_REASONS, "Signature byte not found" + " (%Xh instead).\n", status); + return -ENODEV; + } + if (!dev->irq) { + /* + * if we do this, we're sure to get an IRQ since the + * card has just reset and the NORXflag is on until + * we tell it to start receiving. + */ + + airqmask = probe_irq_on(); + outb(NORXflag, _INTMASK); + udelay(1); + outb(0, _INTMASK); + dev->irq = probe_irq_off(airqmask); + + if (dev->irq <= 0) { + BUGMSG(D_INIT_REASONS, "Autoprobe IRQ failed\n"); + return -ENODEV; + } + } + return com90io_found(dev); +} + + +/* Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +static int __init com90io_found(struct net_device *dev) +{ + struct arcnet_local *lp; + int ioaddr = dev->base_addr; + + /* Reserve the irq */ + if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); + return -ENODEV; + } + /* Reserve the I/O region - guaranteed to work by check_region */ + request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)"); + + /* Initialize the rest of the device structure. */ + dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!dev->priv) { + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + return -ENOMEM; + } + memset(dev->priv, 0, sizeof(struct arcnet_local)); + + lp = (struct arcnet_local *) (dev->priv); + lp->hw.command = com90io_command; + lp->hw.status = com90io_status; + lp->hw.intmask = com90io_setmask; + lp->hw.reset = com90io_reset; + lp->hw.open_close = com90io_openclose; + lp->hw.copy_to_card = com90io_copy_to_card; + lp->hw.copy_from_card = com90io_copy_from_card; + + /* + * Fill in the fields of the device structure with generic + * values. + */ + arcdev_setup(dev); + + lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; + SETCONF(); + + /* get and check the station ID from offset 1 in shmem */ + + dev->dev_addr[0] = get_buffer_byte(dev, 1); + + BUGMSG(D_NORMAL, "COM90IO: station %02Xh found at %03lXh, IRQ %d.\n", + dev->dev_addr[0], dev->base_addr, dev->irq); + + return 0; +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +static int com90io_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + short ioaddr = dev->base_addr; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); + + if (really_reset) { + /* reset the card */ + inb(_RESET); + mdelay(RESETtime); + } + /* Set the thing to IO-mapped, 8-bit mode */ + lp->config = (0x1C | IOMAPflag) & ~ENABLE16flag; + SETCONF(); + + ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | CONFIGclear); + + /* verify that the ARCnet signature byte is present */ + if (get_buffer_byte(dev, 0) != TESTvalue) { + BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); + return 1; + } + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* done! return success. */ + return 0; +} + + +static void com90io_command(struct net_device *dev, int cmd) +{ + short ioaddr = dev->base_addr; + + ACOMMAND(cmd); +} + + +static int com90io_status(struct net_device *dev) +{ + short ioaddr = dev->base_addr; + + return ASTATUS(); +} + + +static void com90io_setmask(struct net_device *dev, int mask) +{ + short ioaddr = dev->base_addr; + + AINTMASK(mask); +} + +static void com90io_openclose(struct net_device *dev, int open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + TIME("put_whole_buffer", count, put_whole_buffer(dev, bufnum * 512 + offset, count, buf)); +} + + +static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + TIME("get_whole_buffer", count, get_whole_buffer(dev, bufnum * 512 + offset, count, buf)); +} + + +#ifdef MODULE + +static struct net_device *my_dev; + +/* Module parameters */ + +static int io = 0x0; /* use the insmod io= irq= shmem= options */ +static int irq = 0; +static char *device; /* use eg. device=arc1 to change name */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(device, "s"); + +int init_module(void) +{ + struct net_device *dev; + int err; + + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + + dev->base_addr = io; + dev->irq = irq; + if (dev->irq == 2) + dev->irq = 9; + + if (com90io_probe(dev)) + return -EIO; + + my_dev = dev; + return 0; +} + +void cleanup_module(void) +{ + struct net_device *dev = my_dev; + int ioaddr = dev->base_addr; + + if (dev->start) + dev->stop(dev); + + /* Flush TX and disable RX */ + AINTMASK(0); /* disable IRQ's */ + ACOMMAND(NOTXcmd); /* stop transmit */ + ACOMMAND(NORXcmd); /* disable receive */ + + /* Set the thing back to MMAP mode, in case the old driver is loaded later */ + outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); + + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); +} + +#else + +static int __init com90io_setup(char *s) +{ + struct net_device *dev; + int ints[4]; + + s = get_options(s, 4, ints); + if (!ints[0]) + return 1; + dev = alloc_bootmem(sizeof(struct net_device) + 10); + memset(dev, 0, sizeof(struct net_device) + 10); + dev->name = (char *) (dev + 1); + dev->init = com90io_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("com90io: Too many arguments.\n"); + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->base_addr = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "com90io: Cannot register arcnet device\n"); + + return 1; +} + +__setup("com90io=", com90io_setup); + +#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/com90xx.c linux/drivers/net/arcnet/com90xx.c --- v2.3.35/linux/drivers/net/arcnet/com90xx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/com90xx.c Sun Jan 2 00:46:32 2000 @@ -0,0 +1,709 @@ +/* + * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers) + * + * Written 1994-1999 by Avery Pennarun. + * Written 1999 by Martin Mares . + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VERSION "arcnet: COM90xx chipset support\n" + + +/* Define this to speed up the autoprobe by assuming if only one io port and + * shmem are left in the list at Stage 5, they must correspond to each + * other. + * + * This is undefined by default because it might not always be true, and the + * extra check makes the autoprobe even more careful. Speed demons can turn + * it on - I think it should be fine if you only have one ARCnet card + * installed. + * + * If no ARCnet cards are installed, this delay never happens anyway and thus + * the option has no effect. + */ +#undef FAST_PROBE + + +/* Internal function declarations */ +static int com90xx_found(struct net_device *dev, int ioaddr, int airq, + u_long shmem); +static void com90xx_command(struct net_device *dev, int command); +static int com90xx_status(struct net_device *dev); +static void com90xx_setmask(struct net_device *dev, int mask); +static int com90xx_reset(struct net_device *dev, int really_reset); +static void com90xx_openclose(struct net_device *dev, bool open); +static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); +static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count); + +/* Known ARCnet cards */ + +static struct net_device *cards[16]; +static int numcards; + +/* Handy defines for ARCnet specific stuff */ + +/* The number of low I/O ports used by the card */ +#define ARCNET_TOTAL_SIZE 16 + +/* Amount of I/O memory used by the card */ +#define BUFFER_SIZE (512) +#define MIRROR_SIZE (BUFFER_SIZE*4) + +/* COM 9026 controller chip --> ARCnet register addresses */ +#define _INTMASK (ioaddr+0) /* writable */ +#define _STATUS (ioaddr+0) /* readable */ +#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ +#define _CONFIG (ioaddr+2) /* Configuration register */ +#define _RESET (ioaddr+8) /* software reset (on read) */ +#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ +#define _ADDR_HI (ioaddr+15) /* Control registers for said */ +#define _ADDR_LO (ioaddr+14) + +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ASTATUS() inb(_STATUS) +#define ACOMMAND(cmd) outb((cmd),_COMMAND) +#define AINTMASK(msk) outb((msk),_INTMASK) + + +static int com90xx_skip_probe __initdata = 0; + +int __init com90xx_probe(struct net_device *dev) +{ + int count, status, ioaddr, numprint, airq, retval = -ENODEV, + openparen = 0; + unsigned long airqmask; + int ports[(0x3f0 - 0x200) / 16 + 1] = + {0}; + u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = + {0}; + int numports, numshmems, *port; + u_long *shmem; + + if (!dev && com90xx_skip_probe) + return -ENODEV; + +#ifndef MODULE + arcnet_init(); +#endif + + BUGLVL(D_NORMAL) printk(VERSION); + + /* set up the arrays where we'll store the possible probe addresses */ + numports = numshmems = 0; + if (dev && dev->base_addr) + ports[numports++] = dev->base_addr; + else + for (count = 0x200; count <= 0x3f0; count += 16) + ports[numports++] = count; + if (dev && dev->mem_start) + shmems[numshmems++] = dev->mem_start; + else + for (count = 0xA0000; count <= 0xFF800; count += 2048) + shmems[numshmems++] = count; + + /* Stage 1: abandon any reserved ports, or ones with status==0xFF + * (empty), and reset any others by reading the reset port. + */ + numprint = -1; + for (port = &ports[0]; port - ports < numports; port++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S1: "); + } + BUGMSG2(D_INIT, "%Xh ", *port); + + ioaddr = *port; + + if (check_region(*port, ARCNET_TOTAL_SIZE)) { + BUGMSG2(D_INIT_REASONS, "(check_region)\n"); + BUGMSG(D_INIT_REASONS, "S1: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + if (ASTATUS() == 0xFF) { + BUGMSG2(D_INIT_REASONS, "(empty)\n"); + BUGMSG(D_INIT_REASONS, "S1: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + inb(_RESET); /* begin resetting card */ + + BUGMSG2(D_INIT_REASONS, "\n"); + BUGMSG(D_INIT_REASONS, "S1: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + } + BUGMSG2(D_INIT, "\n"); + + if (!numports) { + BUGMSG(D_NORMAL, "S1: No ARCnet cards found.\n"); + return -ENODEV; + } + /* Stage 2: we have now reset any possible ARCnet cards, so we can't + * do anything until they finish. If D_INIT, print the list of + * cards that are left. + */ + numprint = -1; + for (port = &ports[0]; port - ports < numports; port++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S2: "); + } + BUGMSG2(D_INIT, "%Xh ", *port); + } + BUGMSG2(D_INIT, "\n"); + mdelay(RESETtime); + + /* Stage 3: abandon any shmem addresses that don't have the signature + * 0xD1 byte in the right place, or are read-only. + */ + numprint = -1; + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + u_long ptr = *shmem; + + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S3: "); + } + BUGMSG2(D_INIT, "%lXh ", *shmem); + + if (check_mem_region(*shmem, BUFFER_SIZE)) { + BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n"); + BUGMSG(D_INIT_REASONS, "Stage 3: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *shmem = shmems[numshmems - 1]; + numshmems--; + shmem--; + continue; + } + if (isa_readb(ptr) != TESTvalue) { + BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n", + isa_readb(ptr), TESTvalue); + BUGMSG(D_INIT_REASONS, "S3: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *shmem = shmems[numshmems - 1]; + numshmems--; + shmem--; + continue; + } + /* By writing 0x42 to the TESTvalue location, we also make + * sure no "mirror" shmem areas show up - if they occur + * in another pass through this loop, they will be discarded + * because *cptr != TESTvalue. + */ + isa_writeb(0x42, ptr); + if (isa_readb(ptr) != 0x42) { + BUGMSG2(D_INIT_REASONS, "(read only)\n"); + BUGMSG(D_INIT_REASONS, "S3: "); + *shmem = shmems[numshmems - 1]; + numshmems--; + shmem--; + continue; + } + BUGMSG2(D_INIT_REASONS, "\n"); + BUGMSG(D_INIT_REASONS, "S3: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + } + BUGMSG2(D_INIT, "\n"); + + if (!numshmems) { + BUGMSG(D_NORMAL, "S3: No ARCnet cards found.\n"); + return -ENODEV; + } + /* Stage 4: something of a dummy, to report the shmems that are + * still possible after stage 3. + */ + numprint = -1; + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S4: "); + } + BUGMSG2(D_INIT, "%lXh ", *shmem); + } + BUGMSG2(D_INIT, "\n"); + + /* Stage 5: for any ports that have the correct status, can disable + * the RESET flag, and (if no irq is given) generate an autoirq, + * register an ARCnet device. + * + * Currently, we can only register one device per probe, so quit + * after the first one is found. + */ + numprint = -1; + for (port = &ports[0]; port - ports < numports; port++) { + numprint++; + numprint %= 8; + if (!numprint) { + BUGMSG2(D_INIT, "\n"); + BUGMSG(D_INIT, "S5: "); + } + BUGMSG2(D_INIT, "%Xh ", *port); + + ioaddr = *port; + status = ASTATUS(); + + if ((status & 0x9D) + != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { + BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); + BUGMSG(D_INIT_REASONS, "S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); + status = ASTATUS(); + if (status & RESETflag) { + BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", + status); + BUGMSG(D_INIT_REASONS, "S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + /* skip this completely if an IRQ was given, because maybe + * we're on a machine that locks during autoirq! + */ + if (!dev || !dev->irq) { + /* if we do this, we're sure to get an IRQ since the + * card has just reset and the NORXflag is on until + * we tell it to start receiving. + */ + airqmask = probe_irq_on(); + AINTMASK(NORXflag); + udelay(1); + AINTMASK(0); + airq = probe_irq_off(airqmask); + + if (airq <= 0) { + BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); + BUGMSG(D_INIT_REASONS, "S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + *port = ports[numports - 1]; + numports--; + port--; + continue; + } + } else { + airq = dev->irq; + } + + BUGMSG2(D_INIT, "(%d,", airq); + openparen = 1; + + /* Everything seems okay. But which shmem, if any, puts + * back its signature byte when the card is reset? + * + * If there are multiple cards installed, there might be + * multiple shmems still in the list. + */ +#ifdef FAST_PROBE + if (numports > 1 || numshmems > 1) { + inb(_RESET); + mdelay(RESETtime); + } else { + /* just one shmem and port, assume they match */ + isa_writeb(TESTvalue, shmems[0]); + } +#else + inb(_RESET); + mdelay(RESETtime); +#endif + + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { + u_long ptr = *shmem; + + if (isa_readb(ptr) == TESTvalue) { /* found one */ + BUGMSG2(D_INIT, "%lXh)\n", *shmem); + openparen = 0; + + /* register the card */ + retval = com90xx_found(dev, *port, airq, *shmem); + numprint = -1; + + /* remove shmem from the list */ + *shmem = shmems[numshmems - 1]; + numshmems--; + + break; /* go to the next I/O port */ + } else { + BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr)); + } + } + + if (openparen) { + BUGLVL(D_INIT) printk("no matching shmem)\n"); + BUGLVL(D_INIT_REASONS) printk("S5: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + } + *port = ports[numports - 1]; + numports--; + port--; + } + + BUGLVL(D_INIT_REASONS) printk("\n"); + + /* Now put back TESTvalue on all leftover shmems. */ + for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) + isa_writeb(TESTvalue, *shmem); + + if (retval && dev && !numcards) + BUGMSG(D_NORMAL, "S5: No ARCnet cards found.\n"); + return retval; +} + + +/* Set up the struct net_device associated with this card. Called after + * probing succeeds. + */ +static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, + u_long shmem) +{ + struct net_device *dev = dev0; + struct arcnet_local *lp; + u_long first_mirror, last_mirror; + int mirror_size, err; + + /* allocate struct net_device if we don't have one yet */ + if (!dev && !(dev = dev_alloc("arc%d", &err))) { + BUGMSG(D_NORMAL, "Can't allocate device!\n"); + return err; + } + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) { + BUGMSG(D_NORMAL, "Can't allocate device data!\n"); + goto err_free_dev; + } + /* find the real shared memory start/end points, including mirrors */ + + /* guess the actual size of one "memory mirror" - the number of + * bytes between copies of the shared memory. On most cards, it's + * 2k (or there are no mirrors at all) but on some, it's 4k. + */ + mirror_size = MIRROR_SIZE; + if (isa_readb(shmem) == TESTvalue + && isa_readb(shmem - mirror_size) != TESTvalue + && isa_readb(shmem - 2 * mirror_size) == TESTvalue) + mirror_size *= 2; + + first_mirror = last_mirror = shmem; + while (isa_readb(first_mirror) == TESTvalue) + first_mirror -= mirror_size; + first_mirror += mirror_size; + + while (isa_readb(last_mirror) == TESTvalue) + last_mirror += mirror_size; + last_mirror -= mirror_size; + + dev->mem_start = first_mirror; + dev->mem_end = last_mirror + MIRROR_SIZE - 1; + dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0; + dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1; + + /* Initialize the rest of the device structure. */ + memset(lp, 0, sizeof(struct arcnet_local)); + lp->hw.command = com90xx_command; + lp->hw.status = com90xx_status; + lp->hw.intmask = com90xx_setmask; + lp->hw.reset = com90xx_reset; + lp->hw.open_close = com90xx_openclose; + lp->hw.copy_to_card = com90xx_copy_to_card; + lp->hw.copy_from_card = com90xx_copy_from_card; + lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); + if (!lp->mem_start) { + BUGMSG(D_NORMAL, "Can't remap device memory!\n"); + goto err_free_dev_priv; + } + /* Fill in the fields of the device structure with generic values. */ + arcdev_setup(dev); + + /* get and check the station ID from offset 1 in shmem */ + dev->dev_addr[0] = readb(lp->mem_start + 1); + + /* reserve the irq */ + if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { + BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); + goto err_unmap; + } + dev->irq = airq; + + /* reserve the I/O and memory regions - guaranteed to work by check_region */ + request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)"); + request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"); + dev->base_addr = ioaddr; + + BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, " + "ShMem %lXh (%ld*%xh).\n", + dev->dev_addr[0], + dev->base_addr, dev->irq, dev->mem_start, + (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); + + if (!dev0 && register_netdev(dev)) + goto err_release; + + cards[numcards++] = dev; + return 0; + + err_release: + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + err_unmap: + iounmap(lp->mem_start); + err_free_dev_priv: + kfree(dev->priv); + err_free_dev: + if (!dev0) + kfree(dev); + return -EIO; +} + + +static void com90xx_command(struct net_device *dev, int cmd) +{ + short ioaddr = dev->base_addr; + + ACOMMAND(cmd); +} + + +static int com90xx_status(struct net_device *dev) +{ + short ioaddr = dev->base_addr; + + return ASTATUS(); +} + + +static void com90xx_setmask(struct net_device *dev, int mask) +{ + short ioaddr = dev->base_addr; + + AINTMASK(mask); +} + + +/* + * Do a hardware reset on the card, and set up necessary registers. + * + * This should be called as little as possible, because it disrupts the + * token on the network (causes a RECON) and requires a significant delay. + * + * However, it does make sure the card is in a defined state. + */ +int com90xx_reset(struct net_device *dev, int really_reset) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + short ioaddr = dev->base_addr; + + BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", + dev->name, ASTATUS()); + + if (really_reset) { + /* reset the card */ + inb(_RESET); + mdelay(RESETtime); + } + ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ + ACOMMAND(CFLAGScmd | CONFIGclear); + + /* don't do this until we verify that it doesn't hurt older cards! */ + /* outb(inb(_CONFIG) | ENABLE16flag, _CONFIG); */ + + /* verify that the ARCnet signature byte is present */ + if (readb(lp->mem_start) != TESTvalue) { + BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); + return 1; + } + /* enable extended (512-byte) packets */ + ACOMMAND(CONFIGcmd | EXTconf); + + /* clean out all the memory to make debugging make more sense :) */ + BUGLVL(D_DURING) + memset_io(lp->mem_start, 0x42, 2048); + + /* done! return success. */ + return 0; +} + + +static void com90xx_openclose(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + + +static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + bufnum * 512 + offset; + TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); +} + + +static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, + void *buf, int count) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + void *memaddr = lp->mem_start + bufnum * 512 + offset; + TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); +} + + + +#ifdef MODULE + +/* Module parameters */ + +static int io = 0x0; /* use the insmod io= irq= shmem= options */ +static int irq = 0; +static int shmem = 0; +static char *device; /* use eg. device=arc1 to change name */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(shmem, "i"); +MODULE_PARM(device, "s"); + +int init_module(void) +{ + struct net_device *dev; + int err; + + if (io || irq || shmem || device) { + dev = dev_alloc(device ? : "arc%d", &err); + if (!dev) + return err; + dev->base_addr = io; + dev->irq = irq; + if (dev->irq == 2) + dev->irq = 9; + dev->mem_start = shmem; + com90xx_probe(dev); + } else + com90xx_probe(NULL); + + if (!numcards) + return -EIO; + return 0; +} + + +void cleanup_module(void) +{ + struct net_device *dev; + struct arcnet_local *lp; + int count; + + for (count = 0; count < numcards; count++) { + dev = cards[count]; + lp = (struct arcnet_local *) dev->priv; + + if (dev->start) + dev->stop(dev); + free_irq(dev->irq, dev); + iounmap(lp->mem_start); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + unregister_netdev(dev); + kfree(dev->priv); + kfree(dev); + } +} + +#else + +static int __init com90xx_setup(char *s) +{ + struct net_device *dev; + int ints[8]; + + com90xx_skip_probe = 1; + + s = get_options(s, 8, ints); + if (!ints[0] && !*s) { + printk("com90xx: Disabled.\n"); + return 1; + } + dev = alloc_bootmem(sizeof(struct net_device) + 10); + memset(dev, 0, sizeof(struct net_device) + 10); + dev->name = (char *) (dev + 1); + dev->init = com90xx_probe; + + switch (ints[0]) { + default: /* ERROR */ + printk("com90xx: Too many arguments.\n"); + case 3: /* Mem address */ + dev->mem_start = ints[3]; + case 2: /* IRQ */ + dev->irq = ints[2]; + case 1: /* IO address */ + dev->base_addr = ints[1]; + } + if (*s) + strncpy(dev->name, s, 9); + else + strcpy(dev->name, "arc%d"); + if (register_netdev(dev)) + printk(KERN_ERR "com90xx: Cannot register arcnet device\n"); + + return 1; +} + +__setup("com90xx=", com90xx_setup); + +#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/rfc1051.c linux/drivers/net/arcnet/rfc1051.c --- v2.3.35/linux/drivers/net/arcnet/rfc1051.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/rfc1051.c Tue Jan 4 09:41:45 2000 @@ -0,0 +1,255 @@ +/* + * Linux ARCnet driver - RFC1051 ("simple" standard) packet encapsulation + * + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n" + + +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum); + + +struct ArcProto rfc1051_proto = +{ + 's', + XMTU - RFC1051_HDR_SIZE, + rx, + build_header, + prepare_tx +}; + + +void __init arcnet_rfc1051_init(void) +{ + arc_proto_map[ARC_P_IP_RFC1051] + = arc_proto_map[ARC_P_ARP_RFC1051] + = &rfc1051_proto; + + /* if someone else already owns the broadcast, we won't take it */ + if (arc_bcast_proto == arc_proto_default) + arc_bcast_proto = &rfc1051_proto; + +} + + +#ifdef MODULE + +int __init init_module(void) +{ + printk(VERSION); + arcnet_rfc1051_init(); + return 0; +} + +void cleanup_module(void) +{ + arcnet_unregister_proto(&rfc1051_proto); +} + +#endif /* MODULE */ + + +/* + * Determine a packet's protocol ID. + * + * With ARCnet we have to convert everything to Ethernet-style stuff. + */ +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct archdr *pkt = (struct archdr *) skb->data; + struct arc_rfc1051 *soft = &pkt->soft.rfc1051; + int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; + + /* Pull off the arcnet header. */ + skb->mac.raw = skb->data; + skb_pull(skb, hdr_size); + + if (pkt->hard.dest == 0) + skb->pkt_type = PACKET_BROADCAST; + else if (dev->flags & IFF_PROMISC) { + /* if we're not sending to ourselves :) */ + if (pkt->hard.dest != dev->dev_addr[0]) + skb->pkt_type = PACKET_OTHERHOST; + } + /* now return the protocol number */ + switch (soft->proto) { + case ARC_P_IP_RFC1051: + return htons(ETH_P_IP); + case ARC_P_ARP_RFC1051: + return htons(ETH_P_ARP); + + default: + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + return 0; + } + + return htons(ETH_P_IP); +} + + +/* packet receiver */ +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct sk_buff *skb; + struct archdr *pkt = pkthdr; + int ofs; + + BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length); + + if (length >= MinTU) + ofs = 512 - length; + else + ofs = 256 - length; + + skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb_put(skb, length + ARC_HDR_SIZE); + skb->dev = dev; + + pkt = (struct archdr *) skb->data; + + /* up to sizeof(pkt->soft) has already been copied from the card */ + memcpy(pkt, pkthdr, sizeof(struct archdr)); + if (length > sizeof(pkt->soft)) + lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), + pkt->soft.raw + sizeof(pkt->soft), + length - sizeof(pkt->soft)); + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = type_trans(skb, dev); + netif_rx(skb); +} + + +/* + * Create the ARCnet hard/soft headers for RFC1051. + */ +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; + struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); + struct arc_rfc1051 *soft = &pkt->soft.rfc1051; + + /* set the protocol ID according to RFC1051 */ + switch (type) { + case ETH_P_IP: + soft->proto = ARC_P_IP_RFC1051; + break; + case ETH_P_ARP: + soft->proto = ARC_P_ARP_RFC1051; + break; + default: + BUGMSG(D_NORMAL, "RFC1051: I don't understand protocol %d (%Xh)\n", + type, type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + return 0; + } + + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help in + * debugging. ARCnet does not allow us to change the source address in + * the actual packet sent) + */ + pkt->hard.source = *dev->dev_addr; + + /* see linux/net/ethernet/eth.c to see where I got the following */ + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + /* + * FIXME: fill in the last byte of the dest ipaddr here to better + * comply with RFC1051 in "noarp" mode. + */ + pkt->hard.dest = 0; + return hdr_size; + } + /* otherwise, just fill it in and go! */ + pkt->hard.dest = daddr; + + return hdr_size; /* success */ +} + + +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arc_hardware *hard = &pkt->hard; + int ofs; + + BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", + lp->next_tx, lp->cur_tx, bufnum); + + length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ + + if (length > XMTU) { + /* should never happen! other people already check for this. */ + BUGMSG(D_NORMAL, "Bug! prepare_tx with size %d (> %d)\n", + length, XMTU); + length = XMTU; + } + if (length > MinTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length; + } else if (length > MTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - length - 3; + } else + hard->offset[0] = ofs = 256 - length; + + lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); + lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft, length); + + lp->lastload_dest = hard->dest; + + return 1; /* done */ +} diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet/rfc1201.c linux/drivers/net/arcnet/rfc1201.c --- v2.3.35/linux/drivers/net/arcnet/rfc1201.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arcnet/rfc1201.c Tue Jan 4 09:41:45 2000 @@ -0,0 +1,536 @@ +/* + * Linux ARCnet driver - RFC1201 (standard) packet encapsulation + * + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include + +#define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n" + + +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev); +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length); +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr); +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum); +static int continue_tx(struct net_device *dev, int bufnum); + +struct ArcProto rfc1201_proto = +{ + 'a', + 1500, /* could be more, but some receivers can't handle it... */ + rx, + build_header, + prepare_tx, + continue_tx +}; + + +void __init arcnet_rfc1201_init(void) +{ + arc_proto_map[ARC_P_IP] + = arc_proto_map[ARC_P_ARP] + = arc_proto_map[ARC_P_RARP] + = arc_proto_map[ARC_P_IPX] + = arc_proto_map[ARC_P_NOVELL_EC] + = &rfc1201_proto; + + /* if someone else already owns the broadcast, we won't take it */ + if (arc_bcast_proto == arc_proto_default) + arc_bcast_proto = &rfc1201_proto; +} + + +#ifdef MODULE + +int __init init_module(void) +{ + printk(VERSION); + arcnet_rfc1201_init(); + return 0; +} + +void cleanup_module(void) +{ + arcnet_unregister_proto(&rfc1201_proto); +} + +#endif /* MODULE */ + + +/* + * Determine a packet's protocol ID. + * + * With ARCnet we have to convert everything to Ethernet-style stuff. + */ +static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct archdr *pkt = (struct archdr *) skb->data; + struct arc_rfc1201 *soft = &pkt->soft.rfc1201; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; + + /* Pull off the arcnet header. */ + skb->mac.raw = skb->data; + skb_pull(skb, hdr_size); + + if (pkt->hard.dest == 0) + skb->pkt_type = PACKET_BROADCAST; + else if (dev->flags & IFF_PROMISC) { + /* if we're not sending to ourselves :) */ + if (pkt->hard.dest != dev->dev_addr[0]) + skb->pkt_type = PACKET_OTHERHOST; + } + /* now return the protocol number */ + switch (soft->proto) { + case ARC_P_IP: + return htons(ETH_P_IP); + case ARC_P_ARP: + return htons(ETH_P_ARP); + case ARC_P_RARP: + return htons(ETH_P_RARP); + + case ARC_P_IPX: + case ARC_P_NOVELL_EC: + return htons(ETH_P_802_3); + default: + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + return 0; + } + + return htons(ETH_P_IP); +} + + +/* packet receiver */ +static void rx(struct net_device *dev, int bufnum, + struct archdr *pkthdr, int length) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct sk_buff *skb; + struct archdr *pkt = pkthdr; + struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201; + int saddr = pkt->hard.source, ofs; + struct Incoming *in = &lp->rfc1201.incoming[saddr]; + + BUGMSG(D_DURING, "it's an RFC1201 packet (length=%d)\n", length); + + if (length >= MinTU) + ofs = 512 - length; + else + ofs = 256 - length; + + if (soft->split_flag == 0xFF) { /* Exception Packet */ + if (length >= 4 + RFC1201_HDR_SIZE) + BUGMSG(D_DURING, "compensating for exception packet\n"); + else { + BUGMSG(D_EXTRA, "short RFC1201 exception packet from %02Xh", + saddr); + return; + } + + /* skip over 4-byte junkola */ + length -= 4; + ofs += 4; + lp->hw.copy_from_card(dev, bufnum, 512 - length, + soft, sizeof(pkt->soft)); + } + if (!soft->split_flag) { /* not split */ + BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n", + soft->split_flag); + + if (in->skb) { /* already assembling one! */ + BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", + in->sequence, soft->split_flag, soft->sequence); + lp->rfc1201.aborted_seq = soft->sequence; + kfree_skb(in->skb); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->skb = NULL; + } + in->sequence = soft->sequence; + + skb = alloc_skb(length + ARC_HDR_SIZE, GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb_put(skb, length + ARC_HDR_SIZE); + skb->dev = dev; + + pkt = (struct archdr *) skb->data; + soft = &pkt->soft.rfc1201; + + /* up to sizeof(pkt->soft) has already been copied from the card */ + memcpy(pkt, pkthdr, sizeof(struct archdr)); + if (length > sizeof(pkt->soft)) + lp->hw.copy_from_card(dev, bufnum, ofs + sizeof(pkt->soft), + pkt->soft.raw + sizeof(pkt->soft), + length - sizeof(pkt->soft)); + + /* + * ARP packets have problems when sent from some DOS systems: the + * source address is always 0! So we take the hardware source addr + * (which is impossible to fumble) and insert it ourselves. + */ + if (soft->proto == ARC_P_ARP) { + struct arphdr *arp = (struct arphdr *) soft->payload; + + /* make sure addresses are the right length */ + if (arp->ar_hln == 1 && arp->ar_pln == 4) { + uint8_t *cptr = (uint8_t *) arp + sizeof(struct arphdr); + + if (!*cptr) { /* is saddr = 00? */ + BUGMSG(D_EXTRA, + "ARP source address was 00h, set to %02Xh.\n", + saddr); + lp->stats.rx_crc_errors++; + *cptr = saddr; + } else { + BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n", + *cptr); + } + } else { + BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n", + arp->ar_hln, arp->ar_pln); + lp->stats.rx_errors++; + lp->stats.rx_crc_errors++; + } + } + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = type_trans(skb, dev); + netif_rx(skb); + } else { /* split packet */ + /* + * NOTE: MSDOS ARP packet correction should only need to apply to + * unsplit packets, since ARP packets are so short. + * + * My interpretation of the RFC1201 document is that if a packet is + * received out of order, the entire assembly process should be + * aborted. + * + * The RFC also mentions "it is possible for successfully received + * packets to be retransmitted." As of 0.40 all previously received + * packets are allowed, not just the most recent one. + * + * We allow multiple assembly processes, one for each ARCnet card + * possible on the network. Seems rather like a waste of memory, + * but there's no other way to be reliable. + */ + + BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n", + soft->split_flag, in->sequence); + + if (in->skb && in->sequence != soft->sequence) { + BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", + saddr, in->sequence, soft->sequence, + soft->split_flag); + kfree_skb(in->skb); + in->skb = NULL; + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->lastpacket = in->numpackets = 0; + } + if (soft->split_flag & 1) { /* first packet in split */ + BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n", + soft->split_flag); + if (in->skb) { /* already assembling one! */ + BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly " + "(splitflag=%d, seq=%d)\n", + in->sequence, soft->split_flag, + soft->sequence); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + kfree_skb(in->skb); + } + in->sequence = soft->sequence; + in->numpackets = ((unsigned) soft->split_flag >> 1) + 2; + in->lastpacket = 1; + + if (in->numpackets > 16) { + BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n", + soft->split_flag); + lp->stats.rx_errors++; + lp->stats.rx_length_errors++; + return; + } + in->skb = skb = alloc_skb(508 * in->numpackets + ARC_HDR_SIZE, + GFP_ATOMIC); + if (skb == NULL) { + BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n"); + lp->stats.rx_dropped++; + return; + } + skb->dev = dev; + pkt = (struct archdr *) skb->data; + soft = &pkt->soft.rfc1201; + + memcpy(pkt, pkthdr, ARC_HDR_SIZE + RFC1201_HDR_SIZE); + skb_put(skb, ARC_HDR_SIZE + RFC1201_HDR_SIZE); + + soft->split_flag = 0; /* end result won't be split */ + } else { /* not first packet */ + int packetnum = ((unsigned) soft->split_flag >> 1) + 1; + + /* + * if we're not assembling, there's no point trying to + * continue. + */ + if (!in->skb) { + if (lp->rfc1201.aborted_seq != soft->sequence) { + BUGMSG(D_EXTRA, "can't continue split without starting " + "first! (splitflag=%d, seq=%d, aborted=%d)\n", + soft->split_flag, soft->sequence, + lp->rfc1201.aborted_seq); + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + } + return; + } + in->lastpacket++; + if (packetnum != in->lastpacket) { /* not the right flag! */ + /* harmless duplicate? ignore. */ + if (packetnum <= in->lastpacket - 1) { + BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n", + soft->split_flag); + lp->stats.rx_errors++; + lp->stats.rx_frame_errors++; + return; + } + /* "bad" duplicate, kill reassembly */ + BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly " + "(seq=%d) aborted (splitflag=%d, seq=%d)\n", + in->sequence, soft->split_flag, soft->sequence); + lp->rfc1201.aborted_seq = soft->sequence; + kfree_skb(in->skb); + in->skb = NULL; + lp->stats.rx_errors++; + lp->stats.rx_missed_errors++; + in->lastpacket = in->numpackets = 0; + return; + } + pkt = (struct archdr *) in->skb->data; + soft = &pkt->soft.rfc1201; + } + + skb = in->skb; + + lp->hw.copy_from_card(dev, bufnum, ofs + RFC1201_HDR_SIZE, + skb->data + skb->len, + length - RFC1201_HDR_SIZE); + skb_put(skb, length - RFC1201_HDR_SIZE); + + /* are we done? */ + if (in->lastpacket == in->numpackets) { + in->skb = NULL; + in->lastpacket = in->numpackets = 0; + + BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); + + skb->protocol = type_trans(skb, dev); + netif_rx(skb); + } + } +} + + +/* Create the ARCnet hard/soft headers for RFC1201. */ +static int build_header(struct sk_buff *skb, unsigned short type, + uint8_t daddr) +{ + struct net_device *dev = skb->dev; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; + struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); + struct arc_rfc1201 *soft = &pkt->soft.rfc1201; + + /* set the protocol ID according to RFC1201 */ + switch (type) { + case ETH_P_IP: + soft->proto = ARC_P_IP; + break; + case ETH_P_ARP: + soft->proto = ARC_P_ARP; + break; + case ETH_P_RARP: + soft->proto = ARC_P_RARP; + break; + case ETH_P_IPX: + case ETH_P_802_3: + case ETH_P_802_2: + soft->proto = ARC_P_IPX; + break; + case ETH_P_ATALK: + soft->proto = ARC_P_ATALK; + break; + default: + BUGMSG(D_NORMAL, "RFC1201: I don't understand protocol %d (%Xh)\n", + type, type); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + return 0; + } + + /* + * Set the source hardware address. + * + * This is pretty pointless for most purposes, but it can help in + * debugging. ARCnet does not allow us to change the source address in + * the actual packet sent) + */ + pkt->hard.source = *dev->dev_addr; + + soft->sequence = htons(lp->rfc1201.sequence++); + soft->split_flag = 0; /* split packets are done elsewhere */ + + /* see linux/net/ethernet/eth.c to see where I got the following */ + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + /* + * FIXME: fill in the last byte of the dest ipaddr here to better + * comply with RFC1051 in "noarp" mode. For now, always broadcasting + * will probably at least get packets sent out :) + */ + pkt->hard.dest = 0; + return hdr_size; + } + /* otherwise, drop in the dest address */ + pkt->hard.dest = daddr; + return hdr_size; +} + + +static void load_pkt(struct net_device *dev, struct arc_hardware *hard, + struct arc_rfc1201 *soft, int softlen, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int ofs; + + /* assume length <= XMTU: someone should have handled that by now. */ + + if (softlen > MinTU) { + hard->offset[0] = 0; + hard->offset[1] = ofs = 512 - softlen; + } else if (softlen > MTU) { /* exception packet - add an extra header */ + struct arc_rfc1201 excsoft = + {soft->proto, 0xFF, 0xFFFF}; + + hard->offset[0] = 0; + ofs = 512 - softlen; + hard->offset[1] = ofs - RFC1201_HDR_SIZE; + lp->hw.copy_to_card(dev, bufnum, ofs - RFC1201_HDR_SIZE, + &excsoft, RFC1201_HDR_SIZE); + } else + hard->offset[0] = ofs = 256 - softlen; + + lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE); + lp->hw.copy_to_card(dev, bufnum, ofs, soft, softlen); + + lp->lastload_dest = hard->dest; +} + + +static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, + int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + const int maxsegsize = XMTU - RFC1201_HDR_SIZE; + struct Outgoing *out; + + + BUGMSG(D_DURING, "prepare_tx: txbufs=%d/%d/%d\n", + lp->next_tx, lp->cur_tx, bufnum); + + length -= ARC_HDR_SIZE; /* hard header is not included in packet length */ + pkt->soft.rfc1201.split_flag = 0; + + /* need to do a split packet? */ + if (length > XMTU) { + out = &lp->outgoing; + + out->length = length - RFC1201_HDR_SIZE; + out->dataleft = lp->outgoing.length; + out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize; + out->segnum = 0; + + BUGMSG(D_DURING, "rfc1201 prep_tx: ready for %d-segment split " + "(%d bytes, seq=%d)\n", out->numsegs, out->length, + pkt->soft.rfc1201.sequence); + + return 0; /* not done */ + } + /* just load the packet into the buffers and send it off */ + load_pkt(dev, &pkt->hard, &pkt->soft.rfc1201, length, bufnum); + + return 1; /* done */ +} + + +static int continue_tx(struct net_device *dev, int bufnum) +{ + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct Outgoing *out = &lp->outgoing; + struct arc_hardware *hard = &out->pkt->hard; + struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft; + int maxsegsize = XMTU - RFC1201_HDR_SIZE; + int seglen; + + BUGMSG(D_DURING, + "rfc1201 continue_tx: loading segment %d(+1) of %d (seq=%d)\n", + out->segnum, out->numsegs, soft->sequence); + + /* the "new" soft header comes right before the data chunk */ + newsoft = (struct arc_rfc1201 *) + (out->pkt->soft.raw + out->length - out->dataleft); + + if (!out->segnum) /* first packet; newsoft == soft */ + newsoft->split_flag = ((out->numsegs - 2) << 1) | 1; + else { + newsoft->split_flag = out->segnum << 1; + newsoft->proto = soft->proto; + newsoft->sequence = soft->sequence; + } + + seglen = maxsegsize; + if (seglen > out->dataleft) + seglen = out->dataleft; + out->dataleft -= seglen; + + load_pkt(dev, hard, newsoft, seglen + RFC1201_HDR_SIZE, bufnum); + + out->segnum++; + if (out->segnum >= out->numsegs) + return 1; + else + return 0; +} diff -u --recursive --new-file v2.3.35/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.3.35/linux/drivers/net/arcnet.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/net/arcnet.c Wed Dec 31 16:00:00 1969 @@ -1,1981 +0,0 @@ -/* $Id: arcnet.c,v 1.34 1997/11/09 11:04:55 mj Exp $ - - Written 1994-1996 by Avery Pennarun, - derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - v3.02 (98/06/07) - - Use register_netdevice() instead of register_netdev() to create - new devices for RFC1051 and Ethernet encapsulation in arcnet_open. - Likewise for unregistering them later. This avoids the deadlock - encountered because the original routines call rtnl_lock() when - it's already locked. [dw] - - v3.01 (98/04/17) - - Interrupt handler now also checks dev->[se]dev are non-NULL - to avoid crashes in interrupts during card init. [dw] - - v3.00 (97/11/09) - - Minor cleanup of debugging messages. [mj] - - v2.93 ALPHA (97/11/06) - - irq2dev mapping removed. - - Interrupt handler now checks whether dev->priv is non-null in order - to avoid crashes in interrupts which come during card init. [mj] - - v2.92 ALPHA (97/09/02) - - Code cleanup [Martin Mares ] - - Better probing for the COM90xx chipset, although only as - a temporary solution until we implement adding of all found - devices at once. [mj] - - v2.91 ALPHA (97/08/19) - - Add counting of octets in/out. - - v2.90 ALPHA (97/08/08) - - Add support for kernel command line parsing so that chipset - drivers are usable when compiled in. - - v2.80 ALPHA (97/08/01) - - Split source into multiple files; generic arcnet support and - individual chipset drivers. - - v2.61 ALPHA (97/07/30) by David Woodhouse (Dave@imladris.demon.co.uk) - for Nortel (Northern Telecom). - - Added support for IO-mapped modes and for SMC COM20020 chipset. - - Fixed (avoided) race condition in send_packet routines which was - discovered when the buffer copy routines got slow (?). - - Fixed support for device naming at load time. - - Added backplane, clock and timeout options for COM20020. - - Added support for promiscuous mode. - - v2.60 ALPHA (96/11/23) - - Added patch from Vojtech Pavlik - and Martin Mares to make the driver work - with the new Linux 2.1.x memory management. I modified their - patch quite a bit though; bugs are my fault. More changes should - be made to get eliminate any remaining phys_to_virt calls. - - Quietly ignore protocol id's 0, 1, 8, and 243. Thanks to Jake - Messinger for reporting these codes and their - meanings. - - Smarter shmem probe for cards with 4k mirrors. (does it work?) - - Initial support for RIM I type cards which use no I/O ports at - all. To use this option, you need to compile with RIM_I_MODE - enabled. Thanks to Kolja Waschk for explaining - RIM I programming to me. Now, does my RIM I code actually - work? - - v2.56 (96/10/18) - - Turned arc0e/arc0s startup messages back on by default, as most - people will probably not notice the additional devices - otherwise. This causes undue confusion. - - Fixed a tiny but noticeable bug in the packet debugging routines - (thanks Tomasz) - - The following has been SUMMARIZED. The complete ChangeLog is - available in the full Linux-ARCnet package at - http://www.worldvisions.ca/~apenwarr/arcnet - - v2.50 (96/02/24) - - Massively improved autoprobe routines; they now work even as a - module. Thanks to Vojtech Pavlik - for his ideas and help in this area. - - Changed printk's around quite a lot. - - v2.22 (95/12/08) - - Major cleanups, speedups, and better code-sharing. - - Eliminated/changed many useless/meaningless/scary debug messages - (and, in most cases, the bugs that caused them). - - Better IPX support. - - lp->stats updated properly. - - RECON checking now by default only prints a message if there are - excessive errors (ie. your cable is probably broken). - - New RFC1051-compliant "arc0s" virtual device by Tomasz - Motylewski. - - Excess debug messages can be compiled out to reduce code size. - - v2.00 (95/09/06) - - ARCnet RECON messages are now detected and logged as "carrier" - errors. - - The TXACK flag is now checked, and errors are logged. - - Debug levels are now completely different. See the README. - - Massive code cleanups, with several no-longer-necessary and some - completely useless options removed. - - Multiprotocol support. You can now use the "arc0e" device to - send "Ethernet-Encapsulation" packets, which are compatible with - Windows for Workgroups and LAN Manager, and possibly other - software. See the README for more information. - - v1.02 (95/06/21) - - A fix to make "exception" packets sent from Linux receivable - on other systems. (The protocol_id byte was sometimes being set - incorrectly, and Linux wasn't checking it on receive so it - didn't show up) - - v1.01 (95/03/24) - - Fixed some IPX-related bugs. (Thanks to Tomasz Motylewski - for the patches to make arcnet work - with dosemu!) - - v1.00 (95/02/15) - - Initial non-alpha release. - - - TO DO: (semi-prioritized) - - - Use cleaner "architecture-independent" shared memory access. - This is half-done in ARCnet 2.60, but still uses some - undocumented i386 stuff. (We shouldn't call phys_to_virt, - for example.) - - Allow use of RFC1051 or Ether devices without RFC1201. - - Keep separate stats for each device. - - Support "arpless" mode like NetBSD does, and as recommended - by the (obsoleted) RFC1051. - - Smarter recovery from RECON-during-transmit conditions. (ie. - retransmit immediately) - - Add support for the new 1.3.x IP header cache, and other features. - - Replace setting of debug level with the "metric" flag hack by - something that still exists. SIOCDEVPRIVATE is a good candidate, - but it would require an extra user-level utility. - - - What about cards with shared memory that can be "turned off?" - (or that have none at all, like the SMC PC500longboard) - Does this work now, with IO_MAPPED_BUFFERS? - - - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play - with temporarily.) Update: yes, the Pure Data config program - for DOS works fine, but the PDI508Plus I have doesn't! :) - - ATA protocol support?? - - VINES TCP/IP encapsulation?? (info needed) - - Sources: - - Crynwr arcnet.com/arcether.com packet drivers. - - arcnet.c v0.00 dated 1/1/94 and apparently by - Donald Becker - it didn't work :) - - skeleton.c v0.05 dated 11/16/93 by Donald Becker - (from Linux Kernel 1.1.45) - - RFC's 1201 and 1051 - re: TCP/IP over ARCnet - - The official ARCnet COM9026 data sheets (!) thanks to Ken - Cornetet - - The official ARCnet COM20020 data sheets. - - Information on some more obscure ARCnet controller chips, thanks - to the nice people at SMC. - - net/inet/eth.c (from kernel 1.1.50) for header-building info. - - Alternate Linux ARCnet source by V.Shergin - - Textual information and more alternate source from Joachim Koenig - - */ - -static const char *version = -"arcnet.c: v3.02 98/06/07 Avery Pennarun et al.\n"; - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include - -/* Define this if you want to make it easier to use the "call trace" when - * a kernel NULL pointer assignment occurs. Hopefully unnecessary, most of - * the time. It will make all the function names (and other things) show - * up as kernel symbols. (especially handy when using arcnet as a module) - */ -#undef static - -/**************************************************************************/ - -/* These are now provided by the chipset driver. There's a performance - * overhead in using them. - */ - -#define AINTMASK(x) ((*lp->asetmask)(dev, x)) -#define ARCSTATUS ((*lp->astatus)(dev)) -#define ACOMMAND(x) ((*lp->acommand)(dev, x)) - -int arcnet_debug = ARCNET_DEBUG; - -/* Exported function prototypes */ - -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -#else -int arcnet_init(void); -static int init_module(void); -#ifdef CONFIG_ARCNET_COM90xx -extern char com90xx_explicit; -extern int arc90xx_probe(struct net_device *dev); -#endif -#endif - -void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp); -void arcnet_use_count(int open); -void arcnet_setup(struct net_device *dev); -void arcnet_makename(char *device); -void arcnetA_continue_tx(struct net_device *dev); -int arcnet_go_tx(struct net_device *dev, int enable_irq); -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); -void arcnet_rx(struct arcnet_local *lp, u_char * arcsoft, short length, int saddr, int daddr); - -EXPORT_SYMBOL(arcnet_debug); -EXPORT_SYMBOL(arcnet_tx_done); -EXPORT_SYMBOL(arcnet_use_count); -EXPORT_SYMBOL(arcnet_setup); -EXPORT_SYMBOL(arcnet_makename); -EXPORT_SYMBOL(arcnetA_continue_tx); -EXPORT_SYMBOL(arcnet_go_tx); -EXPORT_SYMBOL(arcnet_interrupt); -EXPORT_SYMBOL(arcnet_rx); - -#if ARCNET_DEBUG_MAX & D_SKB -void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, - char *desc); -EXPORT_SYMBOL(arcnet_dump_skb); -#else -#define arcnet_dump_skb(dev,skb,desc) ; -#endif - -#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX) -void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext, - char *desc); -EXPORT_SYMBOL(arcnet_dump_packet); -#else -#define arcnet_dump_packet(dev,buffer,ext,desc) ; -#endif - -/* Internal function prototypes */ - -static int arcnet_open(struct net_device *dev); -static int arcnet_close(struct net_device *dev); -static int arcnetA_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int arcnetA_rebuild_header(struct sk_buff *skb); -static int arcnet_send_packet_bad(struct sk_buff *skb, struct net_device *dev); -static int arcnetA_send_packet(struct sk_buff *skb, struct net_device *dev); -static void arcnetA_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr); -static struct net_device_stats *arcnet_get_stats(struct net_device *dev); -static unsigned short arcnetA_type_trans(struct sk_buff *skb, - struct net_device *dev); - - -#ifdef CONFIG_ARCNET_ETH - /* functions specific to Ethernet-Encap */ -static int arcnetE_init(struct net_device *dev); -static int arcnetE_open_close(struct net_device *dev); -static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev); -static void arcnetE_rx(struct net_device *dev, u_char * arcsoft, - int length, u_char saddr, u_char daddr); -#endif - - -#ifdef CONFIG_ARCNET_1051 - /* functions specific to RFC1051 */ -static int arcnetS_init(struct net_device *dev); -static int arcnetS_open_close(struct net_device *dev); -static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *dev); -static void arcnetS_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr); -static int arcnetS_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); -static int arcnetS_rebuild_header(struct sk_buff *skb); -static unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_device *dev); -#endif - - -/**************************************************************************** - * * - * Packet dumps for debugging * - * * - ****************************************************************************/ - -/* Dump the contents of an sk_buff - */ -#if ARCNET_DEBUG_MAX & D_SKB -void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) -{ - int i; - long flags; - - save_flags(flags); - cli(); - printk(KERN_DEBUG "%6s: skb dump (%s) follows:", dev->name, desc); - for (i = 0; i < skb->len; i++) { - if (i % 16 == 0) - printk("\n" KERN_DEBUG "[%04X] ", i); - printk("%02X ", ((u_char *) skb->data)[i]); - } - printk("\n"); - restore_flags(flags); -} -#endif - - -/* Dump the contents of an ARCnet buffer - */ -#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX) -void arcnet_dump_packet(struct net_device *dev, u_char * buffer, int ext, char *desc) -{ - int i; - long flags; - - save_flags(flags); - cli(); - printk(KERN_DEBUG "%6s: packet dump (%s) follows:", dev->name, desc); - for (i = 0; i < 256 + (ext != 0) * 256; i++) { - if (i % 16 == 0) - printk("\n" KERN_DEBUG "[%04X] ", i); - printk("%02X ", buffer[i]); - } - printk("\n"); - restore_flags(flags); -} -#endif - - -/* Setup a struct net_device for ARCnet. This should really be in net_init.c - * but since there are three different ARCnet devices ANYWAY... - * - * Actually, the whole idea of having all this kernel-dependent stuff (ie. - * "new-style flags") setup per-net-device is kind of weird anyway. - * - * Intelligent defaults?! Nah. - */ - -void arcnet_setup(struct net_device *dev) -{ - dev_init_buffers(dev); - - dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ - dev->addr_len = 1; - dev->type = ARPHRD_ARCNET; - dev->tx_queue_len = 30; - - /* New-style flags. */ - dev->flags = IFF_BROADCAST; - - /* Put in this stuff here, so we don't have to export the symbols - * to the chipset drivers. - */ - - dev->open = arcnet_open; - dev->stop = arcnet_close; - dev->hard_start_xmit = arcnetA_send_packet; - dev->get_stats = arcnet_get_stats; - dev->hard_header = arcnetA_header; - dev->rebuild_header = arcnetA_rebuild_header; -} - - -/**************************************************************************** - * * - * Open and close the driver * - * * - ****************************************************************************/ - -/* Open/initialize the board. This is called sometime after booting when - * the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ -static int arcnet_open(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - /* if (dev->metric>=1000) - * { - * arcnet_debug=dev->metric-1000; - * printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug); - * dev->metric=1; - *} - */ - BUGMSG(D_INIT, "arcnet_open: resetting card.\n"); - - /* try to put the card in a defined state - if it fails the first - * time, actually reset it. - */ - if ((*lp->arcnet_reset) (dev, 0) && (*lp->arcnet_reset) (dev, 1)) - return -ENODEV; - - dev->tbusy = 0; - dev->interrupt = 0; - lp->intx = 0; - lp->in_txhandler = 0; - - /* The RFC1201 driver is the default - just store */ - lp->adev = dev; - - /* we're started */ - dev->start = 1; - -#ifdef CONFIG_ARCNET_ETH - /* Initialize the ethernet-encap protocol driver */ - lp->edev = (struct net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (lp->edev == NULL) - return -ENOMEM; - memcpy(lp->edev, dev, sizeof(struct net_device)); - lp->edev->type = ARPHRD_ETHER; - lp->edev->name = (char *) kmalloc(10, GFP_KERNEL); - if (lp->edev->name == NULL) { - kfree(lp->edev); - lp->edev = NULL; - return -ENOMEM; - } - sprintf(lp->edev->name, "%se", dev->name); - lp->edev->init = arcnetE_init; - register_netdevice(lp->edev); -#endif - -#ifdef CONFIG_ARCNET_1051 - /* Initialize the RFC1051-encap protocol driver */ - lp->sdev = (struct net_device *) kmalloc(sizeof(struct net_device) + 10, GFP_KERNEL); - if (lp->sdev == NULL) { -#ifdef CONFIG_ARCNET_ETH - if (lp->edev) - kfree(lp->edev); - lp->edev = NULL; - return -ENOMEM; -#endif - } - memcpy(lp->sdev, dev, sizeof(struct net_device)); - lp->sdev->name = (char *) (lp + 1); - sprintf(lp->sdev->name, "%ss", dev->name); - lp->sdev->init = arcnetS_init; - register_netdevice(lp->sdev); -#endif - - /* Enable TX if we need to */ - if (lp->en_dis_able_TX) - (*lp->en_dis_able_TX) (dev, 1); - - /* make sure we're ready to receive IRQ's. - * arcnet_reset sets this for us, but if we receive one before - * START is set to 1, it could be ignored. So, we turn IRQ's - * off, then on again to clean out the IRQ controller. - */ - - AINTMASK(0); - udelay(1); /* give it time to set the mask before - * we reset it again. (may not even be - * necessary) - */ - SETMASK; - - /* Let it increase its use count */ - (*lp->openclose_device) (1); - - return 0; -} - - -/* The inverse routine to arcnet_open - shuts down the card. - */ -static int arcnet_close(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - if (test_and_set_bit(0, (int *) &dev->tbusy)) - BUGMSG(D_NORMAL, "arcnet_close: tbusy already set!\n"); - - dev->start = 0; -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 1; - lp->sdev->start = 0; -#endif -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 1; - lp->edev->start = 0; -#endif - - /* Shut down the card */ - - /* Disable TX if we need to */ - if (lp->en_dis_able_TX) - (*lp->en_dis_able_TX) (dev, 0); - - (*lp->arcnet_reset) (dev, 3); /* reset IRQ won't run if START=0 */ -#if 0 - lp->intmask = 0; - SETMASK; /* no IRQ's (except RESET, of course) */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ -#endif - - /* reset more flags */ - dev->interrupt = 0; -#ifdef CONFIG_ARCNET_ETH - lp->edev->interrupt = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - lp->sdev->interrupt = 0; -#endif - - /* do NOT free lp->adev!! It's static! */ - lp->adev = NULL; - -#ifdef CONFIG_ARCNET_ETH - /* free the ethernet-encap protocol device */ - lp->edev->priv = NULL; - unregister_netdevice(lp->edev); - kfree(lp->edev->name); - kfree(lp->edev); - lp->edev = NULL; -#endif - -#ifdef CONFIG_ARCNET_1051 - /* free the RFC1051-encap protocol device */ - lp->sdev->priv = NULL; - unregister_netdevice(lp->sdev); - kfree(lp->sdev); - lp->sdev = NULL; -#endif - - /* Update the statistics here. (not necessary in ARCnet) */ - - /* Decrease the use count */ - (*lp->openclose_device) (0); - - return 0; -} - - -/**************************************************************************** - * * - * Transmitter routines * - * * - ****************************************************************************/ - -/* Generic error checking routine for arcnet??_send_packet - */ -static int arcnet_send_packet_bad(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - BUGMSG(D_DURING, "transmit requested (status=%Xh, inTX=%d)\n", - ARCSTATUS, lp->intx); - - if (lp->in_txhandler) { - BUGMSG(D_NORMAL, "send_packet called while in txhandler!\n"); - lp->stats.tx_dropped++; - return 1; - } - if (lp->intx > 1) { - BUGMSG(D_NORMAL, "send_packet called while intx!\n"); - lp->stats.tx_dropped++; - return 1; - } - if (test_bit(0, (int *) &dev->tbusy)) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - - int status = ARCSTATUS; - - if (tickssofar < TX_TIMEOUT) { - BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n", - status, tickssofar, lp->outgoing.skb, - lp->outgoing.numsegs, - lp->outgoing.segnum); - return 1; - } - lp->intmask &= ~TXFREEflag; - SETMASK; - - if (status & TXFREEflag) { /* transmit _DID_ finish */ - BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", - status, tickssofar, lp->intmask, lp->lasttrans_dest); - lp->stats.tx_errors++; - } else { - BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", - status, tickssofar, lp->intmask, lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - - ACOMMAND(NOTXcmd); - } - - if (lp->outgoing.skb) { - dev_kfree_skb(lp->outgoing.skb); - lp->stats.tx_dropped++; - } - lp->outgoing.skb = NULL; - -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 0; -#endif - if (!test_and_clear_bit(0, (int *) &dev->tbusy)) - BUGMSG(D_EXTRA, "after timing out, tbusy was clear!\n"); - - lp->txready = 0; - lp->sending = 0; - - return 1; - } - if (lp->txready) { /* transmit already in progress! */ - BUGMSG(D_NORMAL, "trying to start new packet while busy! (status=%Xh)\n", - ARCSTATUS); - lp->intmask &= ~TXFREEflag; - SETMASK; - ACOMMAND(NOTXcmd); /* abort current send */ - (*lp->inthandler) (dev); /* fake an interrupt */ - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - lp->txready = 0; /* we definitely need this line! */ - - return 1; - } - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (int *) &lp->adev->tbusy)) { - BUGMSG(D_NORMAL, "transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", - ARCSTATUS, lp->intx, jiffies - dev->trans_start); - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - return -EBUSY; - } -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 1; -#endif -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 1; -#endif - - return 0; -} - - -/* Called by the kernel in order to transmit a packet. - */ -static int arcnetA_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int bad, oldmask = 0; - struct Outgoing *out = &(lp->outgoing); - - lp->intx++; - - oldmask |= lp->intmask; - lp->intmask = 0; - SETMASK; - - bad = arcnet_send_packet_bad(skb, dev); - if (bad) { - lp->intx--; - lp->intmask = oldmask; - SETMASK; - return bad; - } - /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ - - lp->intmask = oldmask & ~TXFREEflag; - SETMASK; - - out->length = 1 < skb->len ? skb->len : 1; - out->hdr = (struct ClientData *) skb->data; - out->skb = skb; - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx"); - - out->hdr->sequence = (lp->sequence++); - - /* fits in one packet? */ - if (out->length - EXTRA_CLIENTDATA <= XMTU) { - BUGMSG(D_DURING, "not splitting %d-byte packet. (split_flag=%d)\n", - out->length, out->hdr->split_flag); - if (out->hdr->split_flag) - BUGMSG(D_NORMAL, "short packet has split_flag set?! (split_flag=%d)\n", - out->hdr->split_flag); - out->numsegs = 1; - out->segnum = 1; - (*lp->prepare_tx) (dev, - ((char *) out->hdr) + EXTRA_CLIENTDATA, - sizeof(struct ClientData) - EXTRA_CLIENTDATA, - ((char *) skb->data) + sizeof(struct ClientData), - out->length - sizeof(struct ClientData), - out->hdr->daddr, 1, 0); - - /* done right away */ - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - out->skb = NULL; - - if (arcnet_go_tx(dev, 1)) { - /* inform upper layers */ - arcnet_tx_done(dev, lp); - } - } else { /* too big for one - split it */ - int maxsegsize = XMTU - 4; - - out->data = (u_char *) skb->data - + sizeof(struct ClientData); - out->dataleft = out->length - sizeof(struct ClientData); - out->numsegs = (out->dataleft + maxsegsize - 1) / maxsegsize; - out->segnum = 0; - - BUGMSG(D_TX, "packet (%d bytes) split into %d fragments:\n", - out->length, out->numsegs); - - /* if a packet waiting, launch it */ - arcnet_go_tx(dev, 1); - - if (!lp->txready) { - /* prepare a packet, launch it and prepare - * another. - */ - arcnetA_continue_tx(dev); - if (arcnet_go_tx(dev, 1)) { - arcnetA_continue_tx(dev); - arcnet_go_tx(dev, 1); - } - } - /* if segnum==numsegs, the transmission is finished; - * free the skb right away. - */ - - if (out->segnum == out->numsegs) { - /* transmit completed */ - out->segnum++; - if (out->skb) { - lp->stats.tx_bytes += skb->len; - dev_kfree_skb(out->skb); - } - out->skb = NULL; - } - } - - dev->trans_start = jiffies; - lp->intx--; - - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; - - return 0; -} - - -/* After an RFC1201 split packet has been set up, this function calls - * arcnetAS_prepare_tx to load the next segment into the card. This function - * does NOT automatically call arcnet_go_tx. - */ -void arcnetA_continue_tx(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int maxsegsize = XMTU - 4; - struct Outgoing *out = &(lp->outgoing); - - BUGMSG(D_DURING, "continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n", - ARCSTATUS, lp->intx, lp->in_txhandler, lp->intmask); - - if (lp->txready) { - BUGMSG(D_NORMAL, "continue_tx: called with packet in buffer!\n"); - return; - } - if (out->segnum >= out->numsegs) { - BUGMSG(D_NORMAL, "continue_tx: building segment %d of %d!\n", - out->segnum + 1, out->numsegs); - } - if (!out->segnum) /* first packet */ - out->hdr->split_flag = ((out->numsegs - 2) << 1) + 1; - else - out->hdr->split_flag = out->segnum << 1; - - out->seglen = maxsegsize; - if (out->seglen > out->dataleft) - out->seglen = out->dataleft; - - BUGMSG(D_TX, "building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n", - out->segnum + 1, out->seglen, out->numsegs, - out->length, out->hdr->split_flag); - - (*lp->prepare_tx) (dev, ((char *) out->hdr) + EXTRA_CLIENTDATA, - sizeof(struct ClientData) - EXTRA_CLIENTDATA, - out->data, out->seglen, out->hdr->daddr, 1, 0); - - out->dataleft -= out->seglen; - out->data += out->seglen; - out->segnum++; -} - - -/* Actually start transmitting a packet that was placed in the card's - * buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started. - * - * This should probably always be called with the INTMASK register set to 0, - * so go_tx is not called recursively. - * - * The enable_irq flag determines whether to actually write INTMASK value - * to the card; TXFREEflag is always OR'ed into the memory variable either - * way. - */ -int arcnet_go_tx(struct net_device *dev, int enable_irq) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n", - ARCSTATUS, lp->intmask, lp->txready, lp->sending); - - if (lp->sending || !lp->txready) { - if (enable_irq && lp->sending) { - lp->intmask |= TXFREEflag; - SETMASK; - } - return 0; - } - /* start sending */ - ACOMMAND(TXcmd | (lp->txready << 3)); - - lp->stats.tx_packets++; - lp->txready = 0; - lp->sending++; - - lp->lasttrans_dest = lp->lastload_dest; - lp->lastload_dest = 0; - - lp->intmask |= TXFREEflag; - - if (enable_irq) - SETMASK; - - return 1; -} - - -/**************************************************************************** - * * - * Interrupt handler * - * * - ****************************************************************************/ - - -/* The typical workload of the driver: Handle the network interface - * interrupts. Establish which device needs attention, and call the correct - * chipset interrupt handler. - */ -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct arcnet_local *lp; - - if (dev == NULL) { - BUGMSG(D_DURING, "arcnet: irq %d for unknown device.\n", irq); - return; - } - BUGMSG(D_DURING, "in arcnet_interrupt\n"); - - lp = (struct arcnet_local *) dev->priv; - if (!lp) { - BUGMSG(D_DURING, "arcnet: irq ignored.\n"); - return; - } - /* RESET flag was enabled - if !dev->start, we must clear it right - * away (but nothing else) since inthandler() is never called. - */ - - if (!dev->start) { - if (ARCSTATUS & RESETflag) - ACOMMAND(CFLAGScmd | RESETclear); - return; - } - if (test_and_set_bit(0, (int *) &dev->interrupt)) { - BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n"); - return; /* don't even try. */ - } -#ifdef CONFIG_ARCNET_1051 - if (lp->sdev) - lp->sdev->interrupt = 1; -#endif -#ifdef CONFIG_ARCNET_ETH - if (lp->edev) - lp->edev->interrupt = 1; -#endif - - /* Call the "real" interrupt handler. */ - (*lp->inthandler) (dev); - -#ifdef CONFIG_ARCNET_ETH - if (lp->edev) - lp->edev->interrupt = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - if (lp->sdev) - lp->sdev->interrupt = 0; -#endif - if (!test_and_clear_bit(0, (int *) &dev->interrupt)) - BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n"); - -} - -void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp) -{ - if (dev->tbusy) { -#ifdef CONFIG_ARCNET_ETH - lp->edev->tbusy = 0; -#endif -#ifdef CONFIG_ARCNET_1051 - lp->sdev->tbusy = 0; -#endif - if (!test_and_clear_bit(0, (int *) &dev->tbusy)) - BUGMSG(D_NORMAL, "In arcnet_tx_done: Someone cleared our dev->tbusy" - " flag!\n"); - - mark_bh(NET_BH); - } -} - - -/**************************************************************************** - * * - * Receiver routines * - * * - ****************************************************************************/ - -/* - * This is a generic packet receiver that calls arcnet??_rx depending on the - * protocol ID found. - */ - -void arcnet_rx(struct arcnet_local *lp, u_char * arcsoft, short length, int saddr, int daddr) -{ - struct net_device *dev = lp->adev; - - BUGMSG(D_DURING, "received packet from %02Xh to %02Xh (%d bytes)\n", - saddr, daddr, length); - - /* call the right receiver for the protocol */ - switch (arcsoft[0]) { - case ARC_P_IP: - case ARC_P_ARP: - case ARC_P_RARP: - case ARC_P_IPX: - case ARC_P_NOVELL_EC: - arcnetA_rx(lp->adev, arcsoft, length, saddr, daddr); - break; -#ifdef CONFIG_ARCNET_ETH - case ARC_P_ETHER: - arcnetE_rx(lp->edev, arcsoft, length, saddr, daddr); - break; -#endif -#ifdef CONFIG_ARCNET_1051 - case ARC_P_IP_RFC1051: - case ARC_P_ARP_RFC1051: - arcnetS_rx(lp->sdev, arcsoft, length, saddr, daddr); - break; -#endif - case ARC_P_DATAPOINT_BOOT: - case ARC_P_DATAPOINT_MOUNT: - break; - case ARC_P_POWERLAN_BEACON: - case ARC_P_POWERLAN_BEACON2: - break; - case ARC_P_LANSOFT: /* don't understand. fall through. */ - default: - BUGMSG(D_EXTRA, "received unknown protocol %d (%Xh) from station %d.\n", - arcsoft[0], arcsoft[0], saddr); - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - break; - } - - /* If any worth-while packets have been received, a mark_bh(NET_BH) - * has been done by netif_rx and Linux will handle them after we - * return. - */ - - -} - - - -/* Packet receiver for "standard" RFC1201-style packets - */ -static void arcnetA_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - struct sk_buff *skb; - struct ClientData *arcsoft, *soft; - - BUGMSG(D_DURING, "it's an RFC1201 packet (length=%d)\n", - length); - - /* compensate for EXTRA_CLIENTDATA (which isn't actually in the - * packet) - */ - arcsoft = (struct ClientData *) (buf - EXTRA_CLIENTDATA); - length += EXTRA_CLIENTDATA; - - if (arcsoft->split_flag == 0xFF) { /* Exception Packet */ - BUGMSG(D_DURING, "compensating for exception packet\n"); - - /* skip over 4-byte junkola */ - arcsoft = (struct ClientData *) - ((u_char *) arcsoft + 4); - length -= 4; - } - if (!arcsoft->split_flag) { /* not split */ - struct Incoming *in = &lp->incoming[saddr]; - - BUGMSG(D_RX, "incoming is not split (splitflag=%d)\n", - arcsoft->split_flag); - - if (in->skb) { /* already assembling one! */ - BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", - in->sequence, arcsoft->split_flag, - arcsoft->sequence); - lp->aborted_seq = arcsoft->sequence; - kfree_skb(in->skb); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->skb = NULL; - } - in->sequence = arcsoft->sequence; - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft = (struct ClientData *) skb->data; - - skb_put(skb, length); - skb->dev = dev; - - memcpy((u_char *) soft + EXTRA_CLIENTDATA, - (u_char *) arcsoft + EXTRA_CLIENTDATA, - length - EXTRA_CLIENTDATA); - soft->daddr = daddr; - soft->saddr = saddr; - - /* ARP packets have problems when sent from DOS. - * source address is always 0 on some systems! So we take - * the hardware source addr (which is impossible to fumble) - * and insert it ourselves. - */ - if (soft->protocol_id == ARC_P_ARP) { - struct arphdr *arp = (struct arphdr *) - ((char *) soft + sizeof(struct ClientData)); - - /* make sure addresses are the right length */ - if (arp->ar_hln == 1 && arp->ar_pln == 4) { - char *cptr = (char *) (arp) + sizeof(struct arphdr); - - if (!*cptr) { /* is saddr = 00? */ - BUGMSG(D_EXTRA, "ARP source address was 00h, set to %02Xh.\n", - saddr); - lp->stats.rx_crc_errors++; - *cptr = saddr; - } else { - BUGMSG(D_DURING, "ARP source address (%Xh) is fine.\n", - *cptr); - } - } else { - BUGMSG(D_NORMAL, "funny-shaped ARP packet. (%Xh, %Xh)\n", - arp->ar_hln, arp->ar_pln); - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - } - } - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = arcnetA_type_trans(skb, dev); - netif_rx(skb); - } else { /* split packet */ - /* NOTE: MSDOS ARP packet correction should only need to - * apply to unsplit packets, since ARP packets are so short. - * - * My interpretation of the RFC1201 (ARCnet) document is that - * if a packet is received out of order, the entire assembly - * process should be aborted. - * - * The RFC also mentions "it is possible for successfully - * received packets to be retransmitted." As of 0.40 all - * previously received packets are allowed, not just the - * most recent one. - * - * We allow multiple assembly processes, one for each - * ARCnet card possible on the network. Seems rather like - * a waste of memory. Necessary? - */ - - struct Incoming *in = &lp->incoming[saddr]; - - BUGMSG(D_RX, "packet is split (splitflag=%d, seq=%d)\n", - arcsoft->split_flag, in->sequence); - - if (in->skb && in->sequence != arcsoft->sequence) { - BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", - saddr, in->sequence, arcsoft->sequence, - arcsoft->split_flag); - kfree_skb(in->skb); - in->skb = NULL; - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->lastpacket = in->numpackets = 0; - } - if (arcsoft->split_flag & 1) { /* first packet in split */ - BUGMSG(D_RX, "brand new splitpacket (splitflag=%d)\n", - arcsoft->split_flag); - if (in->skb) { /* already assembling one! */ - BUGMSG(D_EXTRA, "aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n", - in->sequence, arcsoft->split_flag, - arcsoft->sequence); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - kfree_skb(in->skb); - } - in->sequence = arcsoft->sequence; - in->numpackets = ((unsigned) arcsoft->split_flag >> 1) + 2; - in->lastpacket = 1; - - if (in->numpackets > 16) { - BUGMSG(D_EXTRA, "incoming packet more than 16 segments; dropping. (splitflag=%d)\n", - arcsoft->split_flag); - lp->stats.rx_errors++; - lp->stats.rx_length_errors++; - return; - } - in->skb = skb = alloc_skb(508 * in->numpackets - + sizeof(struct ClientData), - GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "(split) memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft = (struct ClientData *) skb->data; - - skb_put(skb, sizeof(struct ClientData)); - skb->dev = dev; - - memcpy((u_char *) soft + EXTRA_CLIENTDATA, - (u_char *) arcsoft + EXTRA_CLIENTDATA, - sizeof(struct ClientData) - EXTRA_CLIENTDATA); - soft->split_flag = 0; /* final packet won't be split */ - } else { /* not first packet */ - int packetnum = ((unsigned) arcsoft->split_flag >> 1) + 1; - - /* if we're not assembling, there's no point - * trying to continue. - */ - if (!in->skb) { - if (lp->aborted_seq != arcsoft->sequence) { - BUGMSG(D_EXTRA, "can't continue split without starting first! (splitflag=%d, seq=%d, aborted=%d)\n", - arcsoft->split_flag, arcsoft->sequence, lp->aborted_seq); - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - } - return; - } - in->lastpacket++; - if (packetnum != in->lastpacket) { /* not the right flag! */ - /* harmless duplicate? ignore. */ - if (packetnum <= in->lastpacket - 1) { - BUGMSG(D_EXTRA, "duplicate splitpacket ignored! (splitflag=%d)\n", - arcsoft->split_flag); - lp->stats.rx_errors++; - lp->stats.rx_frame_errors++; - return; - } - /* "bad" duplicate, kill reassembly */ - BUGMSG(D_EXTRA, "out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n", - in->sequence, arcsoft->split_flag, - arcsoft->sequence); - lp->aborted_seq = arcsoft->sequence; - kfree_skb(in->skb); - in->skb = NULL; - lp->stats.rx_errors++; - lp->stats.rx_missed_errors++; - in->lastpacket = in->numpackets = 0; - return; - } - soft = (struct ClientData *) in->skb->data; - } - - skb = in->skb; - - memcpy(skb->data + skb->len, - (u_char *) arcsoft + sizeof(struct ClientData), - length - sizeof(struct ClientData)); - skb_put(skb, length - sizeof(struct ClientData)); - - soft->daddr = daddr; - soft->saddr = saddr; - - /* are we done? */ - if (in->lastpacket == in->numpackets) { - if (!skb || !in->skb) { - BUGMSG(D_NORMAL, "?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n", - skb, in->skb); - } else { - in->skb = NULL; - in->lastpacket = in->numpackets = 0; - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = arcnetA_type_trans(skb, dev); - netif_rx(skb); - } - } - } -} - - -/**************************************************************************** - * * - * Miscellaneous routines * - * * - ****************************************************************************/ - -/* Get the current statistics. This may be called with the card open or - * closed. - */ - -static struct net_device_stats *arcnet_get_stats(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - return &lp->stats; -} - - -/* Create the ARCnet ClientData header for an arbitrary protocol layer - - * saddr=NULL means use device source address (always will anyway) - * daddr=NULL means leave destination address (eg unresolved arp) - */ -static int arcnetA_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - struct ClientData *head = (struct ClientData *) - skb_push(skb, dev->hard_header_len); - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - BUGMSG(D_DURING, "create header from %d to %d; protocol %d (%Xh); size %u.\n", - saddr ? *(u_char *) saddr : -1, - daddr ? *(u_char *) daddr : -1, - type, type, len); - - /* set the protocol ID according to RFC1201 */ - switch (type) { - case ETH_P_IP: - head->protocol_id = ARC_P_IP; - break; - case ETH_P_ARP: - head->protocol_id = ARC_P_ARP; - break; - case ETH_P_RARP: - head->protocol_id = ARC_P_RARP; - break; - case ETH_P_IPX: - case ETH_P_802_3: - case ETH_P_802_2: - head->protocol_id = ARC_P_IPX; - break; - case ETH_P_ATALK: - head->protocol_id = ARC_P_ATALK; - break; - default: - BUGMSG(D_NORMAL, "I don't understand protocol %d (%Xh)\n", - type, type); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - return 0; - } - - /* - * Set the source hardware address. - * - * This is pretty pointless for most purposes, but it can help - * in debugging. saddr is stored in the ClientData header and - * removed before sending the packet (since ARCnet does not allow - * us to change the source address in the actual packet sent) - */ - if (saddr) - head->saddr = ((u_char *) saddr)[0]; - else - head->saddr = ((u_char *) (dev->dev_addr))[0]; - - head->split_flag = 0; /* split packets are done elsewhere */ - head->sequence = 0; /* so are sequence numbers */ - - /* supposedly if daddr is NULL, we should ignore it... */ - if (daddr) { - head->daddr = ((u_char *) daddr)[0]; - return dev->hard_header_len; - } else - head->daddr = 0; /* better fill one in anyway */ - - return -dev->hard_header_len; -} - - -/* Rebuild the ARCnet ClientData header. This is called after an ARP - * (or in future other address resolution) has completed on this - * sk_buff. We now let ARP fill in the other fields. - */ -static int arcnetA_rebuild_header(struct sk_buff *skb) -{ - struct ClientData *head = (struct ClientData *) skb->data; - struct net_device *dev = skb->dev; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); -#ifdef CONFIG_INET - int status; -#endif - - /* - * Only ARP and IP are currently supported - * - * FIXME: Anyone want to spec IPv6 over ARCnet ? - */ - - if (head->protocol_id != ARC_P_IP) { - BUGMSG(D_NORMAL, "I don't understand protocol type %d (%Xh) addresses!\n", - head->protocol_id, head->protocol_id); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - head->daddr = 0; - /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len); */ - return 0; - } - /* - * Try to get ARP to resolve the header. - */ -#ifdef CONFIG_INET - BUGMSG(D_DURING, "rebuild header from %d to %d; protocol %Xh\n", - head->saddr, head->daddr, head->protocol_id); - status = arp_find(&(head->daddr), skb) ? 1 : 0; - BUGMSG(D_DURING, " rebuilt: from %d to %d; protocol %Xh\n", - head->saddr, head->daddr, head->protocol_id); - return status; -#else - return 0; -#endif -} - - -/* Determine a packet's protocol ID. - - * With ARCnet we have to convert everything to Ethernet-style stuff. - */ -static unsigned short arcnetA_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct ClientData *head; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* Pull off the arcnet header. */ - skb->mac.raw = skb->data; - skb_pull(skb, dev->hard_header_len); - head = (struct ClientData *) skb->mac.raw; - - if (head->daddr == 0) - skb->pkt_type = PACKET_BROADCAST; - else if (dev->flags & IFF_PROMISC) { - /* if we're not sending to ourselves :) */ - if (head->daddr != dev->dev_addr[0]) - skb->pkt_type = PACKET_OTHERHOST; - } - /* now return the protocol number */ - switch (head->protocol_id) { - case ARC_P_IP: - return htons(ETH_P_IP); - case ARC_P_ARP: - return htons(ETH_P_ARP); - case ARC_P_RARP: - return htons(ETH_P_RARP); - - case ARC_P_IPX: - case ARC_P_NOVELL_EC: - return htons(ETH_P_802_3); - default: - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - return 0; - } - - return htons(ETH_P_IP); -} - - -#ifdef CONFIG_ARCNET_ETH -/**************************************************************************** - * * - * Ethernet-Encap Support * - * * - ****************************************************************************/ - -/* Initialize the arc0e device. - */ -static int arcnetE_init(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - ether_setup(dev); /* we're emulating ether here, not ARCnet */ - dev->dev_addr[0] = 0; - dev->dev_addr[5] = lp->stationid; - dev->mtu = 512 - sizeof(struct archdr) - dev->hard_header_len - 1; - dev->open = arcnetE_open_close; - dev->stop = arcnetE_open_close; - dev->hard_start_xmit = arcnetE_send_packet; - - return 0; -} - - -/* Bring up/down the arc0e device - we don't actually have to do anything, - * since our parent arc0 handles the card I/O itself. - */ -static int arcnetE_open_close(struct net_device *dev) -{ - return 0; -} - - -/* Called by the kernel in order to transmit an ethernet-type packet. - */ -static int arcnetE_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int bad, oldmask = 0; - u_char daddr; - short offset, length = skb->len + 1; - u_char proto = ARC_P_ETHER; - - lp->intx++; - - oldmask |= lp->intmask; - lp->intmask = 0; - SETMASK; - - bad = arcnet_send_packet_bad(skb, dev); - if (bad) { - lp->intx--; - lp->intmask = oldmask; - SETMASK; - return bad; - } - /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ - - lp->intmask = oldmask; - SETMASK; - - if (length > XMTU) { - BUGMSG(D_NORMAL, "MTU must be <= 493 for ethernet encap (length=%d).\n", - length); - BUGMSG(D_NORMAL, "transmit aborted.\n"); - - dev_kfree_skb(skb); - lp->intx--; - return 0; - } - BUGMSG(D_DURING, "starting tx sequence...\n"); - - /* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */ - if (((struct ethhdr *) (skb->data))->h_dest[0] == 0xFF) - daddr = 0; - else - daddr = ((struct ethhdr *) (skb->data))->h_dest[5]; - - /* load packet into shared memory */ - offset = 512 - length; - if (length > MTU) { /* long/exception packet */ - if (length < MinTU) - offset -= 3; - } else { /* short packet */ - offset -= 256; - } - - BUGMSG(D_DURING, " length=%Xh, offset=%Xh\n", - length, offset); - - (*lp->prepare_tx) (dev, &proto, 1, skb->data, length - 1, daddr, 0, - offset); - - dev_kfree_skb(skb); - - if (arcnet_go_tx(dev, 1)) { - /* inform upper layers */ - arcnet_tx_done(lp->adev, lp); - } - dev->trans_start = jiffies; - lp->intx--; - - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; - - return 0; -} - - -/* Packet receiver for ethernet-encap packets. - */ -static void arcnetE_rx(struct net_device *dev, u_char * arcsoft, - int length, u_char saddr, u_char daddr) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - struct sk_buff *skb; - - BUGMSG(D_DURING, "it's an ethernet-encap packet (length=%d)\n", - length); - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - skb_put(skb, length); - - skb->dev = dev; - - memcpy(skb->data, (u_char *) arcsoft + 1, length - 1); - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); -} - -#endif /* CONFIG_ARCNET_ETH */ - -#ifdef CONFIG_ARCNET_1051 -/**************************************************************************** - * * - * RFC1051 Support * - * * - ****************************************************************************/ - -/* Initialize the arc0s device. - */ -static int arcnetS_init(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->dev_addr[0] = lp->stationid; - dev->hard_header_len = sizeof(struct S_ClientData); - dev->mtu = 512 - sizeof(struct archdr) - dev->hard_header_len - + S_EXTRA_CLIENTDATA; - dev->open = arcnetS_open_close; - dev->stop = arcnetS_open_close; - dev->hard_start_xmit = arcnetS_send_packet; - dev->hard_header = arcnetS_header; - dev->rebuild_header = arcnetS_rebuild_header; - - return 0; -} - - -/* Bring up/down the arc0s device - we don't actually have to do anything, - * since our parent arc0 handles the card I/O itself. - */ -static int arcnetS_open_close(struct net_device *dev) -{ - return 0; -} - - -/* Called by the kernel in order to transmit an RFC1051-type packet. - */ -static int arcnetS_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int bad, length; - struct S_ClientData *hdr = (struct S_ClientData *) skb->data; - - lp->intx++; - - bad = arcnet_send_packet_bad(skb, dev); - if (bad) { - lp->intx--; - return bad; - } - /* arcnet_send_packet_pad has already set tbusy - don't bother here. */ - - length = 1 < skb->len ? skb->len : 1; - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "tx"); - - /* fits in one packet? */ - if (length - S_EXTRA_CLIENTDATA <= XMTU) { - (*lp->prepare_tx) (dev, - skb->data + S_EXTRA_CLIENTDATA, - sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA, - skb->data + sizeof(struct S_ClientData), - length - sizeof(struct S_ClientData), - hdr->daddr, 0, 0); - - /* done right away */ - dev_kfree_skb(skb); - - if (arcnet_go_tx(dev, 1)) { - /* inform upper layers */ - arcnet_tx_done(lp->adev, lp); - } - } else { /* too big for one - not accepted */ - BUGMSG(D_NORMAL, "packet too long (length=%d)\n", - length); - dev_kfree_skb(skb); - lp->stats.tx_dropped++; - arcnet_tx_done(lp->adev, lp); - } - - dev->trans_start = jiffies; - lp->intx--; - - /* make sure we didn't ignore a TX IRQ while we were in here */ - lp->intmask |= TXFREEflag; - SETMASK; - - return 0; -} - - -/* Packet receiver for RFC1051 packets; - */ -static void arcnetS_rx(struct net_device *dev, u_char * buf, - int length, u_char saddr, u_char daddr) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - struct sk_buff *skb; - struct S_ClientData *arcsoft, *soft; - - arcsoft = (struct S_ClientData *) (buf - S_EXTRA_CLIENTDATA); - length += S_EXTRA_CLIENTDATA; - - BUGMSG(D_DURING, "it's an RFC1051 packet (length=%d)\n", - length); - - { /* was "if not split" in A protocol, S is never split */ - - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - BUGMSG(D_NORMAL, "Memory squeeze, dropping packet.\n"); - lp->stats.rx_dropped++; - return; - } - soft = (struct S_ClientData *) skb->data; - skb_put(skb, length); - - memcpy((u_char *) soft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA, - (u_char *) arcsoft + sizeof(struct S_ClientData) - S_EXTRA_CLIENTDATA, - length - sizeof(struct S_ClientData) + S_EXTRA_CLIENTDATA); - soft->protocol_id = arcsoft->protocol_id; - soft->daddr = daddr; - soft->saddr = saddr; - skb->dev = dev; /* is already lp->sdev */ - - BUGLVL(D_SKB) arcnet_dump_skb(dev, skb, "rx"); - - lp->stats.rx_bytes += skb->len; - skb->protocol = arcnetS_type_trans(skb, dev); - netif_rx(skb); - } -} - - -/* Create the ARCnet ClientData header for an arbitrary protocol layer - - * saddr=NULL means use device source address (always will anyway) - * daddr=NULL means leave destination address (eg unresolved arp) - */ -static int arcnetS_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - struct S_ClientData *head = (struct S_ClientData *) - skb_push(skb, dev->hard_header_len); - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* set the protocol ID according to RFC1051 */ - switch (type) { - case ETH_P_IP: - head->protocol_id = ARC_P_IP_RFC1051; - BUGMSG(D_DURING, "S_header: IP_RFC1051 packet.\n"); - break; - case ETH_P_ARP: - head->protocol_id = ARC_P_ARP_RFC1051; - BUGMSG(D_DURING, "S_header: ARP_RFC1051 packet.\n"); - break; - default: - BUGMSG(D_NORMAL, "I don't understand protocol %d (%Xh)\n", - type, type); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - return 0; - } - - /* - * Set the source hardware address. - * - * This is pretty pointless for most purposes, but it can help - * in debugging. saddr is stored in the ClientData header and - * removed before sending the packet (since ARCnet does not allow - * us to change the source address in the actual packet sent) - */ - if (saddr) - head->saddr = ((u_char *) saddr)[0]; - else - head->saddr = ((u_char *) (dev->dev_addr))[0]; - - /* supposedly if daddr is NULL, we should ignore it... */ - if (daddr) { - head->daddr = ((u_char *) daddr)[0]; - return dev->hard_header_len; - } else - head->daddr = 0; /* better fill one in anyway */ - - return -dev->hard_header_len; -} - - -/* Rebuild the ARCnet ClientData header. This is called after an ARP - * (or in future other address resolution) has completed on this - * sk_buff. We now let ARP fill in the other fields. - */ -static int arcnetS_rebuild_header(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct S_ClientData *head = (struct S_ClientData *) skb->data; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* - * Only ARP and IP are currently supported - */ - - if (head->protocol_id != ARC_P_IP_RFC1051) { - BUGMSG(D_NORMAL, "I don't understand protocol type %d (%Xh) addresses!\n", - head->protocol_id, head->protocol_id); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - head->daddr = 0; - /*memcpy(eth->h_source, dev->dev_addr, dev->addr_len); */ - return 0; - } - /* - * Try to get ARP to resolve the header. - */ -#ifdef CONFIG_INET - return arp_find(&(head->daddr), skb) ? 1 : 0; -#else - return 0; -#endif -} - - -/* Determine a packet's protocol ID. - - * With ARCnet we have to convert everything to Ethernet-style stuff. - */ -unsigned short arcnetS_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct S_ClientData *head; - struct arcnet_local *lp = (struct arcnet_local *) (dev->priv); - - /* Pull off the arcnet header. */ - skb->mac.raw = skb->data; - skb_pull(skb, dev->hard_header_len); - head = (struct S_ClientData *) skb->mac.raw; - - if (head->daddr == 0) - skb->pkt_type = PACKET_BROADCAST; - else if (dev->flags & IFF_PROMISC) { - /* if we're not sending to ourselves :) */ - if (head->daddr != dev->dev_addr[0]) - skb->pkt_type = PACKET_OTHERHOST; - } - /* now return the protocol number */ - switch (head->protocol_id) { - case ARC_P_IP_RFC1051: - return htons(ETH_P_IP); - case ARC_P_ARP_RFC1051: - return htons(ETH_P_ARP); - case ARC_P_ATALK: - return htons(ETH_P_ATALK); /* untested appletalk */ - default: - lp->stats.rx_errors++; - lp->stats.rx_crc_errors++; - return 0; - } - - return htons(ETH_P_IP); -} - -#endif /* CONFIG_ARCNET_1051 */ - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - -#ifdef MODULE - -void cleanup_module(void) -{ - printk("Generic arcnet support removed.\n"); -} - -void arcnet_use_count(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - -#else - -void arcnet_use_count(int open) -{ -} - -struct net_device arcnet_devs[MAX_ARCNET_DEVS]; -int arcnet_num_devs = 0; -char arcnet_dev_names[MAX_ARCNET_DEVS][10]; - -int __init arcnet_init(void) -{ - int c; - - init_module(); - - /* Don't register_netdev here. The chain hasn't been initialised. */ - -#ifdef CONFIG_ARCNET_COM90xx - if ((!com90xx_explicit) && arcnet_num_devs < MAX_ARCNET_DEVS) { - arcnet_devs[arcnet_num_devs].init = arc90xx_probe; - arcnet_devs[arcnet_num_devs].name = - (char *) &arcnet_dev_names[arcnet_num_devs]; - arcnet_num_devs++; - } -#endif - - if (!arcnet_num_devs) { - printk("Don't forget to load the chipset driver.\n"); - return 0; - } - /* Link into the device chain */ - - /* Q: Should we put ourselves at the beginning or the end of the chain? */ - /* Probably the end, because we're not so fast, but... */ - - for (c = 0; c < (arcnet_num_devs - 1); c++) - arcnet_devs[c].next = &arcnet_devs[c + 1]; - - write_lock_bh(&dev_base_lock); - arcnet_devs[c].next = dev_base; - dev_base = &arcnet_devs[0]; - write_unlock_bh(&dev_base_lock); - - /* Give names to those without them */ - - for (c = 0; c < arcnet_num_devs; c++) - if (!arcnet_dev_names[c][0]) - arcnet_makename((char *) &arcnet_dev_names[c]); - return 0; -} - -#endif /* MODULE */ - - -#ifdef MODULE -int init_module(void) -#else -static int __init init_module(void) -#endif -{ -#ifdef ALPHA_WARNING - BUGLVL(D_EXTRA) { - printk("arcnet: ***\n"); - printk("arcnet: * Read arcnet.txt for important release notes!\n"); - printk("arcnet: *\n"); - printk("arcnet: * This is an ALPHA version! (Last stable release: v2.56) E-mail me if\n"); - printk("arcnet: * you have any questions, comments, or bug reports.\n"); - printk("arcnet: ***\n"); - } -#endif - - printk("%sAvailable protocols: ARCnet RFC1201" -#ifdef CONFIG_ARCNET_ETH - ", Ethernet-Encap" -#endif -#ifdef CONFIG_ARCNET_1051 - ", ARCnet RFC1051" -#endif -#ifdef MODULE - ".\nDon't forget to load the chipset driver" -#endif - ".\n", version); - return 0; -} - - -void arcnet_makename(char *device) -{ - struct net_device *dev; - int arcnum; - - arcnum = 0; - for (;;) { - sprintf(device, "arc%d", arcnum); - read_lock_bh(&dev_base_lock); - for (dev = dev_base; dev; dev = dev->next) - if (dev->name != device && !strcmp(dev->name, device)) - break; - read_unlock_bh(&dev_base_lock); - if (!dev) - return; - arcnum++; - } -} diff -u --recursive --new-file v2.3.35/linux/drivers/net/com20020.c linux/drivers/net/com20020.c --- v2.3.35/linux/drivers/net/com20020.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/com20020.c Wed Dec 31 16:00:00 1969 @@ -1,1091 +0,0 @@ -/* $Id: com20020.c,v 1.6 1997/11/09 11:04:58 mj Exp $ - - Written 1997 by David Woodhouse - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** -*/ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -/* Internal function declarations */ - -static int arc20020_probe(struct net_device *dev); -static void arc20020_rx(struct net_device *dev,int recbuf); -static int arc20020_found(struct net_device *dev,int ioaddr,int airq); -static void arc20020_inthandler (struct net_device *dev); -static int arc20020_reset (struct net_device *dev, int reset_delay); -static void arc20020_setmask (struct net_device *dev, u_char mask); -static void arc20020_command (struct net_device *dev, u_char command); -static u_char arc20020_status (struct net_device *dev); -static void arc20020_en_dis_able_TX (struct net_device *dev, int enable); -static void arc20020_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset); -static void arc20020_openclose(int open); -static void arc20020_set_mc_list(struct net_device *dev); -static u_char get_buffer_byte (struct net_device *dev, unsigned offset); -static void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum); -static void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); -static void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); - - -/* Module parameters */ - -#ifdef MODULE -static int node=0; -static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq=0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ -static int timeout=3; -static int backplane=0; -static int clock=0; - -MODULE_PARM(node,"i"); -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -MODULE_PARM(timeout,"i"); -MODULE_PARM(backplane,"i"); -MODULE_PARM(clock,"i"); -#else -void __init com20020_setup (char *str, int *ints); -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - - -/* Handy defines for ARCnet specific stuff */ - -static char *clockrates[]={"2.5 Mb/s","1.25Mb/s","625 Kb/s","312.5 Kb/s", - "156.25 Kb/s", "Reserved", "Reserved", - "Reserved"}; - - -/* The number of low I/O ports used by the card. */ -#define ARCNET_TOTAL_SIZE 9 - -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _CONFIG (ioaddr+6) /* Configuration register */ -#define _DIAGSTAT (ioaddr+1) /* Diagnostic status register */ -#define _MEMDATA (ioaddr+4) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+2) /* Control registers for said */ -#define _ADDR_LO (ioaddr+3) - -#define RDDATAflag 0x80 /* Next access is a read/~write */ -#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */ - -#define TXENflag 0x20 /* Enable TX (in CONFIG register) */ - -#define PROMISCflag 0x10 /* Enable RCV_ALL (in SETUP register) */ - -#define REGTENTID (lp->config &= ~3); -#define REGNID (lp->config = (lp->config&~2)|1); -#define REGSETUP (lp->config = (lp->config&~1)|2); -#define REGNXTID (lp->config |= 3); - -#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \ - udelay(5); \ - outb(lp->config , _CONFIG); \ - } -#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \ - udelay(5); \ - outb(0x18 , _CONFIG); \ - } - -#define ARCSTATUS inb(_STATUS) -#define ACOMMAND(cmd) outb((cmd),_COMMAND) -#define AINTMASK(msk) outb((msk),_INTMASK) -#define SETCONF outb((lp->config),_CONFIG) - - -/**************************************************************************** - * * - * IO-mapped operation routines * - * * - ****************************************************************************/ - -u_char get_buffer_byte (struct net_device *dev, unsigned offset) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8 | RDDATAflag, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - return inb(_MEMDATA); -} - -void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - outb(datum, _MEMDATA); -} - - -#undef ONE_AT_A_TIME_TX -#undef ONE_AT_A_TIME_RX - -void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag | RDDATAflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_RX - *(dest++) = get_buffer_byte(dev,offset++); -#else - *(dest++) = inb (_MEMDATA); -#endif -} - -void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_TX - put_buffer_byte(dev,offset++,*(dest++)); -#else - outb (*(dest++), _MEMDATA); -#endif -} - - -static const char *version = - "com20020.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - - -/* We cannot probe for an IO mapped card either, although we can check that - * it's where we were told it was, and even autoirq - */ - -int __init arc20020_probe(struct net_device *dev) -{ - int ioaddr=dev->base_addr,status,delayval; - unsigned long airqmask; - - BUGLVL(D_NORMAL) printk(version); - - if (ioaddr<0x200) - { - BUGMSG(D_NORMAL,"No autoprobe for IO mapped cards; you " - "must specify the base address!\n"); - return -ENODEV; - } - - if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) - { - BUGMSG(D_NORMAL,"IO region %xh-%xh already allocated.\n", - ioaddr,ioaddr+ARCNET_TOTAL_SIZE-1); - return -ENXIO; - } - - if (ARCSTATUS == 0xFF) - { - BUGMSG(D_NORMAL,"IO address %x empty\n",ioaddr); - return -ENODEV; - } - - ARCRESET0; - JIFFER(RESETtime); - - status=ARCSTATUS; - - if ((status & 0x99) - != (NORXflag|TXFREEflag|RESETflag)) - { - BUGMSG(D_NORMAL,"Status invalid (%Xh).\n",status); - return -ENODEV; - } - - BUGMSG(D_INIT_REASONS,"Status after reset: %X\n",status); - - /* Enable TX */ - outb(0x39,_CONFIG); - outb(inb(ioaddr+8),ioaddr+7); - - ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear); - - BUGMSG(D_INIT_REASONS,"Status after reset acknowledged: %X\n",status); - - /* Reset card. */ - - outb(0x98,_CONFIG); - udelay(5); - outb(0x18,_CONFIG); - - /* Read first loc'n of memory */ - - outb(0 | RDDATAflag | AUTOINCflag ,_ADDR_HI); - outb(0,_ADDR_LO); - - if ((status=inb(_MEMDATA)) != 0xd1) - { - BUGMSG(D_NORMAL,"Signature byte not found.\n"); - return -ENODEV; - } - - if (!dev->irq) - { - /* if we do this, we're sure to get an IRQ since the - * card has just reset and the NORXflag is on until - * we tell it to start receiving. - */ - BUGMSG(D_INIT_REASONS, "intmask was %d:\n",inb(_INTMASK)); - outb(0, _INTMASK); - airqmask = probe_irq_on(); - outb(NORXflag,_INTMASK); - udelay(1); - outb(0,_INTMASK); - dev->irq = probe_irq_off(airqmask); - - if (dev->irq<=0) - { - BUGMSG(D_INIT_REASONS,"Autoprobe IRQ failed first time\n"); - airqmask = probe_irq_on(); - outb(NORXflag,_INTMASK); - udelay(5); - outb(0,_INTMASK); - dev->irq = probe_irq_off(airqmask); - if (dev->irq<=0) - { - BUGMSG(D_NORMAL,"Autoprobe IRQ failed.\n"); - return -ENODEV; - } - } - } - - return arc20020_found(dev,dev->base_addr,dev->irq); -} - - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -int __init arc20020_found(struct net_device *dev,int ioaddr,int airq) -{ - struct arcnet_local *lp; - - /* reserve the irq */ - if (request_irq(airq,&arcnet_interrupt,0,"arcnet (COM20020)",dev)) - { - BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq); - return -ENODEV; - } - dev->irq=airq; - - /* reserve the I/O region - guaranteed to work by check_region */ - request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM20020)"); - dev->base_addr=ioaddr; - - dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) - { - free_irq(airq,dev); - release_region(ioaddr,ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - - memset(dev->priv,0,sizeof(struct arcnet_local)); - lp=(struct arcnet_local *)(dev->priv); - lp->card_type = ARC_20020; - lp->card_type_str = "COM 20020"; - - lp->arcnet_reset=arc20020_reset; - lp->asetmask=arc20020_setmask; - lp->astatus=arc20020_status; - lp->acommand=arc20020_command; - lp->en_dis_able_TX=arc20020_en_dis_able_TX; - lp->openclose_device=arc20020_openclose; - lp->prepare_tx=arc20020_prepare_tx; - lp->inthandler=arc20020_inthandler; - - dev->set_multicast_list = arc20020_set_mc_list; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu=1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len=sizeof(struct ClientData); - lp->sequence=1; - lp->recbuf=0; - - BUGMSG(D_DURING,"ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING,"HardHeader size is %d.\n", - sizeof(struct archdr)); - - /* get and check the station ID from offset 1 in shmem */ - lp->timeout = dev->dev_addr[3] & 3; dev->dev_addr[3]=0; - lp->backplane =dev->dev_addr[1] & 1; dev->dev_addr[1]=0; - lp->setup = (dev->dev_addr[2] & 7) << 1; dev->dev_addr[2]=0; - - if (dev->dev_addr[0]) - lp->stationid=dev->dev_addr[0]; - else - lp->stationid=inb(ioaddr+8); /* FIX ME - We should check that - this is valid before using it */ - lp->config = 0x21 | (lp->timeout << 3) | (lp->backplane << 2); - /* Default 0x38 + register: Node ID */ - SETCONF; - outb(lp->stationid, ioaddr+7); - - REGSETUP; - SETCONF; - outb(lp->setup, ioaddr+7); - - if (!lp->stationid) - BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid==255) - BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0]=lp->stationid; - - BUGMSG(D_NORMAL,"ARCnet COM20020: station %02Xh found at %03lXh, IRQ %d.\n", - lp->stationid, dev->base_addr,dev->irq); - - if (lp->backplane) - BUGMSG (D_NORMAL, "Using backplane mode.\n"); - - if (lp->timeout != 3) - BUGMSG (D_NORMAL, "Using Extended Timeout value of %d.\n",lp->timeout); - if (lp->setup) - { - BUGMSG (D_NORMAL, "Using CKP %d - Data rate %s.\n", - lp->setup >>1,clockrates[lp->setup >> 1] ); - } - return 0; -} - - -/**************************************************************************** - * * - * Utility routines * - * * - ****************************************************************************/ - -/* Do a hardware reset on the card, and set up necessary registers. - * - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arc20020_reset(struct net_device *dev,int reset_delay) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - short ioaddr=dev->base_addr; - int delayval,recbuf=lp->recbuf; - - if (reset_delay==3) - { - ARCRESET; - return 0; - } - - /* no IRQ's, please! */ - lp->intmask=0; - SETMASK; - - BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", - dev->name,ARCSTATUS); - - lp->config = 0x20 | (lp->timeout<<3) | (lp->backplane<<2); - /* power-up defaults */ - SETCONF; - - if (reset_delay) - { - /* reset the card */ - ARCRESET; - JIFFER(RESETtime); - } - - ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd|CONFIGclear); - - /* verify that the ARCnet signature byte is present */ - - if (get_buffer_byte(dev,0) != TESTvalue) - { - BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n"); - return 1; - } - - /* clear out status variables */ - recbuf=lp->recbuf=0; - lp->txbuf=2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd|EXTconf); - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask|=NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask|=RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -/* Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, and do - * best-effort filtering. - * FIX ME - do multicast stuff, not just promiscuous. - */ -static void -arc20020_set_mc_list(struct net_device *dev) -{ - struct arcnet_local *lp=dev->priv; - int ioaddr=dev->base_addr; - - if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) - { /* Enable promiscuous mode */ - if (!(lp->setup & PROMISCflag)) - BUGMSG(D_NORMAL, "Setting promiscuous flag...\n"); - REGSETUP; - SETCONF; - lp->setup|=PROMISCflag; - outb(lp->setup,ioaddr+7); - } else - /* Disable promiscuous mode, use normal mode */ - { - if ((lp->setup & PROMISCflag)) - BUGMSG(D_NORMAL, "Resetting promiscuous flag...\n"); - REGSETUP; - SETCONF; - lp->setup &= ~PROMISCflag; - outb(lp->setup,ioaddr+7); - } -} - - -static void arc20020_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - -static void arc20020_en_dis_able_TX(struct net_device *dev, int enable) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr; - - lp->config=enable?(lp->config | TXENflag):(lp->config & ~TXENflag); - SETCONF; -} - - -static void arc20020_setmask(struct net_device *dev, u_char mask) -{ - short ioaddr=dev->base_addr; - - AINTMASK(mask); -} - - -static u_char arc20020_status(struct net_device *dev) -{ - short ioaddr=dev->base_addr; - - return ARCSTATUS; -} - - -static void arc20020_command(struct net_device *dev, u_char cmd) -{ - short ioaddr=dev->base_addr; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void -arc20020_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr, status, boguscount = 3, didsomething, - dstatus; - - AINTMASK(0); - - BUGMSG(D_DURING,"in arc20020_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS,lp->intmask); - - do - { - status = ARCSTATUS; - didsomething=0; - - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) - { - BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", - status); - arc20020_reset(dev,0); - - /* all other flag values are just garbage */ - break; - } - - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) - { - int recbuf=lp->recbuf=!lp->recbuf; - int oldaddr=0; - - BUGMSG(D_DURING,"receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - if (lp->intx) - oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO); - - /* Got a packet. */ - arc20020_rx(dev,!recbuf); - - if (lp->intx) - { - outb( (oldaddr >> 8), _ADDR_HI); - outb( oldaddr & 0xff, _ADDR_LO); - } - - didsomething++; - } - - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ - if (status & lp->intmask & TXFREEflag) - { - struct Outgoing *out=&(lp->outgoing); - int was_sending=lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) lp->sending--; - - BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status,out->numsegs,out->segnum,out->skb); - - if (was_sending && !(status&TXACKflag)) - { - if (lp->lasttrans_dest != 0) - { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } - else - { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - - /* send packet if there is one */ - arcnet_go_tx(dev,0); - didsomething++; - - if (lp->intx) - { - BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS,lp->intx); - lp->in_txhandler--; - continue; - } - - if (!lp->outgoing.skb) - { - BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnumnumsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum>=out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb=NULL; - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } - else if (lp->txready && !lp->sending && !lp->intx) - { - BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev,0); - didsomething++; - } - - if ((dstatus=inb(_DIAGSTAT)) & NEWNXTIDflag) - { - REGNXTID; - SETCONF; - BUGMSG(D_EXTRA,"New NextID detected: %X\n",inb(ioaddr+7)); - } - - -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) - { - ACOMMAND(CFLAGScmd|CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh, diag status=%Xh, config=%X)\n", - status,dstatus,lp->config); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); - lp->first_recon=lp->last_recon=jiffies; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"recon: clearing counters.\n"); - } - else /* add to current RECON counter */ - { - lp->last_recon=jiffies; - lp->num_recons++; - - BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon-lp->first_recon)/HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon-lp->first_recon)<=HZ*60 - && lp->num_recons >= RECON_THRESHOLD) - { - lp->network_down=1; - BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); - } - else if (!lp->network_down - && lp->last_recon-lp->first_recon > HZ*60) - { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon=lp->last_recon; - lp->num_recons=1; - } - } - } - else if (lp->network_down && jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"cabling restored?\n"); - lp->first_recon=lp->last_recon=0; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS,boguscount); - BUGMSG(D_DURING,"\n"); - - SETMASK; /* put back interrupt mask */ - -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void -arc20020_rx(struct net_device *dev,int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr; - union ArcPacket packetbuf; - union ArcPacket *arcpacket=&packetbuf; - u_char *arcsoft; - short length,offset; - u_char daddr,saddr; - - lp->stats.rx_packets++; - - get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket); - - saddr=arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr==0) - { - BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - put_buffer_byte(dev,recbuf*512,0); - - arcpacket->hardheader.source=0; - - daddr=arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) /* Normal Packet */ - { - offset=arcpacket->hardheader.offset1; - arcsoft=&arcpacket->raw[offset]; - length=256-offset; - } - else /* ExtendedPacket or ExceptionPacket */ - { - offset=arcpacket->hardheader.offset2; - arcsoft=&arcpacket->raw[offset]; - length=512-offset; - } - - get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset); - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx"); -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void -arc20020_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ - - length+=hdrlen; - - BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr,length,data); - - put_buffer_byte(dev, lp->txbuf*512+1, daddr); - - /* load packet into shared memory */ - if (length<=MTU) /* Normal (256-byte) Packet */ - put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length); - - else if (length>=MinTU || offset) /* Extended (512-byte) Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=offset?offset:512-length); - } - else if (exceptA) /* RFC1201 Exception Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4); - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]); - put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377"); - offset+=4; - } - else /* "other" Exception packet */ - { - /* RFC1051 - set 4 trailing bytes to 0 */ - - put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0"); - - /* now round up to MinTU */ - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU); - } - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr); - put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data); - - BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n", - daddr,length); - - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static struct net_device *cards[16]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; - - -int init_module(void) -{ - struct net_device *dev; - - cards[0]=dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - memset(dev, 0, sizeof(struct net_device)); - - dev->name=(char *)kmalloc(9, GFP_KERNEL); - if (!dev->name) - { - kfree(dev); - return -ENOMEM; - } - dev->init=arc20020_probe; - - if (device) - strcpy(dev->name,device); - else arcnet_makename(dev->name); - - if (node && node != 0xff) - dev->dev_addr[0]=node; - - if (backplane) dev->dev_addr[1]=backplane?1:0; - if (clock) dev->dev_addr[2]=clock&7; - dev->dev_addr[3]=timeout&3; - - dev->base_addr=io; - dev->irq=irq; - - if (dev->irq==2) dev->irq=9; - - if (register_netdev(dev) != 0) - return -EIO; - - /* Increase use count of arcnet.o */ - arcnet_use_count(1); - - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev=cards[0]; - int ioaddr=dev->base_addr; - - if (dev->start) (*dev->stop)(dev); - - /* Flush TX and disable RX */ - if (ioaddr) - { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - } - - if (dev->irq) - { - free_irq(dev->irq,dev); - } - - if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE); - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - - /* Decrease use count of arcnet.o */ - arcnet_use_count(0); -} - -#else - -void __init com20020_setup (char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) - { - printk("com20020: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - - dev=&arcnet_devs[arcnet_num_devs]; - - if (ints[0] < 1) - { - printk("com20020: You must give an IO address.\n"); - return; - } - - dev->dev_addr[3]=3; - dev->init=arc20020_probe; - - switch(ints[0]) - { - case 7: /* ERROR */ - printk("com20020: Too many arguments.\n"); - - case 6: /* Timeout */ - dev->dev_addr[3]=(u_char)ints[6]; - - case 5: /* CKP value */ - dev->dev_addr[2]=(u_char)ints[5]; - - case 4: /* Backplane flag */ - dev->dev_addr[1]=(u_char)ints[4]; - - case 3: /* Node ID */ - dev->dev_addr[0]=(u_char)ints[3]; - - case 2: /* IRQ */ - dev->irq=ints[2]; - - case 1: /* IO address */ - dev->base_addr=ints[1]; - } - - dev->name = (char *)&arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} -#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/com90io.c linux/drivers/net/com90io.c --- v2.3.35/linux/drivers/net/com90io.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/com90io.c Wed Dec 31 16:00:00 1969 @@ -1,958 +0,0 @@ -/* $Id: com90io.c,v 1.6 1997/11/09 11:04:59 mj Exp $ - - Written 1997 by David Woodhouse - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** -*/ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -/* Internal function declarations */ - -static int arc90io_probe(struct net_device *dev); -static void arc90io_rx(struct net_device *dev,int recbuf); -static int arc90io_found(struct net_device *dev,int ioaddr,int airq); -static void arc90io_inthandler (struct net_device *dev); -static int arc90io_reset (struct net_device *dev, int reset_delay); -static void arc90io_setmask (struct net_device *dev, u_char mask); -static void arc90io_command (struct net_device *dev, u_char command); -static u_char arc90io_status (struct net_device *dev); -static void arc90io_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset); -static void arc90io_openclose(int open); - -static u_char get_buffer_byte (struct net_device *dev, unsigned offset); -static void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum); -static void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); -static void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest); - - -/* Module parameters */ - -#ifdef MODULE -static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq=0; /* or use the insmod io= irq= shmem= options */ -static char *device; /* use eg. device="arc1" to change name */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(device, "s"); -#else -void __init com90io_setup (char *str, int *ints); -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - - -/* Handy defines for ARCnet specific stuff */ - -/* The number of low I/O ports used by the card. */ -#define ARCNET_TOTAL_SIZE 16 - -/* COM 9026 controller chip --> ARCnet register addresses */ -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _RESET (ioaddr+8) /* software reset (on read) */ -#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+15) /* Control registers for said */ -#define _ADDR_LO (ioaddr+14) -#define _CONFIG (ioaddr+2) /* Configuration register */ - -#define ARCSTATUS inb(_STATUS) -#define ACOMMAND(cmd) outb((cmd),_COMMAND) -#define AINTMASK(msk) outb((msk),_INTMASK) - -#define ARCRESET inb(_RESET) - -#define SETCONF outb((lp->config),_CONFIG) - - -/**************************************************************************** - * * - * IO-mapped operation routines * - * * - ****************************************************************************/ - -u_char get_buffer_byte (struct net_device *dev, unsigned offset) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - return inb(_MEMDATA); -} - -void put_buffer_byte (struct net_device *dev, unsigned offset, u_char datum) -{ - int ioaddr=dev->base_addr; - - outb(offset >> 8, _ADDR_HI); - outb(offset & 0xff, _ADDR_LO); - - outb(datum, _MEMDATA); -} - - -#undef ONE_AT_A_TIME_TX -#undef ONE_AT_A_TIME_RX - -void get_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_RX - *(dest++) = get_buffer_byte(dev,offset++); -#else - *(dest++) = inb (_MEMDATA); -#endif -} - -void put_whole_buffer (struct net_device *dev, unsigned offset, unsigned length, char *dest) -{ - int ioaddr=dev->base_addr; - - outb( (offset >> 8) | AUTOINCflag, _ADDR_HI); - outb( offset & 0xff, _ADDR_LO); - - while (length--) -#ifdef ONE_AT_A_TIME_TX - put_buffer_byte(dev,offset++,*(dest++)); -#else - outb (*(dest++), _MEMDATA); -#endif -} - - -static const char *version = - "com90io.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - -/* We cannot probe for an IO mapped card either, although we can check that - * it's where we were told it was, and even autoirq - */ - -int __init arc90io_probe(struct net_device *dev) -{ - int ioaddr=dev->base_addr,status,delayval; - unsigned long airqmask; - - BUGLVL(D_NORMAL) printk(version); - - if (ioaddr<0x200) - { - BUGMSG(D_NORMAL,"No autoprobe for IO mapped cards; you " - "must specify the base address!\n"); - return -ENODEV; - } - - if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) - { - BUGMSG(D_INIT_REASONS,"IO check_region %x-%x failed.\n", - ioaddr,ioaddr+ARCNET_TOTAL_SIZE-1); - return -ENXIO; - } - - if (ARCSTATUS == 0xFF) - { - BUGMSG(D_INIT_REASONS,"IO address %x empty\n",ioaddr); - return -ENODEV; - } - - ARCRESET; - JIFFER(RESETtime); - - status=ARCSTATUS; - - if ((status & 0x9D) - != (NORXflag|RECONflag|TXFREEflag|RESETflag)) - { - BUGMSG(D_INIT_REASONS,"Status invalid (%Xh).\n",status); - return -ENODEV; - } - - BUGMSG(D_INIT_REASONS,"Status after reset: %X\n",status); - - ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear); - - BUGMSG(D_INIT_REASONS,"Status after reset acknowledged: %X\n",status); - - status=ARCSTATUS; - - if (status & RESETflag) - { - BUGMSG(D_INIT_REASONS,"Eternal reset (status=%Xh)\n",status); - return -ENODEV; - } - - outb((0x16 | IOMAPflag) &~ENABLE16flag, _CONFIG); - - /* Read first loc'n of memory */ - - outb(AUTOINCflag ,_ADDR_HI); - outb(0,_ADDR_LO); - - if ((status=inb(_MEMDATA)) != 0xd1) - { - BUGMSG(D_INIT_REASONS,"Signature byte not found" - " (%Xh instead).\n", status); - return -ENODEV; - } - - if (!dev->irq) - { - /* if we do this, we're sure to get an IRQ since the - * card has just reset and the NORXflag is on until - * we tell it to start receiving. - */ - - airqmask = probe_irq_on(); - outb(NORXflag,_INTMASK); - udelay(1); - outb(0,_INTMASK); - dev->irq = probe_irq_off(airqmask); - - if (dev->irq<=0) - { - BUGMSG(D_INIT_REASONS,"Autoprobe IRQ failed\n"); - return -ENODEV; - } - } - - return arc90io_found(dev,dev->base_addr,dev->irq); -} - - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -int __init arc90io_found(struct net_device *dev,int ioaddr,int airq) -{ - struct arcnet_local *lp; - - /* reserve the irq */ - if (request_irq(airq,&arcnet_interrupt,0,"arcnet (COM90xx-IO)",dev)) - { - BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq); - return -ENODEV; - } - dev->irq=airq; - - /* reserve the I/O region - guaranteed to work by check_region */ - request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM90xx-IO)"); - dev->base_addr=ioaddr; - - dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) - { - free_irq(airq,dev); - release_region(ioaddr,ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - - memset(dev->priv,0,sizeof(struct arcnet_local)); - lp=(struct arcnet_local *)(dev->priv); - lp->card_type = ARC_90xx_IO; - lp->card_type_str = "COM 90xx (IO)"; - - lp->arcnet_reset=arc90io_reset; - lp->asetmask=arc90io_setmask; - lp->astatus=arc90io_status; - lp->acommand=arc90io_command; - lp->openclose_device=arc90io_openclose; - lp->prepare_tx=arc90io_prepare_tx; - lp->inthandler=arc90io_inthandler; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu=1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len=sizeof(struct ClientData); - lp->sequence=1; - lp->recbuf=0; - - BUGMSG(D_DURING,"ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING,"HardHeader size is %d.\n", - sizeof(struct archdr)); - - lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag; - SETCONF; - - /* get and check the station ID from offset 1 in shmem */ - - lp->stationid = get_buffer_byte(dev,1); - - if (!lp->stationid) - BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid==255) - BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0]=lp->stationid; - - BUGMSG(D_NORMAL,"ARCnet COM90xx in IO-mapped mode: " - "station %02Xh found at %03lXh, IRQ %d.\n", - lp->stationid, - dev->base_addr,dev->irq); - - return 0; -} - - -/**************************************************************************** - * * - * Utility routines * - * * - ****************************************************************************/ - -/* Do a hardware reset on the card, and set up necessary registers. - * - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arc90io_reset(struct net_device *dev,int reset_delay) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - short ioaddr=dev->base_addr; - int delayval,recbuf=lp->recbuf; - - if (reset_delay==3) - { - ARCRESET; - return 0; - } - - /* no IRQ's, please! */ - lp->intmask=0; - SETMASK; - - BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", - dev->name,ARCSTATUS); - - /* Set the thing to IO-mapped, 8-bit mode */ - lp->config = (0x1C|IOMAPflag) & ~ENABLE16flag; - SETCONF; - - if (reset_delay) - { - /* reset the card */ - ARCRESET; - JIFFER(RESETtime); - } - - ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd|CONFIGclear); - - /* verify that the ARCnet signature byte is present */ - - if (get_buffer_byte(dev,0) != TESTvalue) - { - BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n"); - return 1; - } - - /* clear out status variables */ - recbuf=lp->recbuf=0; - lp->txbuf=2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd|EXTconf); - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask|=NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask|=RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -static void arc90io_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - -static void arc90io_setmask(struct net_device *dev, u_char mask) -{ - short ioaddr=dev->base_addr; - - AINTMASK(mask); -} - -static u_char arc90io_status(struct net_device *dev) -{ - short ioaddr=dev->base_addr; - - return ARCSTATUS; -} - -static void arc90io_command(struct net_device *dev, u_char cmd) -{ - short ioaddr=dev->base_addr; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void -arc90io_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp=(struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr, status, boguscount = 3, didsomething; - - AINTMASK(0); - - BUGMSG(D_DURING,"in arc90io_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS,lp->intmask); - - do - { - status = ARCSTATUS; - didsomething=0; - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) - { - BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", - status); - arc90io_reset(dev,0); - - /* all other flag values are just garbage */ - break; - } - - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) - { - int recbuf=lp->recbuf=!lp->recbuf; - int oldaddr=0; - - BUGMSG(D_DURING,"receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - if (lp->intx) - oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO); - - - /* Got a packet. */ - arc90io_rx(dev,!recbuf); - - - if (lp->intx) - { - outb( (oldaddr >> 8), _ADDR_HI); - outb( oldaddr & 0xff, _ADDR_LO); - } - - didsomething++; - } - - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ - if (status & lp->intmask & TXFREEflag) - { - struct Outgoing *out=&(lp->outgoing); - int was_sending=lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) lp->sending--; - - BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status,out->numsegs,out->segnum,out->skb); - - if (was_sending && !(status&TXACKflag)) - { - if (lp->lasttrans_dest != 0) - { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status,lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } - else - { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - - /* send packet if there is one */ - arcnet_go_tx(dev,0); - didsomething++; - - if (lp->intx) - { - BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS,lp->intx); - lp->in_txhandler--; - continue; - } - - if (!lp->outgoing.skb) - { - BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnumnumsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev,0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum>=out->numsegs) - { - /* transmit completed */ - out->segnum++; - if (out->skb) - { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb=NULL; - - /* inform upper layers */ - if (!lp->txready) arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } - else if (lp->txready && !lp->sending && !lp->intx) - { - BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev,0); - didsomething++; - } - -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) - { - ACOMMAND(CFLAGScmd|CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL,"Network reconfiguration detected" - " (status=%Xh, config=%X)\n", - status,lp->config); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); - lp->first_recon=lp->last_recon=jiffies; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"recon: clearing counters.\n"); - } - else /* add to current RECON counter */ - { - lp->last_recon=jiffies; - lp->num_recons++; - - BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon-lp->first_recon)/HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon-lp->first_recon)<=HZ*60 - && lp->num_recons >= RECON_THRESHOLD) - { - lp->network_down=1; - BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); - } - else if (!lp->network_down - && lp->last_recon-lp->first_recon > HZ*60) - { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon=lp->last_recon; - lp->num_recons=1; - } - } - } - else if (lp->network_down && jiffies-lp->last_recon > HZ*10) - { - if (lp->network_down) - BUGMSG(D_NORMAL,"cabling restored?\n"); - lp->first_recon=lp->last_recon=0; - lp->num_recons=lp->network_down=0; - - BUGMSG(D_DURING,"not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS,boguscount); - BUGMSG(D_DURING,"\n"); - - SETMASK; /* put back interrupt mask */ -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void -arc90io_rx(struct net_device *dev,int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - int ioaddr=dev->base_addr; - union ArcPacket packetbuf; - union ArcPacket *arcpacket=&packetbuf; - u_char *arcsoft; - short length,offset; - u_char daddr,saddr; - - lp->stats.rx_packets++; - - get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket); - - saddr=arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr==0) - { - BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - put_buffer_byte(dev,recbuf*512,0); - - arcpacket->hardheader.source=0; - - daddr=arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) /* Normal Packet */ - { - offset=arcpacket->hardheader.offset1; - arcsoft=&arcpacket->raw[offset]; - length=256-offset; - } - else /* ExtendedPacket or ExceptionPacket */ - { - offset=arcpacket->hardheader.offset2; - arcsoft=&arcpacket->raw[offset]; - length=512-offset; - } - - get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset); - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx"); -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void -arc90io_prepare_tx(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; - - lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ - - length+=hdrlen; - - BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr,length,data); - - put_buffer_byte(dev, lp->txbuf*512+1, daddr); - - /* load packet into shared memory */ - if (length<=MTU) /* Normal (256-byte) Packet */ - put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length); - - else if (length>=MinTU || offset) /* Extended (512-byte) Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=offset?offset:512-length); - } - else if (exceptA) /* RFC1201 Exception Packet */ - { - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4); - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]); - put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377"); - offset+=4; - } - else /* "other" Exception packet */ - { - /* RFC1051 - set 4 trailing bytes to 0 */ - - put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0"); - - /* now round up to MinTU */ - put_buffer_byte(dev, lp->txbuf*512+2, 0); - put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU); - } - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr); - put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data); - - BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n", - daddr,length); - - lp->lastload_dest=daddr; - lp->txready=lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static struct net_device *cards[16]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; - - -int init_module(void) -{ - struct net_device *dev=cards[0]; - - cards[0]=dev=(struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - memset(dev, 0, sizeof(struct net_device)); - - dev->name=(char *)kmalloc(9, GFP_KERNEL); - if (!dev->name) - { - kfree(dev); - return -ENOMEM; - } - dev->init=arc90io_probe; - - if (device) - strcpy(dev->name,device); - else arcnet_makename(dev->name); - - dev->base_addr=io; - dev->irq=irq; - - if (dev->irq==2) dev->irq=9; - - if (register_netdev(dev) != 0) - return -EIO; - - /* Increase use count of arcnet.o */ - arcnet_use_count(1); - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev=cards[0]; - int ioaddr=dev->base_addr; - - if (dev->start) (*dev->stop)(dev); - - /* Flush TX and disable RX */ - if (ioaddr) - { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - - /* Set the thing back to MMAP mode, in case the old - driver is loaded later */ - outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG); - } - - if (dev->irq) - { - free_irq(dev->irq,dev); - } - - if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE); - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - - /* Decrease use count of arcnet.o */ - arcnet_use_count(0); -} - -#else - -void __init com90io_setup (char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) - { - printk("com90xx IO-MAP: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - - dev=&arcnet_devs[arcnet_num_devs]; - - if (ints[0] < 1) - { - printk("com90xx IO-MAP: You must give an IO address.\n"); - return; - } - - dev->init=arc90io_probe; - - switch(ints[0]) - { - case 3: /* ERROR */ - printk("com90xx IO-MAP: Too many arguments.\n"); - - case 2: /* IRQ */ - dev->irq=ints[2]; - - case 1: /* IO address */ - dev->base_addr=ints[1]; - } - - dev->name = (char *)&arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/com90xx.c linux/drivers/net/com90xx.c --- v2.3.35/linux/drivers/net/com90xx.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/net/com90xx.c Wed Dec 31 16:00:00 1969 @@ -1,1164 +0,0 @@ -/* $Id: com90xx.c,v 1.9 1998/03/21 18:02:51 alan Exp $ - - Derived from the original arcnet.c, - Written 1994-1996 by Avery Pennarun, - which was in turn derived from skeleton.c by Donald Becker. - - ********************** - - The original copyright of skeleton.c was as follows: - - skeleton.c Written 1993 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may only be used - and distributed according to the terms of the GNU Public License as - modified by SRC, incorporated herein by reference. - - ********************** - - For more details, see drivers/net/arcnet.c - - ********************** - */ - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/**************************************************************************/ - -/* On a fast computer, the buffer copy from memory to the ARCnet card during - * a transmit can hog the bus just a little too long. SLOW_XMIT_COPY - * replaces the fast memcpy() with a slower for() loop that seems to solve - * my problems with ftape. - * - * Probably a better solution would be to use memcpy_toio (more portable - * anyway) and modify that routine to support REALLY_SLOW_IO-style - * defines; ARCnet probably is not the only driver that can screw up an - * ftape DMA transfer. - * - * Turn this on if you have timing-sensitive DMA (ie. a tape drive) and - * would like to sacrifice a little bit of network speed to reduce tape - * write retries or some related problem. - */ -#undef SLOW_XMIT_COPY - - -/* Define this to speed up the autoprobe by assuming if only one io port and - * shmem are left in the list at Stage 5, they must correspond to each - * other. - * - * This is undefined by default because it might not always be true, and the - * extra check makes the autoprobe even more careful. Speed demons can turn - * it on - I think it should be fine if you only have one ARCnet card - * installed. - * - * If no ARCnet cards are installed, this delay never happens anyway and thus - * the option has no effect. - */ -#undef FAST_PROBE - - -/* Internal function declarations */ -#ifdef MODULE -static -#endif -int arc90xx_probe(struct net_device *dev); -static void arc90xx_rx(struct net_device *dev, int recbuf); -static int arc90xx_found(struct net_device *dev, int ioaddr, int airq, void * shmem, int more); -static void arc90xx_inthandler(struct net_device *dev); -static int arc90xx_reset(struct net_device *dev, int reset_delay); -static void arc90xx_setmask(struct net_device *dev, u_char mask); -static void arc90xx_command(struct net_device *dev, u_char command); -static u_char arc90xx_status(struct net_device *dev); -static void arc90xx_prepare_tx(struct net_device *dev, u_char * hdr, int hdrlen, - char *data, int length, int daddr, int exceptA, int offset); -static void arc90xx_openclose(int open); - - -/* Module parameters */ - -#ifdef MODULE -static int io = 0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ -static int irq = 0; /* or use the insmod io= irq= shmem= options */ -static int shmem = 0; -static char *device; /* use eg. device="arc1" to change name */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(shmem, "i"); -MODULE_PARM(device, "s"); -#else -void __init com90xx_setup(char *str, int *ints); -char __initdata com90xx_explicit = 0; - -extern struct net_device arcnet_devs[]; -extern char arcnet_dev_names[][10]; -extern int arcnet_num_devs; -#endif - - -/* Handy defines for ARCnet specific stuff */ - -/* The number of low I/O ports used by the card. */ -#define ARCNET_TOTAL_SIZE 16 - -/* COM 9026 controller chip --> ARCnet register addresses */ -#define _INTMASK (ioaddr+0) /* writable */ -#define _STATUS (ioaddr+0) /* readable */ -#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ -#define _RESET (ioaddr+8) /* software reset (on read) */ -#define _MEMDATA (ioaddr+12) /* Data port for IO-mapped memory */ -#define _ADDR_HI (ioaddr+15) /* Control registers for said */ -#define _ADDR_LO (ioaddr+14) -#define _CONFIG (ioaddr+2) /* Configuration register */ - -#define RDDATAflag 0x00 /* Next access is a read/~write */ - -#define ARCSTATUS inb(_STATUS) -#define ACOMMAND(cmd) outb((cmd),_COMMAND) -#define AINTMASK(msk) outb((msk),_INTMASK) -#define SETCONF outb(lp->config,_CONFIG) -#define ARCRESET inb(_RESET) - -static const char *version = -"com90xx.c: v3.00 97/11/09 Avery Pennarun et al.\n"; - - -/**************************************************************************** - * * - * Probe and initialization * - * * - ****************************************************************************/ - -/* Check for an ARCnet network adaptor, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). - * - * NOTE: the list of possible ports/shmems is static, so it is retained - * across calls to arcnet_probe. So, if more than one ARCnet probe is made, - * values that were discarded once will not even be tried again. - * - * FIXME: grab all devices in one shot and eliminate the big static array. - */ - -static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { - 0 -}; -static void * shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { - 0 -}; - -int __init arc90xx_probe(struct net_device *dev) -{ - static int init_once = 0; - static int numports = sizeof(ports) / sizeof(ports[0]), numshmems = sizeof(shmems) / sizeof(shmems[0]); - int count, status, delayval, ioaddr, numprint, airq, retval = -ENODEV, - openparen = 0; - unsigned long airqmask; - int *port; - void **shmem; - - if (!init_once) { - for (count = 0x200; count <= 0x3f0; count += 16) - ports[(count - 0x200) / 16] = count; - for (count = 0xA0000; count <= 0xFF800; count += 2048) - shmems[(count - 0xA0000) / 2048] = ioremap(count, 2048); - BUGLVL(D_NORMAL) printk(version); - BUGMSG(D_DURING, "space used for probe buffers: %d+%d=%d bytes\n", - sizeof(ports), sizeof(shmems), - sizeof(ports) + sizeof(shmems)); - } - init_once++; - - BUGMSG(D_INIT, "given: base %lXh, IRQ %d, shmem %lXh\n", - dev->base_addr, dev->irq, dev->mem_start); - - if (dev->base_addr > 0x1ff) { /* Check a single specified port */ - ports[0] = dev->base_addr; - numports = 1; - } else if (dev->base_addr > 0) /* Don't probe at all. */ - return -ENXIO; - - if (dev->mem_start) { - shmems[0] = ioremap(dev->mem_start, 2048); - numshmems = 1; - } - /* Stage 1: abandon any reserved ports, or ones with status==0xFF - * (empty), and reset any others by reading the reset port. - */ - BUGMSG(D_INIT, "Stage 1: "); - numprint = 0; - for (port = &ports[0]; port - ports < numports; port++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 1: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%Xh ", *port); - - ioaddr = *port; - - if (check_region(*port, ARCNET_TOTAL_SIZE)) { - BUGMSG2(D_INIT_REASONS, "(check_region)\n"); - BUGMSG(D_INIT_REASONS, "Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - if (ARCSTATUS == 0xFF) { - BUGMSG2(D_INIT_REASONS, "(empty)\n"); - BUGMSG(D_INIT_REASONS, "Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - ARCRESET; /* begin resetting card */ - - BUGMSG2(D_INIT_REASONS, "\n"); - BUGMSG(D_INIT_REASONS, "Stage 1: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - } - BUGMSG2(D_INIT, "\n"); - - if (!numports) { - BUGMSG(D_NORMAL, "Stage 1: No ARCnet cards found.\n"); - return -ENODEV; - } - /* Stage 2: we have now reset any possible ARCnet cards, so we can't - * do anything until they finish. If D_INIT, print the list of - * cards that are left. - */ - BUGMSG(D_INIT, "Stage 2: "); - numprint = 0; - for (port = &ports[0]; port - ports < numports; port++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 2: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%Xh ", *port); - } - BUGMSG2(D_INIT, "\n"); - JIFFER(RESETtime); - - /* Stage 3: abandon any shmem addresses that don't have the signature - * 0xD1 byte in the right place, or are read-only. - */ - BUGMSG(D_INIT, "Stage 3: "); - numprint = 0; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - void * ptr; - - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 3: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%ph ", *shmem); - - ptr = *shmem; - - if (readb(ptr) != TESTvalue) { - BUGMSG2(D_INIT_REASONS, "(mem=%02Xh, not %02Xh)\n", - readb(ptr), TESTvalue); - BUGMSG(D_INIT_REASONS, "Stage 3: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; - continue; - } - /* By writing 0x42 to the TESTvalue location, we also make - * sure no "mirror" shmem areas show up - if they occur - * in another pass through this loop, they will be discarded - * because *cptr != TESTvalue. - */ - writeb(0x42, ptr); - if (readb(ptr) != 0x42) { - BUGMSG2(D_INIT_REASONS, "(read only)\n"); - BUGMSG(D_INIT_REASONS, "Stage 3: "); - *shmem = shmems[numshmems - 1]; - numshmems--; - shmem--; - continue; - } - BUGMSG2(D_INIT_REASONS, "\n"); - BUGMSG(D_INIT_REASONS, "Stage 3: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - } - BUGMSG2(D_INIT, "\n"); - - if (!numshmems) { - BUGMSG(D_NORMAL, "Stage 3: No ARCnet cards found.\n"); - return -ENODEV; - } - /* Stage 4: something of a dummy, to report the shmems that are - * still possible after stage 3. - */ - BUGMSG(D_INIT, "Stage 4: "); - numprint = 0; - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 4: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%ph ", *shmem); - } - BUGMSG2(D_INIT, "\n"); - - /* Stage 5: for any ports that have the correct status, can disable - * the RESET flag, and (if no irq is given) generate an autoirq, - * register an ARCnet device. - * - * Currently, we can only register one device per probe, so quit - * after the first one is found. - */ - BUGMSG(D_INIT, "Stage 5: "); - numprint = 0; - for (port = &ports[0]; port - ports < numports; port++) { - numprint++; - if (numprint > 8) { - BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "Stage 5: "); - numprint = 1; - } - BUGMSG2(D_INIT, "%Xh ", *port); - - ioaddr = *port; - status = ARCSTATUS; - - if ((status & 0x9D) - != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { - BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear); - status = ARCSTATUS; - if (status & RESETflag) { - BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", - status); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - /* skip this completely if an IRQ was given, because maybe - * we're on a machine that locks during autoirq! - */ - if (!dev->irq) { - /* if we do this, we're sure to get an IRQ since the - * card has just reset and the NORXflag is on until - * we tell it to start receiving. - */ - airqmask = probe_irq_on(); - AINTMASK(NORXflag); - mdelay(1); - AINTMASK(0); - airq = probe_irq_off(airqmask); - - if (airq <= 0) { - BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - *port = ports[numports - 1]; - numports--; - port--; - continue; - } - } else { - airq = dev->irq; - } - - BUGMSG2(D_INIT, "(%d,", airq); - openparen = 1; - - /* Everything seems okay. But which shmem, if any, puts - * back its signature byte when the card is reset? - * - * If there are multiple cards installed, there might be - * multiple shmems still in the list. - */ -#ifdef FAST_PROBE - if (numports > 1 || numshmems > 1) { - ARCRESET; - JIFFER(RESETtime); - } else { - /* just one shmem and port, assume they match */ - writeb(TESTvalue, shmems[0]); - } -#else - ARCRESET; - JIFFER(RESETtime); -#endif - - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) { - void * ptr; - ptr = *shmem; - - if (readb(ptr) == TESTvalue) { /* found one */ - int probe_more; - BUGMSG2(D_INIT, "%ph)\n", *shmem); - openparen = 0; - - /* register the card */ - if (init_once == 1 && numshmems > 1) - probe_more = numshmems - 1; - else - probe_more = 0; - retval = arc90xx_found(dev, *port, airq, *shmem, probe_more); - if (retval) - openparen = 0; - - /* remove shmem from the list */ - *shmem = shmems[numshmems - 1]; - numshmems--; - - break; - } else { - BUGMSG2(D_INIT_REASONS, "%Xh-", readb(ptr)); - } - } - - if (openparen) { - BUGMSG2(D_INIT, "no matching shmem)\n"); - BUGMSG(D_INIT_REASONS, "Stage 5: "); - BUGLVL(D_INIT_REASONS) numprint = 0; - } - *port = ports[numports - 1]; - numports--; - port--; - - if (!retval) - break; - } - BUGMSG(D_INIT_REASONS, "\n"); - - /* Now put back TESTvalue on all leftover shmems. - */ - for (shmem = &shmems[0]; shmem - shmems < numshmems; shmem++) - writeb(TESTvalue, *shmem); - - if (retval) - BUGMSG(D_NORMAL, "Stage 5: No ARCnet cards found.\n"); - return retval; -} - -/* Set up the struct net_device associated with this card. Called after - * probing succeeds. - */ -static int __init arc90xx_found(struct net_device *dev, int ioaddr, int airq, void * shmem, int more) -{ - struct arcnet_local *lp; - void *first_mirror, *last_mirror; - int mirror_size; - - /* reserve the irq */ - if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { - BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); - return -ENODEV; - } - dev->irq = airq; - - /* reserve the I/O region - guaranteed to work by check_region */ - request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (90xx)"); - dev->base_addr = ioaddr; - - /* find the real shared memory start/end points, including mirrors */ -#define BUFFER_SIZE (512) -#define MIRROR_SIZE (BUFFER_SIZE*4) - - /* guess the actual size of one "memory mirror" - the number of - * bytes between copies of the shared memory. On most cards, it's - * 2k (or there are no mirrors at all) but on some, it's 4k. - */ - mirror_size = MIRROR_SIZE; - if (readb(shmem) == TESTvalue - && readb(shmem - mirror_size) != TESTvalue - && readb(shmem - 2 * mirror_size) == TESTvalue) - mirror_size *= 2; - - first_mirror = last_mirror = shmem; - while (readb(first_mirror) == TESTvalue) - first_mirror -= mirror_size; - first_mirror += mirror_size; - - while (readb(last_mirror) == TESTvalue) - last_mirror += mirror_size; - last_mirror -= mirror_size; - - dev->mem_start = (unsigned long) first_mirror; - dev->mem_end = (unsigned long) last_mirror + MIRROR_SIZE - 1; - dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0; - dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1; - - /* Initialize the rest of the device structure. */ - - dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (dev->priv == NULL) { - free_irq(airq, dev); - release_region(ioaddr, ARCNET_TOTAL_SIZE); - return -ENOMEM; - } - memset(dev->priv, 0, sizeof(struct arcnet_local)); - lp = (struct arcnet_local *) (dev->priv); - lp->card_type = ARC_90xx; - lp->card_type_str = "COM 90xx"; - lp->arcnet_reset = arc90xx_reset; - lp->asetmask = arc90xx_setmask; - lp->astatus = arc90xx_status; - lp->acommand = arc90xx_command; - lp->openclose_device = arc90xx_openclose; - lp->prepare_tx = arc90xx_prepare_tx; - lp->inthandler = arc90xx_inthandler; - - /* Fill in the fields of the device structure with generic - * values. - */ - arcnet_setup(dev); - - /* And now fill particular fields with arcnet values */ - dev->mtu = 1500; /* completely arbitrary - agrees with ether, though */ - dev->hard_header_len = sizeof(struct ClientData); - lp->sequence = 1; - lp->recbuf = 0; - - BUGMSG(D_DURING, "ClientData header size is %d.\n", - sizeof(struct ClientData)); - BUGMSG(D_DURING, "HardHeader size is %d.\n", - sizeof(struct archdr)); - - /* get and check the station ID from offset 1 in shmem */ - lp->stationid = readb(first_mirror + 1); - - if (lp->stationid == 0) - BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " - "for broadcasts!\n"); - else if (lp->stationid == 255) - BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse " - "DOS networking programs!\n"); - dev->dev_addr[0] = lp->stationid; - - BUGMSG(D_NORMAL, "ARCnet COM90xx: station %02Xh found at %03lXh, IRQ %d, " - "ShMem %lXh (%ld*%xh).\n", - lp->stationid, - dev->base_addr, dev->irq, dev->mem_start, - (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); - - /* OK. We're finished. If there are probably other cards, add other - * COM90xx drivers to the device chain, so they get probed later. - */ - -#ifndef MODULE - while (!com90xx_explicit && more--) { - if (arcnet_num_devs < MAX_ARCNET_DEVS) { - arcnet_devs[arcnet_num_devs].next = dev->next; - dev->next = &arcnet_devs[arcnet_num_devs]; - dev = dev->next; - dev->name = (char *) &arcnet_dev_names[arcnet_num_devs]; - arcnet_num_devs++; - } else { - BUGMSG(D_NORMAL, "Too many arcnet devices - no more will be probed for.\n"); - return 0; - } - arcnet_makename(dev->name); - dev->init = arc90xx_probe; - } -#endif - - return 0; -} - - -/* Do a hardware reset on the card, and set up necessary registers. - - * This should be called as little as possible, because it disrupts the - * token on the network (causes a RECON) and requires a significant delay. - * - * However, it does make sure the card is in a defined state. - */ -int arc90xx_reset(struct net_device *dev, int reset_delay) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - short ioaddr = dev->base_addr; - int delayval, recbuf = lp->recbuf; - - if (reset_delay == 3) { - ARCRESET; - return 0; - } - /* no IRQ's, please! */ - lp->intmask = 0; - SETMASK; - - BUGMSG(D_INIT, "Resetting %s (status=%Xh)\n", - dev->name, ARCSTATUS); - - if (reset_delay) { - /* reset the card */ - ARCRESET; - JIFFER(RESETtime); - } - ACOMMAND(CFLAGScmd | RESETclear); /* clear flags & end reset */ - ACOMMAND(CFLAGScmd | CONFIGclear); - - /* verify that the ARCnet signature byte is present */ - if (readb(dev->mem_start) != TESTvalue) { - BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n"); - return 1; - } - /* clear out status variables */ - recbuf = lp->recbuf = 0; - lp->txbuf = 2; - - /* enable extended (512-byte) packets */ - ACOMMAND(CONFIGcmd | EXTconf); - -#ifndef SLOW_XMIT_COPY - /* clean out all the memory to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start, 0x42, 2048); -#endif - - /* and enable receive of our first packet to the first buffer */ - EnableReceiver(); - - /* re-enable interrupts */ - lp->intmask |= NORXflag; -#ifdef DETECT_RECONFIGS - lp->intmask |= RECONflag; -#endif - SETMASK; - - /* done! return success. */ - return 0; -} - - -static void arc90xx_openclose(int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - -static void arc90xx_setmask(struct net_device *dev, u_char mask) -{ - short ioaddr = dev->base_addr; - - AINTMASK(mask); -} - - -static u_char arc90xx_status(struct net_device *dev) -{ - short ioaddr = dev->base_addr; - - return ARCSTATUS; -} - - -static void arc90xx_command(struct net_device *dev, u_char cmd) -{ - short ioaddr = dev->base_addr; - - ACOMMAND(cmd); -} - - -/* The actual interrupt handler routine - handle various IRQ's generated - * by the card. - */ -static void arc90xx_inthandler(struct net_device *dev) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int ioaddr = dev->base_addr, status, boguscount = 3, didsomething; - - AINTMASK(0); - - BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", - ARCSTATUS, lp->intmask); - - do { - status = ARCSTATUS; - didsomething = 0; - - /* RESET flag was enabled - card is resetting and if RX - * is disabled, it's NOT because we just got a packet. - */ - if (status & RESETflag) { - BUGMSG(D_NORMAL, "spurious reset (status=%Xh)\n", - status); - arc90xx_reset(dev, 0); - - /* all other flag values are just garbage */ - break; - } - /* RX is inhibited - we must have received something. */ - if (status & lp->intmask & NORXflag) { - int recbuf = lp->recbuf = !lp->recbuf; - - BUGMSG(D_DURING, "receive irq (status=%Xh)\n", - status); - - /* enable receive of our next packet */ - EnableReceiver(); - - /* Got a packet. */ - arc90xx_rx(dev, !recbuf); - - didsomething++; - } - /* it can only be an xmit-done irq if we're xmitting :) */ - /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending) */ - if (status & lp->intmask & TXFREEflag) { - struct Outgoing *out = &(lp->outgoing); - int was_sending = lp->sending; - - lp->intmask &= ~TXFREEflag; - - lp->in_txhandler++; - if (was_sending) - lp->sending--; - - BUGMSG(D_DURING, "TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", - status, out->numsegs, out->segnum, out->skb); - - if (was_sending && !(status & TXACKflag)) { - if (lp->lasttrans_dest != 0) { - BUGMSG(D_EXTRA, "transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", - status, lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_carrier_errors++; - } else { - BUGMSG(D_DURING, "broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", - status, - lp->lasttrans_dest); - } - } - /* send packet if there is one */ - arcnet_go_tx(dev, 0); - didsomething++; - - if (lp->intx) { - BUGMSG(D_DURING, "TXDONE while intx! (status=%Xh, intx=%d)\n", - ARCSTATUS, lp->intx); - lp->in_txhandler--; - continue; - } - if (!lp->outgoing.skb) { - BUGMSG(D_DURING, "TX IRQ done: no split to continue.\n"); - - /* inform upper layers */ - if (!lp->txready) - arcnet_tx_done(dev, lp); - lp->in_txhandler--; - continue; - } - /* if more than one segment, and not all segments - * are done, then continue xmit. - */ - if (out->segnum < out->numsegs) - arcnetA_continue_tx(dev); - arcnet_go_tx(dev, 0); - - /* if segnum==numsegs, the transmission is finished; - * free the skb. - */ - if (out->segnum >= out->numsegs) { - /* transmit completed */ - out->segnum++; - if (out->skb) { - lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb); - } - out->skb = NULL; - - /* inform upper layers */ - if (!lp->txready) - arcnet_tx_done(dev, lp); - } - didsomething++; - - lp->in_txhandler--; - } else if (lp->txready && !lp->sending && !lp->intx) { - BUGMSG(D_NORMAL, "recovery from silent TX (status=%Xh)\n", - status); - arcnet_go_tx(dev, 0); - didsomething++; - } -#ifdef DETECT_RECONFIGS - if (status & (lp->intmask) & RECONflag) { - ACOMMAND(CFLAGScmd | CONFIGclear); - lp->stats.tx_carrier_errors++; - -#ifdef SHOW_RECONFIGS - BUGMSG(D_NORMAL, "Network reconfiguration detected (status=%Xh)\n", - status); -#endif /* SHOW_RECONFIGS */ - -#ifdef RECON_THRESHOLD - /* is the RECON info empty or old? */ - if (!lp->first_recon || !lp->last_recon || - jiffies - lp->last_recon > HZ * 10) { - if (lp->network_down) - BUGMSG(D_NORMAL, "reconfiguration detected: cabling restored?\n"); - lp->first_recon = lp->last_recon = jiffies; - lp->num_recons = lp->network_down = 0; - - BUGMSG(D_DURING, "recon: clearing counters.\n"); - } else { /* add to current RECON counter */ - lp->last_recon = jiffies; - lp->num_recons++; - - BUGMSG(D_DURING, "recon: counter=%d, time=%lds, net=%d\n", - lp->num_recons, - (lp->last_recon - lp->first_recon) / HZ, - lp->network_down); - - /* if network is marked up; - * and first_recon and last_recon are 60+ sec - * apart; - * and the average no. of recons counted is - * > RECON_THRESHOLD/min; - * then print a warning message. - */ - if (!lp->network_down - && (lp->last_recon - lp->first_recon) <= HZ * 60 - && lp->num_recons >= RECON_THRESHOLD) { - lp->network_down = 1; - BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n"); - } else if (!lp->network_down - && lp->last_recon - lp->first_recon > HZ * 60) { - /* reset counters if we've gone for - * over a minute. - */ - lp->first_recon = lp->last_recon; - lp->num_recons = 1; - } - } - } else if (lp->network_down && jiffies - lp->last_recon > HZ * 10) { - if (lp->network_down) - BUGMSG(D_NORMAL, "cabling restored?\n"); - lp->first_recon = lp->last_recon = 0; - lp->num_recons = lp->network_down = 0; - - BUGMSG(D_DURING, "not recon: clearing counters anyway.\n"); -#endif - } -#endif /* DETECT_RECONFIGS */ - } while (--boguscount && didsomething); - - BUGMSG(D_DURING, "net_interrupt complete (status=%Xh, count=%d)\n", - ARCSTATUS, boguscount); - BUGMSG(D_DURING, "\n"); - - SETMASK; /* put back interrupt mask */ -} - - -/* A packet has arrived; grab it from the buffers and pass it to the generic - * arcnet_rx routing to deal with it. - */ - -static void arc90xx_rx(struct net_device *dev, int recbuf) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int ioaddr = dev->base_addr; - union ArcPacket *arcpacket = - (union ArcPacket *) phys_to_virt(dev->mem_start + recbuf * 512); - u_char *arcsoft; - short length, offset; - u_char daddr, saddr; - - lp->stats.rx_packets++; - - saddr = arcpacket->hardheader.source; - - /* if source is 0, it's a "used" packet! */ - if (saddr == 0) { - BUGMSG(D_NORMAL, "discarding old packet. (status=%Xh)\n", - ARCSTATUS); - lp->stats.rx_errors++; - return; - } - /* Set source address to zero to mark it as old */ - - arcpacket->hardheader.source = 0; - - daddr = arcpacket->hardheader.destination; - - if (arcpacket->hardheader.offset1) { /* Normal Packet */ - offset = arcpacket->hardheader.offset1; - arcsoft = &arcpacket->raw[offset]; - length = 256 - offset; - } else { /* ExtendedPacket or ExceptionPacket */ - offset = arcpacket->hardheader.offset2; - arcsoft = &arcpacket->raw[offset]; - - length = 512 - offset; - } - - arcnet_rx(lp, arcsoft, length, saddr, daddr); - - BUGLVL(D_RX) arcnet_dump_packet(lp->adev, arcpacket->raw, length > 240, "rx"); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset((void *) arcpacket->raw, 0x42, 512); -#endif -} - - -/* Given an skb, copy a packet into the ARCnet buffers for later transmission - * by arcnet_go_tx. - */ -static void arc90xx_prepare_tx(struct net_device *dev, u_char * hdr, int hdrlen, - char *data, int length, int daddr, int exceptA, int offset) -{ - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - union ArcPacket *arcpacket = - (union ArcPacket *) phys_to_virt(dev->mem_start + 512 * (lp->txbuf ^ 1)); - -#ifdef SLOW_XMIT_COPY - char *iptr, *iend, *optr; -#endif - - lp->txbuf = lp->txbuf ^ 1; /* XOR with 1 to alternate between 2 and 3 */ - - length += hdrlen; - - BUGMSG(D_TX, "arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", - hdr, length, data); - -#ifndef SLOW_XMIT_COPY - /* clean out the page to make debugging make more sense :) */ - BUGLVL(D_DURING) - memset_io(dev->mem_start + lp->txbuf * 512, 0x42, 512); -#endif - - arcpacket->hardheader.destination = daddr; - - /* load packet into shared memory */ - if (length <= MTU) /* Normal (256-byte) Packet */ - arcpacket->hardheader.offset1 = offset = offset ? offset : 256 - length; - - else if (length >= MinTU || offset) { /* Extended (512-byte) Packet */ - arcpacket->hardheader.offset1 = 0; - arcpacket->hardheader.offset2 = offset = offset ? offset : 512 - length; - } else if (exceptA) { /* RFC1201 Exception Packet */ - arcpacket->hardheader.offset1 = 0; - arcpacket->hardheader.offset2 = offset = 512 - length - 4; - - /* exception-specific stuff - these four bytes - * make the packet long enough to fit in a 512-byte - * frame. - */ - - arcpacket->raw[offset + 0] = hdr[0]; - arcpacket->raw[offset + 1] = 0xFF; /* FF flag */ - arcpacket->raw[offset + 2] = 0xFF; /* FF padding */ - arcpacket->raw[offset + 3] = 0xFF; /* FF padding */ - offset += 4; - } else { /* "other" Exception packet */ - /* RFC1051 - set 4 trailing bytes to 0 */ - memset(&arcpacket->raw[508], 0, 4); - - /* now round up to MinTU */ - arcpacket->hardheader.offset1 = 0; - arcpacket->hardheader.offset2 = offset = 512 - MinTU; - } - - /* copy the packet into ARCnet shmem - * - the first bytes of ClientData header are skipped - */ - - memcpy((u_char *) arcpacket + offset, (u_char *) hdr, hdrlen); -#ifdef SLOW_XMIT_COPY - for (iptr = data, iend = iptr + length - hdrlen, optr = (char *) arcpacket + offset + hdrlen; - iptr < iend; iptr++, optr++) { - *optr = *iptr; - /*udelay(5); */ - } -#else - memcpy((u_char *) arcpacket + offset + hdrlen, data, length - hdrlen); -#endif - - BUGMSG(D_DURING, "transmitting packet to station %02Xh (%d bytes)\n", - daddr, length); - - BUGLVL(D_TX) arcnet_dump_packet(dev, arcpacket->raw, length > MTU, "tx"); - - lp->lastload_dest = daddr; - lp->txready = lp->txbuf; /* packet is ready for sending */ -} - - -/**************************************************************************** - * * - * Kernel Loadable Module Support * - * * - ****************************************************************************/ - - -#ifdef MODULE - -static char devicename[9] = ""; -static struct net_device thiscard = -{ - devicename, /* device name is inserted by linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0, 0, /* I/O address, IRQ */ - 0, 0, 0, NULL, arc90xx_probe -}; - - -int init_module(void) -{ - struct net_device *dev = &thiscard; - if (device) - strcpy(dev->name, device); - else - arcnet_makename(dev->name); - - dev->base_addr = io; - - dev->irq = irq; - if (dev->irq == 2) - dev->irq = 9; - - if (shmem) { - dev->mem_start = shmem; - dev->mem_end = thiscard.mem_start + 512 * 4 - 1; - dev->rmem_start = thiscard.mem_start + 512 * 0; - dev->rmem_end = thiscard.mem_start + 512 * 2 - 1; - } - if (register_netdev(dev) != 0) - return -EIO; - arcnet_use_count(1); - return 0; -} - -void cleanup_module(void) -{ - struct net_device *dev = &thiscard; - int ioaddr = dev->mem_start; - - if (dev->start) - (*dev->stop) (dev); - - /* Flush TX and disable RX */ - if (ioaddr) { - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ - -#if defined(IO_MAPPED_BUFFERS) && !defined(COM20020) - /* Set the thing back to MMAP mode, in case the old - driver is loaded later */ - outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); -#endif - } - if (dev->irq) { - free_irq(dev->irq, dev); - } - if (dev->base_addr) - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - unregister_netdev(dev); - kfree(dev->priv); - dev->priv = NULL; - arcnet_use_count(0); -} - -#else - -void __init com90xx_setup(char *str, int *ints) -{ - struct net_device *dev; - - if (arcnet_num_devs == MAX_ARCNET_DEVS) { - printk("com90xx: Too many ARCnet devices registered (max %d).\n", - MAX_ARCNET_DEVS); - return; - } - if (!ints[0] && (!str || !*str)) { - printk("com90xx: Disabled.\n"); - com90xx_explicit++; - return; - } - dev = &arcnet_devs[arcnet_num_devs]; - - dev->dev_addr[3] = 3; - dev->init = arc90xx_probe; - - switch (ints[0]) { - case 4: /* ERROR */ - printk("com20020: Too many arguments.\n"); - - case 3: /* Mem address */ - dev->mem_start = ints[3]; - - case 2: /* IRQ */ - dev->irq = ints[2]; - - case 1: /* IO address */ - dev->base_addr = ints[1]; - } - - dev->name = (char *) &arcnet_dev_names[arcnet_num_devs]; - - if (str) - strncpy(dev->name, str, 9); - - arcnet_num_devs++; -} -#endif /* MODULE */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.3.35/linux/drivers/net/eepro.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/net/eepro.c Wed Dec 29 17:00:54 1999 @@ -747,7 +747,7 @@ 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 */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.3.35/linux/drivers/net/eth16i.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/eth16i.c Wed Dec 29 17:00:54 1999 @@ -1,8 +1,8 @@ /* 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 @@ -16,7 +16,7 @@ (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 @@ -118,6 +118,12 @@ 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 @@ -137,7 +143,7 @@ */ 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 @@ -400,7 +406,8 @@ 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; }; @@ -1147,9 +1154,9 @@ } lp->tx_buffered_packets++; + lp->tx_buffered_bytes = length; lp->tx_queue++; lp->tx_queue_len += length + 2; - } lp->tx_buf_busy = 0; @@ -1260,6 +1267,7 @@ 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; @@ -1368,6 +1376,7 @@ 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 ? */ @@ -1500,7 +1509,7 @@ }, }; -static int ioaddr[MAX_ETH16I_CARDS] = { 0, }; +static int io[MAX_ETH16I_CARDS] = { 0, }; #if 0 static int irq[MAX_ETH16I_CARDS] = { 0, }; #endif @@ -1511,8 +1520,8 @@ MODULE_AUTHOR("Mika Kuoppala "); 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"); @@ -1536,7 +1545,7 @@ 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) @@ -1547,7 +1556,7 @@ 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 */ @@ -1557,7 +1566,7 @@ 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; diff -u --recursive --new-file v2.3.35/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c --- v2.3.35/linux/drivers/net/irda/irport.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/irda/irport.c Wed Dec 29 17:08:55 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * 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 * Sources: serial.c by Linus Torvalds * @@ -218,9 +218,6 @@ 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 */ @@ -266,8 +263,6 @@ 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 */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c --- v2.3.35/linux/drivers/net/irda/irtty.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/irda/irtty.c Wed Dec 29 17:08:55 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * 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 * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, @@ -233,8 +233,6 @@ 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; @@ -286,8 +284,6 @@ 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! */ diff -u --recursive --new-file v2.3.35/linux/drivers/net/irda/pc87108.c linux/drivers/net/irda/pc87108.c --- v2.3.35/linux/drivers/net/irda/pc87108.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/irda/pc87108.c Wed Dec 29 17:08:55 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * 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 * * Copyright (c) 1998-1999 Dag Brattli @@ -113,7 +113,6 @@ 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); @@ -257,9 +256,6 @@ 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; @@ -308,8 +304,6 @@ 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 */ @@ -666,7 +660,7 @@ __u8 bank; int iobase; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed); ASSERT(self != NULL, return;); @@ -819,11 +813,11 @@ 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); @@ -992,12 +986,13 @@ 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); @@ -1163,9 +1158,7 @@ /* 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 */ } @@ -1215,7 +1208,14 @@ } /* 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; @@ -1350,19 +1350,6 @@ outb(bsr, iobase+BSR); /* Restore bank register */ 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)); } /* diff -u --recursive --new-file v2.3.35/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.3.35/linux/drivers/net/irda/toshoboe.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/irda/toshoboe.c Tue Jan 4 09:41:45 2000 @@ -87,7 +87,7 @@ /* No user servicable parts below here */ #include - +#include #include #include #include @@ -702,8 +702,6 @@ rtnl_lock(); unregister_netdevice(self->netdev); rtnl_unlock(); - /* Must free the old-style 2.2.x device */ - kfree(self->netdev); } kfree (self->taskfilebuf); @@ -872,8 +870,6 @@ 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; diff -u --recursive --new-file v2.3.35/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c --- v2.3.35/linux/drivers/net/irda/w83977af_ir.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/irda/w83977af_ir.c Tue Jan 4 09:41:45 2000 @@ -6,7 +6,7 @@ * 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 * * Copyright (c) 1998-1999 Dag Brattli @@ -40,7 +40,7 @@ ********************************************************************/ #include - +#include #include #include #include @@ -244,9 +244,6 @@ 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; @@ -301,8 +298,6 @@ 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 */ @@ -1013,8 +1008,15 @@ } } /* 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; diff -u --recursive --new-file v2.3.35/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in --- v2.3.35/linux/drivers/net/pcmcia/Config.in Mon Dec 20 18:48:21 1999 +++ linux/drivers/net/pcmcia/Config.in Thu Dec 30 11:51:26 1999 @@ -14,7 +14,8 @@ dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA - dep_tristate ' Aironet 4500/4800 PCMCIA support ' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA + dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA + dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA if [ "$CONFIG_CARDBUS" = "y" ]; then dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m diff -u --recursive --new-file v2.3.35/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile --- v2.3.35/linux/drivers/net/pcmcia/Makefile Wed Dec 8 14:11:26 1999 +++ linux/drivers/net/pcmcia/Makefile Thu Dec 30 11:51:26 1999 @@ -30,6 +30,7 @@ obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o +obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o # 16-bit wireless client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o diff -u --recursive --new-file v2.3.35/linux/drivers/net/pcmcia/com20020_cs.c linux/drivers/net/pcmcia/com20020_cs.c --- v2.3.35/linux/drivers/net/pcmcia/com20020_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/com20020_cs.c Thu Dec 30 11:51:26 1999 @@ -0,0 +1,569 @@ +/* + * Linux ARCnet driver - COM20020 PCMCIA support + * + * Written 1994-1999 by Avery Pennarun, + * based on an ISA version by David Woodhouse. + * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4) + * which was derived from pcnet_cs.c by David Hinds. + * Some additional portions derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" + +#ifdef PCMCIA_DEBUG + +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) + +static void regdump(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + int count; + + printk("com20020 register dump:\n"); + for (count = ioaddr; count < ioaddr + 16; count++) + { + if (!(count % 16)) + printk("\n%04X: ", count); + printk("%02X ", inb(count)); + } + printk("\n"); + + printk("buffer0 dump:\n"); + /* set up the address register */ + count = 0; + outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); + outb(count & 0xff, _ADDR_LO); + + for (count = 0; count < 256+32; count++) + { + if (!(count % 16)) + printk("\n%04X: ", count); + + /* copy the data */ + printk("%02X ", inb(_MEMDATA)); + } + printk("\n"); +} + +#else + +#define DEBUG(n, args...) do { } while (0) +static inline void regdump(struct net_device *dev) { } + +#endif + + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int node = 0; +static int timeout = 3; +static int backplane = 0; +static int clock = 0; + +MODULE_PARM(node, "i"); +MODULE_PARM(timeout, "i"); +MODULE_PARM(backplane, "i"); +MODULE_PARM(clock, "i"); + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +static void com20020_config(dev_link_t *link); +static void com20020_release(u_long arg); +static int com20020_event(event_t event, int priority, + event_callback_args_t *args); + +static dev_info_t dev_info = "com20020_cs"; + +static dev_link_t *com20020_attach(void); +static void com20020_detach(dev_link_t *); + +static dev_link_t *dev_list = NULL; + +/*====================================================================*/ + +typedef struct com20020_dev_t { + struct net_device *dev; + int dev_configured; + dev_node_t node; +} com20020_dev_t; + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + +======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + com20020_detach(link); + } +} + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + com20020_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +======================================================================*/ + +static void com20020cs_open_close(struct net_device *dev, bool open) +{ + if (open) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +static dev_link_t *com20020_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + com20020_dev_t *info; + struct net_device *dev; + int i, ret; + struct arcnet_local *lp; + + DEBUG(0, "com20020_attach()\n"); + flush_stale_links(); + + /* Create new network device */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) + return NULL; + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &com20020_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 16; + link->io.IOAddrLines = 16; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(struct com20020_dev_t)); + + dev = dev_alloc("arc%d", &ret); + if (!dev) + return NULL; + lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); + if (!lp) + return NULL; + memset(lp, 0, sizeof(struct arcnet_local)); + + /* fill in our module parameters as defaults */ + dev->dev_addr[0] = node; + lp->timeout = timeout; + lp->backplane = backplane; + lp->clock = clock; + lp->hw.open_close_ll = com20020cs_open_close; + + link->irq.Instance = info->dev = dev; + link->priv = info; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &com20020_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + com20020_detach(link); + return NULL; + } + + return link; +} /* com20020_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void com20020_detach(dev_link_t *link) +{ + struct com20020_dev_t *info = link->priv; + dev_link_t **linkp; + struct net_device *dev; + + DEBUG(1,"detach...\n"); + + DEBUG(0, "com20020_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + dev = info->dev; + + if (link->state & DEV_CONFIG) { + com20020_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + DEBUG(1,"unlinking...\n"); + *linkp = link->next; + if (link->priv) + { + dev = info->dev; + if (dev) + { + if (info->dev_configured) + { + DEBUG(1,"unregister...\n"); + + if (dev->start) + dev->stop(dev); + + /* + * this is necessary because we register our IRQ separately + * from card services. + */ + if (dev->irq) + free_irq(dev->irq, dev); + + /* ...but I/O ports are done automatically by card services */ + + unregister_netdev(dev); + MOD_DEC_USE_COUNT; + } + + DEBUG(1,"kfree...\n"); + kfree(dev->priv); + kfree(dev); + } + DEBUG(1,"kfree2...\n"); + kfree_s(info, sizeof(struct com20020_dev_t)); + } + DEBUG(1,"kfree3...\n"); + kfree_s(link, sizeof(struct dev_link_t)); + +} /* com20020_detach */ + +/*====================================================================== + + com20020_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void com20020_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + com20020_dev_t *info; + struct net_device *dev; + int i, last_ret, last_fn; + u_char buf[64]; + int ioaddr; + + handle = link->handle; + info = link->priv; + dev = info->dev; + + DEBUG(1,"config...\n"); + + DEBUG(0, "com20020_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + + /* Configure card */ + link->state |= DEV_CONFIG; + strcpy(info->node.dev_name, dev->name); + + DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1); + i = !CS_SUCCESS; + if (!link->io.BasePort1) + { + for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) + { + link->io.BasePort1 = ioaddr; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + } + else + i = CardServices(RequestIO, link->handle, &link->io); + + if (i != CS_SUCCESS) + { + DEBUG(1,"arcnet: requestIO failed totally!\n"); + goto failed; + } + + ioaddr = dev->base_addr = link->io.BasePort1; + DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr); + + DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n", + link->irq.AssignedIRQ, + link->irq.IRQInfo1, link->irq.IRQInfo2); + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) + { + DEBUG(1,"arcnet: requestIRQ failed totally!\n"); + goto failed; + } + + dev->irq = link->irq.AssignedIRQ; + + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + if (com20020_check(dev)) + { + regdump(dev); + goto failed; + } + + MOD_INC_USE_COUNT; + i = com20020_found(dev, 0); + + if (i != 0) { + DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n"); + goto failed; + } + + info->dev_configured = 1; + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n", + dev->name, dev->base_addr, dev->irq); + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + DEBUG(1,"com20020_config failed...\n"); + com20020_release((u_long)link); +} /* com20020_config */ + +/*====================================================================== + + After a card is removed, com20020_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void com20020_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(1,"release...\n"); + + DEBUG(0, "com20020_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1,"postpone...\n"); + DEBUG(1, "com20020_cs: release postponed, device stll open\n"); + link->state |= DEV_STALE_CONFIG; + return; + } + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* com20020_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + +======================================================================*/ + +static int com20020_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + com20020_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + DEBUG(1, "com20020_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dev->tbusy = 1; dev->start = 0; + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT; + com20020_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 1; dev->start = 0; + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) { + int ioaddr = dev->base_addr; + struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + ARCRESET; + } + } + break; + } + return 0; +} /* com20020_event */ + + +/*====================================================================*/ + +static int __init init_com20020_cs(void) +{ + servinfo_t serv; + + DEBUG(0, "%s\n", VERSION); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "com20020_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &com20020_attach, &com20020_detach); + return 0; +} + +static void __exit exit_com20020_cs(void) +{ + DEBUG(0, "com20020_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + com20020_detach(dev_list); +} + +module_init(init_com20020_cs); +module_exit(exit_com20020_cs); diff -u --recursive --new-file v2.3.35/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c --- v2.3.35/linux/drivers/net/pcmcia/tulip_cb.c Thu Nov 18 20:25:37 1999 +++ linux/drivers/net/pcmcia/tulip_cb.c Thu Dec 30 14:43:45 1999 @@ -1464,6 +1464,9 @@ outl(tp->csr0, ioaddr + CSR0); udelay(2); + if (tulip_tbl[tp->chip_id].flags & HAS_ACPI) + pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x00000000); + /* Clear the tx ring */ for (i = 0; i < TX_RING_SIZE; i++) { tp->tx_skbuff[i] = 0; diff -u --recursive --new-file v2.3.35/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.3.35/linux/drivers/net/sis900.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/sis900.c Wed Dec 29 17:00:54 1999 @@ -1221,7 +1221,7 @@ /* 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); } diff -u --recursive --new-file v2.3.35/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.35/linux/drivers/parport/parport_pc.c Thu Nov 11 20:11:42 1999 +++ linux/drivers/parport/parport_pc.c Thu Dec 30 10:11:57 1999 @@ -1687,12 +1687,6 @@ parport_pc_write_data(p, 0); parport_pc_data_forward (p); - parport_pc_write_control(p, PARPORT_CONTROL_SELECT); - udelay (50); - parport_pc_write_control(p, - PARPORT_CONTROL_SELECT - | PARPORT_CONTROL_INIT); - udelay (50); /* Now that we've told the sharing engine about the port, and found out its characteristics, let the high-level drivers diff -u --recursive --new-file v2.3.35/linux/drivers/parport/share.c linux/drivers/parport/share.c --- v2.3.35/linux/drivers/parport/share.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/parport/share.c Thu Dec 30 10:11:57 1999 @@ -95,6 +95,14 @@ } } +/* Ask kmod for some lowlevel drivers. */ +static void get_lowlevel_driver (void) +{ + /* There is no actual module called this: you should set + * up an alias for modutils. */ + request_module ("parport_lowlevel"); +} + int parport_register_driver (struct parport_driver *drv) { struct parport *port; @@ -107,12 +115,8 @@ for (port = portlist; port; port = port->next) drv->attach (port); - /* For compatibility with 2.2, check the (obsolete) parport_lowlevel - * alias in case some people haven't changed to post-install rules - * yet. parport_enumerate (itself deprecated) will printk a - * friendly reminder. */ if (!portlist) - parport_enumerate (); + get_lowlevel_driver (); return 0; } @@ -123,12 +127,21 @@ while (drv) { if (drv == arg) { + struct parport *port; + spin_lock (&driverlist_lock); if (olddrv) olddrv->next = drv->next; else driver_chain = drv->next; spin_unlock (&driverlist_lock); + + /* Call the driver's detach routine for each + * port to clean up any resources that the + * attach routine acquired. */ + for (port = portlist; port; port = port->next) + drv->detach (port); + return; } olddrv = drv; @@ -136,20 +149,12 @@ } } -/* Return a list of all the ports we know about. */ +/* Return a list of all the ports we know about. This function shouldn't + * really be used -- use parport_register_driver instead. */ struct parport *parport_enumerate(void) { - /* Attempt to make things work on 2.2 systems. */ - if (!portlist) { - request_module ("parport_lowlevel"); - if (portlist) - /* The user has a parport_lowlevel alias in - * modules.conf. Warn them that it won't work - * for long. */ - printk (KERN_WARNING - "parport: 'parport_lowlevel' is deprecated; " - "see parport.txt\n"); - } + if (!portlist) + get_lowlevel_driver (); return portlist; } diff -u --recursive --new-file v2.3.35/linux/drivers/pci/names.c linux/drivers/pci/names.c --- v2.3.35/linux/drivers/pci/names.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/pci/names.c Mon Jan 3 11:15:05 2000 @@ -123,7 +123,6 @@ void __init pci_name_device(struct pci_dev *dev) { - sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device); } char * diff -u --recursive --new-file v2.3.35/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.35/linux/drivers/pci/pci.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/pci/pci.c Mon Jan 3 12:18:01 2000 @@ -269,7 +269,7 @@ return IORESOURCE_MEM; } -static void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) +static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg, next; u32 l, sz, tmp; @@ -447,6 +447,7 @@ */ static int __init pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int busnr) { + int i; unsigned short cr; unsigned int buses; struct pci_bus *child; @@ -455,7 +456,14 @@ * Insert it into the tree of buses. */ child = pci_add_new_bus(bus, dev, ++busnr); - child->subordinate = busnr; + + for (i = 0; i < 4; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + + /* + * Maybe we'll have another bus behind this one? + */ + child->subordinate = ++busnr; sprintf(child->name, "PCI CardBus #%02x", child->number); /* @@ -566,7 +574,7 @@ * Read interrupt line and base address registers. * The architecture-dependent code can tweak these, of course. */ -static void __init pci_read_irq(struct pci_dev *dev) +static void pci_read_irq(struct pci_dev *dev) { unsigned char irq; @@ -577,31 +585,15 @@ } /* - * Read the config data for a PCI device, sanity-check it - * and fill in the dev structure... + * Fill in class and map information of a device */ -static struct pci_dev * __init pci_scan_device(struct pci_dev *temp) +int pci_setup_device(struct pci_dev * dev) { - struct pci_dev *dev; - u32 l, class; + u32 class; - if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l)) - return NULL; - - /* some broken boards return 0 or ~0 if a slot is empty: */ - if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) - return NULL; - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - memcpy(dev, temp, sizeof(*dev)); - dev->vendor = l & 0xffff; - dev->device = (l >> 16) & 0xffff; sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - pci_name_device(dev); - + sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device); + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); class >>= 8; /* upper 3 bytes */ dev->class = class; @@ -635,8 +627,7 @@ default: /* unknown header */ printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n", dev->slot_name, dev->hdr_type); - kfree(dev); - return NULL; + return -1; bad: printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n", @@ -645,6 +636,36 @@ } /* We found a fine healthy device, go go go... */ + return 0; +} + +/* + * Read the config data for a PCI device, sanity-check it + * and fill in the dev structure... + */ +static struct pci_dev * __init pci_scan_device(struct pci_dev *temp) +{ + struct pci_dev *dev; + u32 l; + + if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l)) + return NULL; + + /* some broken boards return 0 or ~0 if a slot is empty: */ + if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) + return NULL; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + memcpy(dev, temp, sizeof(*dev)); + dev->vendor = l & 0xffff; + dev->device = (l >> 16) & 0xffff; + if (pci_setup_device(dev) < 0) { + kfree(dev); + dev = NULL; + } return dev; } @@ -667,12 +688,13 @@ dev = pci_scan_device(temp); if (!dev) continue; + pci_name_device(dev); if (!func) { is_multi = hdr_type & 0x80; first_dev = dev; } - DBG("PCI: %02x:%02x [%04x/%04x] %06x %02x\n", bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type); + DBG("PCI: %02x:%02x [%04x/%04x] %06x %02x\n", bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type); /* * Put it into the global PCI device chain. It's used to diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/Config.in linux/drivers/pcmcia/Config.in --- v2.3.35/linux/drivers/pcmcia/Config.in Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/Config.in Mon Jan 3 16:02:01 2000 @@ -8,7 +8,6 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then if [ "$CONFIG_PCI" != "n" ]; then bool ' CardBus support' CONFIG_CARDBUS - dep_tristate ' Yenta Cardbus support' CONFIG_YENTA $CONFIG_CARDBUS fi bool ' i82365 compatible bridge support' CONFIG_I82365 bool ' Databook TCIC host bridge support' CONFIG_TCIC diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile --- v2.3.35/linux/drivers/pcmcia/Makefile Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/Makefile Mon Jan 3 16:36:39 2000 @@ -18,19 +18,16 @@ O_OBJS := cistpl.o rsrc_mgr.o bulkmem.o OX_OBJS := ds.o cs.o O_TARGET := pcmcia.o + ifeq ($(CONFIG_CARDBUS),y) + O_OBJS += cardbus.o + OX_OBJS += cb_enabler.o yenta.o pci_socket.o + endif ifeq ($(CONFIG_I82365),y) O_OBJS += i82365.o endif ifeq ($(CONFIG_TCIC),y) O_OBJS += tcic.o endif - ifeq ($(CONFIG_YENTA),y) - OX_OBJS += yenta.o pci_socket.o - endif - ifeq ($(CONFIG_CARDBUS),y) - O_OBJS += cardbus.o - OX_OBJS += cb_enabler.o - endif else ifeq ($(CONFIG_PCMCIA),m) M_OBJS := pcmcia_core.o @@ -45,7 +42,7 @@ endif ifeq ($(CONFIG_CARDBUS),y) CORE_OBJS += cardbus.o - MX_OBJS += cb_enabler.o + MX_OBJS += cb_enabler.o yenta.o pci_socket.o endif endif endif diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c --- v2.3.35/linux/drivers/pcmcia/cardbus.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/cardbus.c Mon Jan 3 15:47:23 2000 @@ -33,9 +33,19 @@ well as setting up and shutting down Cardbus sockets. They are called from cs.c in response to Request/ReleaseConfiguration and Request/ReleaseIO calls. - + ======================================================================*/ +/* + * This file is going away. Cardbus handling has been re-written to be + * more of a PCI bridge thing, and the PCI code basically does all the + * resource handling. This has wrappers to make the rest of the PCMCIA + * subsystem not notice that it's not here any more. + * + * Linus, Jan 2000 + */ + + #define __NO_VERSION__ #include @@ -68,15 +78,12 @@ #define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1))) -#define pci_readb pcibios_read_config_byte -#define pci_writeb pcibios_write_config_byte -#define pci_readw pcibios_read_config_word -#define pci_writew pcibios_write_config_word -#define pci_readl pcibios_read_config_dword -#define pci_writel pcibios_write_config_dword - -#define CB_BAR(n) (PCI_BASE_ADDRESS_0+(4*(n))) -#define CB_ROM_BASE 0x0030 +#define pci_readb pci_read_config_byte +#define pci_writeb pci_write_config_byte +#define pci_readw pci_read_config_word +#define pci_writew pci_write_config_word +#define pci_readl pci_read_config_dword +#define pci_writel pci_write_config_dword /* Offsets in the Expansion ROM Image Header */ #define ROM_SIGNATURE 0x0000 /* 2 bytes */ @@ -93,17 +100,9 @@ #define PCDATA_INDICATOR 0x0015 typedef struct cb_config_t { - u_int size[7]; - struct pci_dev dev; + struct pci_dev dev; } cb_config_t; -#define BASE(dev,n) ((dev).resource[n].start) -#define ROM(dev) ((dev).resource[6].start) - -/* There are three classes of bridge maps: IO ports, - non-prefetchable memory, and prefetchable memory */ -typedef enum { B_IO, B_M1, B_M2 } bridge_type; - /*===================================================================== Expansion ROM's have a special layout, and pointers specify an @@ -114,45 +113,49 @@ =====================================================================*/ -static int check_rom(u_char *b, u_long len) +static int check_rom(u_char * b, u_long len) +{ + u_int img = 0, ofs = 0, sz; + u_short data; + DEBUG(0, "ROM image dump:\n"); + while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { + data = readb(b + ROM_DATA_PTR) + + (readb(b + ROM_DATA_PTR + 1) << 8); + sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + + (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); + DEBUG(0, " image %d: 0x%06x-0x%06x, signature %c%c%c%c\n", + img, ofs, ofs + sz - 1, + readb(b + data + PCDATA_SIGNATURE), + readb(b + data + PCDATA_SIGNATURE + 1), + readb(b + data + PCDATA_SIGNATURE + 2), + readb(b + data + PCDATA_SIGNATURE + 3)); + ofs += sz; + img++; + if ((readb(b + data + PCDATA_INDICATOR) & 0x80) || + (sz == 0) || (ofs >= len)) + break; + b += sz; + } + return img; +} + +static u_int xlate_rom_addr(u_char * b, u_int addr) { - u_int img = 0, ofs = 0, sz; - u_short data; - DEBUG(0, "ROM image dump:\n"); - while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) { - data = readb(b+ROM_DATA_PTR) + - (readb(b+ROM_DATA_PTR+1) << 8); - sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) + - (readb(b+data+PCDATA_IMAGE_SZ+1) << 8)); - DEBUG(0, " image %d: 0x%06x-0x%06x, signature %c%c%c%c\n", - img, ofs, ofs+sz-1, - readb(b+data+PCDATA_SIGNATURE), - readb(b+data+PCDATA_SIGNATURE+1), - readb(b+data+PCDATA_SIGNATURE+2), - readb(b+data+PCDATA_SIGNATURE+3)); - ofs += sz; img++; - if ((readb(b+data+PCDATA_INDICATOR) & 0x80) || - (sz == 0) || (ofs >= len)) break; - b += sz; - } - return img; -} - -static u_int xlate_rom_addr(u_char *b, u_int addr) -{ - u_int img = 0, ofs = 0, sz; - u_short data; - while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) { - if (img == (addr >> 28)) - return (addr & 0x0fffffff) + ofs; - data = readb(b+ROM_DATA_PTR) + (readb(b+ROM_DATA_PTR+1) << 8); - sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) + - (readb(b+data+PCDATA_IMAGE_SZ+1) << 8)); - if ((sz == 0) || (readb(b+data+PCDATA_INDICATOR) & 0x80)) - break; - b += sz; ofs += sz; img++; - } - return 0; + u_int img = 0, ofs = 0, sz; + u_short data; + while ((readb(b) == 0x55) && (readb(b + 1) == 0xaa)) { + if (img == (addr >> 28)) + return (addr & 0x0fffffff) + ofs; + data = readb(b + ROM_DATA_PTR) + (readb(b + ROM_DATA_PTR + 1) << 8); + sz = 512 * (readb(b + data + PCDATA_IMAGE_SZ) + + (readb(b + data + PCDATA_IMAGE_SZ + 1) << 8)); + if ((sz == 0) || (readb(b + data + PCDATA_INDICATOR) & 0x80)) + break; + b += sz; + ofs += sz; + img++; + } + return 0; } /*===================================================================== @@ -163,76 +166,36 @@ =====================================================================*/ -int cb_setup_cis_mem(socket_info_t *s, int space) +void cb_release_cis_mem(socket_info_t * s) { - cb_bridge_map *m = &s->cb_cis_map; - u_long base = 0; - u_int sz, br; + if (s->cb_cis_virt) { + DEBUG(1, "cs: cb_release_cis_mem()\n"); + iounmap(s->cb_cis_virt); + s->cb_cis_virt = NULL; + s->cb_cis_res = 0; + } +} - if (space == s->cb_cis_space) - return CS_SUCCESS; - else if (s->cb_cis_space != 0) - cb_release_cis_mem(s); - DEBUG(1, "cs: cb_setup_cis_mem(space %d)\n", space); - /* If socket is configured, then use existing memory mapping */ - if (s->lock_count) { - s->cb_cis_virt = - ioremap(BASE(s->cb_config[0].dev, space-1), - s->cb_config[0].size[space-1] & ~3); - s->cb_cis_space = space; - return CS_SUCCESS; - } - - /* Not configured? Then set up temporary map */ - br = (space == 7) ? CB_ROM_BASE : CB_BAR(space-1); - pci_writel(s->cap.cardbus, 0, br, 0xffffffff); - pci_readl(s->cap.cardbus, 0, br, &sz); - sz &= PCI_BASE_ADDRESS_MEM_MASK; - sz = FIND_FIRST_BIT(sz); - if (sz < PAGE_SIZE) sz = PAGE_SIZE; - if (find_mem_region(&base, sz, sz, 0, "cb_enabler") != 0) { - printk(KERN_NOTICE "cs: could not allocate %dK memory for" - " CardBus socket %d\n", sz/1024, s->sock); - return CS_OUT_OF_RESOURCE; - } - s->cb_cis_space = space; - s->cb_cis_virt = ioremap(base, sz); - DEBUG(1, " phys 0x%08lx-0x%08lx, virt 0x%08lx\n", - base, base+sz-1, (u_long)s->cb_cis_virt); - pci_writel(s->cap.cardbus, 0, br, base | 1); - pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, PCI_COMMAND_MEMORY); - m->map = 0; m->flags = MAP_ACTIVE; - m->start = base; m->stop = base+sz-1; - s->ss_entry->set_bridge(s->sock, m); - if ((space == 7) && (check_rom(s->cb_cis_virt, sz) == 0)) { - printk(KERN_NOTICE "cs: no valid ROM images found!\n"); - return CS_READ_FAILURE; - } - return CS_SUCCESS; -} - -void cb_release_cis_mem(socket_info_t *s) -{ - cb_bridge_map *m = &s->cb_cis_map; - u_int br; - if (s->cb_cis_virt) { - DEBUG(1, "cs: cb_release_cis_mem()\n"); - iounmap(s->cb_cis_virt); - s->cb_cis_virt = NULL; - s->cb_cis_space = 0; - } - if (m->start) { - /* This is overkill: we probably only need to release the - memory region, but the rest should be safe */ - br = (s->cb_cis_space == 7) ? - CB_ROM_BASE : CB_BAR(s->cb_cis_space-1); - m->map = 0; m->flags = 0; - s->ss_entry->set_bridge(s->sock, m); - pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, 0); - pci_writel(s->cap.cardbus, 0, br, 0); - release_mem_region(m->start, m->stop - m->start + 1); - m->start = 0; - } +static int cb_setup_cis_mem(socket_info_t * s, struct pci_dev *dev, struct resource *res) +{ + unsigned int start, size; + + if (res == s->cb_cis_res) + return 0; + + if (s->cb_cis_res) + cb_release_cis_mem(s); + + start = res->start; + size = res->end - start + 1; + s->cb_cis_virt = ioremap(start, size); + + if (!s->cb_cis_virt) + return -1; + + s->cb_cis_res = res; + + return 0; } /*===================================================================== @@ -242,30 +205,47 @@ =====================================================================*/ -void read_cb_mem(socket_info_t *s, u_char fn, int space, +void read_cb_mem(socket_info_t * s, u_char fn, int space, u_int addr, u_int len, void *ptr) { - DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); - if (space == 0) { - if (addr+len > 0x100) goto fail; - for (; len; addr++, ptr++, len--) - pci_readb(s->cap.cardbus, fn, addr, (u_char *)ptr); - } else { - if (cb_setup_cis_mem(s, space) != 0) goto fail; + struct pci_dev *dev; + struct resource *res; + + DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); + + dev = &s->cb_config[fn].dev; + + /* Config space? */ + if (space == 0) { + if (addr + len > 0x100) + goto fail; + for (; len; addr++, ptr++, len--) + pci_readb(dev, addr, (u_char *) ptr); + return; + } + + res = dev->resource + space - 1; + if (!res->flags) + goto fail; + + if (cb_setup_cis_mem(s, dev, res) != 0) + goto fail; + if (space == 7) { - addr = xlate_rom_addr(s->cb_cis_virt, addr); - if (addr == 0) goto fail; + addr = xlate_rom_addr(s->cb_cis_virt, addr); + if (addr == 0) + goto fail; } - if (addr+len > s->cb_cis_map.stop - s->cb_cis_map.start) - goto fail; - if (s->cb_cis_virt != NULL) - for (; len; addr++, ptr++, len--) - *(u_char *)ptr = readb(s->cb_cis_virt+addr); - } - return; - fail: - memset(ptr, 0xff, len); - return; + + if (addr + len > res->end - res->start) + goto fail; + + memcpy_fromio(ptr, s->cb_cis_virt + addr, len); + return; + +fail: + memset(ptr, 0xff, len); + return; } /*===================================================================== @@ -276,87 +256,124 @@ =====================================================================*/ -int cb_alloc(socket_info_t *s) +int cb_alloc(socket_info_t * s) { - struct pci_dev tmp; - u_short vend, v, dev; - u_char i, hdr, fn, bus = s->cap.cardbus; - cb_config_t *c; - - memset(&tmp, 0, sizeof(tmp)); - tmp.bus = s->cap.cb_bus; tmp.devfn = 0; - - - pci_read_config_word(&tmp, PCI_VENDOR_ID, &vend); - pci_read_config_word(&tmp, PCI_DEVICE_ID, &dev); - printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, " - "device 0x%04x\n", bus, vend, dev); - - pci_read_config_byte(&tmp, PCI_HEADER_TYPE, &hdr); - if (hdr & 0x80) { - /* Count functions */ - for (fn = 0; fn < 8; fn++) { - tmp.devfn = fn; - pci_read_config_word(&tmp, PCI_VENDOR_ID, &v); - if (v != vend) break; - } - } else fn = 1; - s->functions = fn; - - c = kmalloc(fn * sizeof(struct cb_config_t), GFP_ATOMIC); - if (!c) return CS_OUT_OF_RESOURCE; - memset(c, 0, fn * sizeof(struct cb_config_t)); - s->cb_config = c; - - for (i = 0; i < fn; i++) { - c[i].dev.bus = s->cap.cb_bus; - c[i].dev.devfn = i; - if (i < fn-1) { - c[i].dev.sibling = c[i].dev.next = &c[i+1].dev; - } - } - s->cap.cb_bus->devices = &c[0].dev; - /* Link into PCI device chain */ - c[fn-1].dev.next = pci_devices; - pci_devices = &c[0].dev; - for (i = 0; i < fn; i++) { - c[i].dev.vendor = vend; - pci_readw(bus, i, PCI_DEVICE_ID, &c[i].dev.device); - pci_readl(bus, i, PCI_CLASS_REVISION, &c[i].dev.class); - c[i].dev.class >>= 8; - c[i].dev.hdr_type = hdr; + struct pci_bus *bus; + struct pci_dev tmp; + u_short vend, v, dev; + u_char i, hdr, fn; + cb_config_t *c; + + bus = s->cap.cb_dev->subordinate; + memset(&tmp, 0, sizeof(tmp)); + tmp.bus = bus; + tmp.devfn = 0; + printk("bus=%p, number=%d\n", bus, bus->number); + + pci_readw(&tmp, PCI_VENDOR_ID, &vend); + pci_readw(&tmp, PCI_DEVICE_ID, &dev); + printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, " + "device 0x%04x\n", bus->number, vend, dev); + + pci_readb(&tmp, PCI_HEADER_TYPE, &hdr); + fn = 1; + if (hdr & 0x80) { + do { + tmp.devfn = fn; + pci_readw(&tmp, PCI_VENDOR_ID, &v); + if (v != vend) + break; + fn++; + } while (fn < 8); + } + s->functions = fn; + + c = kmalloc(fn * sizeof(struct cb_config_t), GFP_ATOMIC); + if (!c) + return CS_OUT_OF_RESOURCE; + memset(c, 0, fn * sizeof(struct cb_config_t)); + + for (i = 0; i < fn; i++) { + struct pci_dev *dev = &c[i].dev; + int r; + + dev->bus = bus; + dev->devfn = i; + if (i < fn - 1) { + dev->sibling = dev->next = &c[i + 1].dev; + } + dev->vendor = vend; + pci_readw(dev, PCI_DEVICE_ID, &dev->device); + dev->hdr_type = hdr; + + pci_setup_device(dev); + for (r = 0; r < 7; r++) { + struct resource *res = dev->resource + r; + if (res->flags) { + /* Unset resource address, assign new one! */ + res->end -= res->start; + res->start = 0; + pci_assign_resource(dev, r); + } + printk("Resource %d at %08lx-%08lx (%04lx)\n", + r, + res->start, + res->end, + res->flags); + } + pci_enable_device(dev); + #ifdef CONFIG_PROC_FS - pci_proc_attach_device(&c[i].dev); + pci_proc_attach_device(dev); #endif - } - - return CS_SUCCESS; + } + + /* Link into PCI device chain */ + bus->devices = &c[0].dev; + c[fn - 1].dev.next = pci_devices; + pci_devices = &c[0].dev; + s->cb_config = c; + + return CS_SUCCESS; } -void cb_free(socket_info_t *s) +static void free_resources(struct pci_dev *dev) { - cb_config_t *c = s->cb_config; + int i; - if (c) { - struct pci_dev **p; - /* Unlink from PCI device chain */ - p = &pci_devices; - while (*p) { - struct pci_dev * dev = *p; - if (dev->bus != s->cap.cb_bus) { - p = &dev->next; - continue; - } - *p = dev->next; + for (i = 0; i < 7; i++) { + struct resource *res = dev->resource + i; + if (res->parent) + release_resource(res); + } +} + +void cb_free(socket_info_t * s) +{ + cb_config_t *c = s->cb_config; + struct pci_bus *bus = s->cap.cb_dev->subordinate; + + if (c) { + struct pci_dev **p; + /* Unlink from PCI device chain */ + p = &pci_devices; + while (*p) { + struct pci_dev *dev = *p; + if (dev->bus != bus) { + p = &dev->next; + continue; + } + *p = dev->next; + free_resources(dev); #ifdef CONFIG_PROC_FS - pci_proc_detach_device(dev); + pci_proc_detach_device(dev); #endif + } + bus->devices = NULL; + kfree(s->cb_config); + s->cb_config = NULL; + printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number); } - s->cap.cb_bus->devices = NULL; - kfree(s->cb_config); - s->cb_config = NULL; - printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cardbus); - } } /*===================================================================== @@ -371,143 +388,59 @@ ======================================================================*/ -int cb_config(socket_info_t *s) +int cb_config(socket_info_t * s) { - cb_config_t *c = s->cb_config; - u_char fn = s->functions; - u_char i, j, bus = s->cap.cardbus, *name; - u_int sz, align, m, mask[3], num[3], base[3]; - int irq, try, ret; - - printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cardbus); - - /* Determine IO and memory space needs */ - num[B_IO] = num[B_M1] = num[B_M2] = 0; - mask[B_IO] = mask[B_M1] = mask[B_M2] = 0; - for (i = 0; i < fn; i++) { - for (j = 0; j < 6; j++) { - pci_writel(bus, i, CB_BAR(j), 0xffffffff); - pci_readl(bus, i, CB_BAR(j), &sz); - if (sz == 0) continue; - if (sz & PCI_BASE_ADDRESS_SPACE) { - m = B_IO; - sz &= PCI_BASE_ADDRESS_IO_MASK; - } else { - m = (sz & PCI_BASE_ADDRESS_MEM_PREFETCH) ? B_M2 : B_M1; - sz &= PCI_BASE_ADDRESS_MEM_MASK; - } - sz = FIND_FIRST_BIT(sz); - c[i].size[j] = sz | m; - if (m && (sz < PAGE_SIZE)) sz = PAGE_SIZE; - num[m] += sz; mask[m] |= sz; - } - pci_writel(bus, i, CB_ROM_BASE, 0xffffffff); - pci_readl(bus, i, CB_ROM_BASE, &sz); - if (sz != 0) { - sz = FIND_FIRST_BIT(sz & ~0x00000001); - c[i].size[6] = sz | B_M1; - if (sz < PAGE_SIZE) sz = PAGE_SIZE; - num[B_M1] += sz; mask[B_M1] |= sz; - } - } - - /* Allocate system resources */ - name = "cb_enabler"; - s->io[0].NumPorts = num[B_IO]; - s->io[0].BasePort = 0; - if (num[B_IO]) { - if (find_io_region(&s->io[0].BasePort, num[B_IO], - num[B_IO], name) != 0) { - printk(KERN_NOTICE "cs: could not allocate %d IO ports for" - " CardBus socket %d\n", num[B_IO], s->sock); - goto failed; - } - base[B_IO] = s->io[0].BasePort + num[B_IO]; - } - s->win[0].size = num[B_M1]; - s->win[0].base = 0; - if (num[B_M1]) { - if (find_mem_region(&s->win[0].base, num[B_M1], num[B_M1], - 0, name) != 0) { - printk(KERN_NOTICE "cs: could not allocate %dK memory for" - " CardBus socket %d\n", num[B_M1]/1024, s->sock); - goto failed; - } - base[B_M1] = s->win[0].base + num[B_M1]; - } - s->win[1].size = num[B_M2]; - s->win[1].base = 0; - if (num[B_M2]) { - if (find_mem_region(&s->win[1].base, num[B_M2], num[B_M2], - 0, name) != 0) { - printk(KERN_NOTICE "cs: could not allocate %dK memory for" - " CardBus socket %d\n", num[B_M2]/1024, s->sock); - goto failed; - } - base[B_M2] = s->win[1].base + num[B_M2]; - } - - /* Set up base address registers */ - while (mask[B_IO] | mask[B_M1] | mask[B_M2]) { - num[B_IO] = FIND_FIRST_BIT(mask[B_IO]); mask[B_IO] -= num[B_IO]; - num[B_M1] = FIND_FIRST_BIT(mask[B_M1]); mask[B_M1] -= num[B_M1]; - num[B_M2] = FIND_FIRST_BIT(mask[B_M2]); mask[B_M2] -= num[B_M2]; + cb_config_t *c = s->cb_config; + u_char fn = s->functions; + u_char i, j; + int irq, try, ret; + + printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cb_dev->subordinate->number); + + /* Allocate interrupt if needed */ + s->irq.AssignedIRQ = irq = 0; + ret = -1; for (i = 0; i < fn; i++) { - for (j = 0; j < 7; j++) { - sz = c[i].size[j]; - m = sz & 3; sz &= ~3; - align = (m && (sz < PAGE_SIZE)) ? PAGE_SIZE : sz; - if (sz && (align == num[m])) { - base[m] -= align; - if (j < 6) - printk(KERN_INFO " fn %d bar %d: ", i, j+1); - else - printk(KERN_INFO " fn %d rom: ", i); - printk("%s 0x%x-0x%x\n", (m) ? "mem" : "io", - base[m], base[m]+sz-1); - BASE(c[i].dev, j) = base[m]; - } - } - } - } - - /* Allocate interrupt if needed */ - s->irq.AssignedIRQ = irq = 0; ret = -1; - for (i = 0; i < fn; i++) { - pci_readb(bus, i, PCI_INTERRUPT_PIN, &j); - if (j == 0) continue; - if (irq == 0) { - if (s->cap.irq_mask & (1 << s->cap.pci_irq)) { - irq = s->cap.pci_irq; - ret = 0; - } + struct pci_dev *dev = &c[i].dev; + pci_readb(dev, PCI_INTERRUPT_PIN, &j); + if (j == 0) + continue; + if (irq == 0) { + if (s->cap.irq_mask & (1 << s->cap.pci_irq)) { + irq = s->cap.pci_irq; + ret = 0; + } #ifdef CONFIG_ISA - else - for (try = 0; try < 2; try++) { - for (irq = 0; irq < 32; irq++) - if ((s->cap.irq_mask >> irq) & 1) { - ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try); - if (ret == 0) break; + else + for (try = 0; try < 2; try++) { + for (irq = 0; irq < 32; irq++) + if ((s->cap.irq_mask >> irq) & 1) { + ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try); + if (ret == 0) + break; + } + if (ret == 0) + break; + } + if (ret != 0) { + printk(KERN_NOTICE "cs: could not allocate interrupt" + " for CardBus socket %d\n", s->sock); + goto failed; } - if (ret == 0) break; - } - if (ret != 0) { - printk(KERN_NOTICE "cs: could not allocate interrupt" - " for CardBus socket %d\n", s->sock); - goto failed; - } #endif - s->irq.AssignedIRQ = irq; + s->irq.AssignedIRQ = irq; + } } - } - for (i = 0; i < fn; i++) - c[i].dev.irq = irq; - - return CS_SUCCESS; + for (i = 0; i < fn; i++) { + struct pci_dev *dev = &c[i].dev; + dev->irq = irq; + } + + return CS_SUCCESS; -failed: - cb_release(s); - return CS_OUT_OF_RESOURCE; + failed: + cb_release(s); + return CS_OUT_OF_RESOURCE; } /*====================================================================== @@ -520,22 +453,15 @@ ======================================================================*/ -void cb_release(socket_info_t *s) +void cb_release(socket_info_t * s) { - cb_config_t *c = s->cb_config; - - DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cardbus); - - if (s->win[0].size > 0) - release_mem_region(s->win[0].base, s->win[0].size); - if (s->win[1].size > 0) - release_mem_region(s->win[1].base, s->win[1].size); - if (s->io[0].NumPorts > 0) - release_region(s->io[0].BasePort, s->io[0].NumPorts); - s->io[0].NumPorts = 0; + cb_config_t *c = s->cb_config; + + DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cb_dev->subordinate->number); + #ifdef CONFIG_ISA - if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq)) - undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq); + if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq)) + undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq); #endif } @@ -554,66 +480,32 @@ ======================================================================*/ -void cb_enable(socket_info_t *s) +void cb_enable(socket_info_t * s) { - u_char i, j, bus = s->cap.cardbus; - cb_config_t *c = s->cb_config; - - DEBUG(0, "cs: cb_enable(bus %d)\n", bus); - - /* Configure bridge */ - if (s->cb_cis_map.start) + struct pci_dev *dev; + u_char i, bus = s->cap.cb_dev->subordinate->number; + + DEBUG(0, "cs: cb_enable(bus %d)\n", bus); + + /* Configure bridge */ cb_release_cis_mem(s); - for (i = 0; i < 3; i++) { - cb_bridge_map m; - switch (i) { - case B_IO: - m.map = 0; m.flags = MAP_IOSPACE | MAP_ACTIVE; - m.start = s->io[0].BasePort; - m.stop = m.start + s->io[0].NumPorts - 1; - break; - case B_M1: - m.map = 0; m.flags = MAP_ACTIVE; - m.start = s->win[0].base; - m.stop = m.start + s->win[0].size - 1; - break; - case B_M2: - m.map = 1; m.flags = MAP_PREFETCH | MAP_ACTIVE; - m.start = s->win[1].base; - m.stop = m.start + s->win[1].size - 1; - break; - } - if (m.start == 0) continue; - DEBUG(0, " bridge %s map %d (flags 0x%x): 0x%x-0x%x\n", - (m.flags & MAP_IOSPACE) ? "io" : "mem", - m.map, m.flags, m.start, m.stop); - s->ss_entry->set_bridge(s->sock, &m); - } - - /* Set up base address registers */ - for (i = 0; i < s->functions; i++) { - for (j = 0; j < 6; j++) { - if (BASE(c[i].dev, j) != 0) - pci_writel(bus, i, CB_BAR(j), BASE(c[i].dev, j)); - } - if (ROM(c[i].dev) != 0) - pci_writel(bus, i, CB_ROM_BASE, ROM(c[i].dev) | 1); - } - - /* Set up PCI interrupt and command registers */ - for (i = 0; i < s->functions; i++) { - pci_writeb(bus, i, PCI_COMMAND, PCI_COMMAND_MASTER | - PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_writeb(bus, i, PCI_CACHE_LINE_SIZE, 8); - } - - if (s->irq.AssignedIRQ) { - for (i = 0; i < s->functions; i++) - pci_writeb(bus, i, PCI_INTERRUPT_LINE, - s->irq.AssignedIRQ); - s->socket.io_irq = s->irq.AssignedIRQ; - s->ss_entry->set_socket(s->sock, &s->socket); - } + + /* Set up PCI interrupt and command registers */ + for (i = 0; i < s->functions; i++) { + dev = &s->cb_config[i].dev; + pci_writeb(dev, PCI_COMMAND, PCI_COMMAND_MASTER | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_writeb(dev, PCI_CACHE_LINE_SIZE, 8); + } + + if (s->irq.AssignedIRQ) { + for (i = 0; i < s->functions; i++) { + dev = &s->cb_config[i].dev; + pci_writeb(dev, PCI_INTERRUPT_LINE, s->irq.AssignedIRQ); + } + s->socket.io_irq = s->irq.AssignedIRQ; + s->ss_entry->set_socket(s->sock, &s->socket); + } } /*====================================================================== @@ -625,22 +517,10 @@ ======================================================================*/ -void cb_disable(socket_info_t *s) +void cb_disable(socket_info_t * s) { - u_char i; - cb_bridge_map m = { 0, 0, 0, 0xffff }; - - DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cardbus); - - /* Turn off bridge windows */ - if (s->cb_cis_map.start) + DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cb_dev->subordinate->number); + + /* Turn off bridge windows */ cb_release_cis_mem(s); - for (i = 0; i < 3; i++) { - switch (i) { - case B_IO: m.map = 0; m.flags = MAP_IOSPACE; break; - case B_M1: m.map = m.flags = 0; break; - case B_M2: m.map = 1; m.flags = 0; break; - } - s->ss_entry->set_bridge(s->sock, &m); - } } diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c --- v2.3.35/linux/drivers/pcmcia/cistpl.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/cistpl.c Sat Jan 1 22:11:30 2000 @@ -367,7 +367,7 @@ #ifdef CONFIG_CARDBUS if (s->state & SOCKET_CARDBUS) { u_int ptr; - pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr); + pcibios_read_config_dword(s->cap.cb_dev->subordinate->number, 0, 0x28, &ptr); tuple->CISOffset = ptr & ~7; SPACE(tuple->Flags) = (ptr & 7); } else diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.3.35/linux/drivers/pcmcia/cs.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/cs.c Mon Jan 3 11:56:26 2000 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,7 @@ #include #include #include + #include "cs_internal.h" #include "rsrc_mgr.h" @@ -131,7 +133,7 @@ /*====================================================================*/ -static socket_state_t dead_socket = { +socket_state_t dead_socket = { 0, SS_DETECT, 0, 0, 0 }; @@ -276,29 +278,16 @@ return s->ss_entry->set_mem_map(s->sock, mem); } -/*====================================================================== - - Reset a socket to the default state - -======================================================================*/ - -static void init_socket(socket_info_t *s) +static int suspend_socket(socket_info_t *s) { - int i; - pccard_io_map io = { 0, 0, 0, 0, 1 }; - pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + s->socket = dead_socket; + return s->ss_entry->suspend(s->sock); +} - mem.sys_stop = s->cap.map_size; - s->socket = dead_socket; - set_socket(s, &s->socket); - for (i = 0; i < 2; i++) { - io.map = i; - set_io_map(s, &io); - } - for (i = 0; i < 5; i++) { - mem.map = i; - set_mem_map(s, &mem); - } +static int init_socket(socket_info_t *s) +{ + s->socket = dead_socket; + return s->ss_entry->init(s->sock); } /*====================================================================*/ @@ -704,7 +693,7 @@ if ((s->state & SOCKET_PRESENT) && !(s->state & SOCKET_SUSPEND)){ send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); - set_socket(s, &dead_socket); + suspend_socket(s); s->state |= SOCKET_SUSPEND; } } @@ -1007,7 +996,7 @@ config->Function = fn; config->Vcc = s->socket.Vcc; config->Vpp1 = config->Vpp2 = s->socket.Vpp; - config->Option = s->cap.cardbus; + config->Option = s->cap.cb_dev->subordinate->number; if (s->cb_config) { config->Attributes = CONF_VALID_CLIENT; config->IntType = INT_CARDBUS; @@ -1972,7 +1961,7 @@ DEBUG(1, "cs: suspending socket %d\n", i); send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); - set_socket(s, &dead_socket); + suspend_socket(s); s->state |= SOCKET_SUSPEND; return CS_SUCCESS; diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h --- v2.3.35/linux/drivers/pcmcia/cs_internal.h Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/cs_internal.h Tue Jan 4 13:33:58 2000 @@ -136,8 +136,7 @@ u_char *cis_virt; config_t *config; #ifdef CONFIG_CARDBUS - u_int cb_cis_space; - cb_bridge_map cb_cis_map; + struct resource * cb_cis_res; u_char *cb_cis_virt; struct cb_config_t *cb_config; #endif @@ -206,8 +205,7 @@ void cb_disable(socket_info_t *s); void read_cb_mem(socket_info_t *s, u_char fn, int space, u_int addr, u_int len, void *ptr); -int cb_setup_cis_mem(socket_info_t *s, int space); -void cb_release_cis_mem(socket_info_t *s); +void cb_release_cis_mem(socket_info_t * s); /* In cistpl.c */ void read_cis_mem(socket_info_t *s, int attr, diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c --- v2.3.35/linux/drivers/pcmcia/i82365.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/i82365.c Mon Jan 3 16:34:23 2000 @@ -1,7 +1,6 @@ /*====================================================================== - Device driver for Intel 82365 and compatible PC Card controllers, - and Yenta-compatible PCI-to-CardBus controllers. + Device driver for Intel 82365 and compatible PC Card controllers. i82365.c 1.265 1999/11/10 18:36:21 @@ -156,54 +155,6 @@ MODULE_PARM(cmd_time, "i"); MODULE_PARM(recov_time, "i"); -#ifdef CONFIG_PCI -/* Scan PCI bus? */ -static int do_pci_probe = 1; -static int fast_pci = -1; -static int hold_time = -1; -/* Override BIOS interrupt routing mode? */ -static int irq_mode = -1; -static int has_clkrun = -1; -static int clkrun_sel = -1; -static int pci_latency = -1; -static int cb_latency = -1; -static int cb_bus_base = 0; -static int cb_bus_step = 2; -static int cb_write_post = -1; -MODULE_PARM(do_pci_probe, "i"); -MODULE_PARM(fast_pci, "i"); -MODULE_PARM(hold_time, "i"); -MODULE_PARM(irq_mode, "i"); -MODULE_PARM(has_clkrun, "i"); -MODULE_PARM(clkrun_sel, "i"); -MODULE_PARM(pci_latency, "i"); -MODULE_PARM(cb_latency, "i"); -MODULE_PARM(cb_bus_base, "i"); -MODULE_PARM(cb_bus_step, "i"); -MODULE_PARM(cb_write_post, "i"); -#endif - -#ifdef CONFIG_ISA -#ifdef CONFIG_PCI -/* PCI card status change interrupts? */ -static int pci_csc = 0; -/* PCI IO card functional interrupts? */ -static int pci_int = 0; -MODULE_PARM(pci_csc, "i"); -MODULE_PARM(pci_int, "i"); -#else /* no PCI */ -#define pci_csc 0 -#define pci_int 0 -#endif -#else /* no ISA */ -#ifdef CONFIG_PCI -#define pci_csc 0 -#define pci_int 1 -#else -#error "No bus architectures defined!" -#endif -#endif - /*====================================================================*/ typedef struct cirrus_state_t { @@ -245,24 +196,9 @@ #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc; #endif -#ifdef CONFIG_PCI - struct pci_dev *pdev; - u_char revision; - u_short bcr; - u_char pci_lat, cb_lat, sub_bus; - u_char cache; - u_int cb_phys; - char *cb_virt; -#endif union { cirrus_state_t cirrus; vg46x_state_t vg46x; -#ifdef CONFIG_PCI - o2micro_state_t o2micro; - ti113x_state_t ti113x; - rl5c4xx_state_t rl5c4xx; - topic_state_t topic; -#endif } state; } socket_info_t; @@ -278,10 +214,8 @@ #ifdef CONFIG_ISA static int grab_irq; static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED; -#define ISA_LOCK(n, f) \ - if (!(socket[n].flags & IS_CARDBUS)) spin_lock_irqsave(&isa_lock, f) -#define ISA_UNLOCK(n, f) \ - if (!(socket[n].flags & IS_CARDBUS)) spin_unlock_irqrestore(&isa_lock, f) +#define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f) +#define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f) #else #define ISA_LOCK(n, f) do { } while (0) #define ISA_UNLOCK(n, f) do { } while (0) @@ -302,17 +236,6 @@ IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469, IS_PD6710, IS_PD672X, IS_VT83C469, #endif -#ifdef CONFIG_PCI - IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730, - IS_I82092AA, IS_OM82C092G, - IS_PD6832, IS_OZ6832, IS_OZ6836, IS_OZ6812, - IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478, - IS_SMC34C90, - IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210, - IS_TI1251A, IS_TI1251B, IS_TI1450, IS_TI1225, IS_TI1211, IS_TI1420, - IS_TOPIC95_A, IS_TOPIC95_B, IS_TOPIC97, - IS_UNK_PCI, IS_UNK_CARDBUS -#endif } pcic_id; /* Flags for classifying groups of controllers */ @@ -327,15 +250,11 @@ #define IS_VG_PWR 0x0800 #define IS_DF_PWR 0x1000 #define IS_PCI 0x2000 -#define IS_CARDBUS 0x4000 #define IS_ALIVE 0x8000 typedef struct pcic_t { char *name; u_short flags; -#ifdef CONFIG_PCI - u_short vendor, device; -#endif } pcic_t; static pcic_t pcic[] = { @@ -352,72 +271,6 @@ { "Cirrus PD672x", IS_CIRRUS }, { "VIA VT83C469", IS_CIRRUS|IS_VIA }, #endif -#ifdef CONFIG_PCI - { "Cirrus PD6729", IS_CIRRUS|IS_PCI, - PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729 }, - { "Cirrus PD6730", IS_CIRRUS|IS_PCI, - PCI_VENDOR_ID_CIRRUS, 0xffff }, - { "O2Micro OZ6729", IS_O2MICRO|IS_PCI|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6729 }, - { "O2Micro OZ6730", IS_O2MICRO|IS_PCI|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6730 }, - { "Intel 82092AA", IS_PCI, - PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82092AA_0 }, - { "Omega Micro 82C092G", IS_PCI, - PCI_VENDOR_ID_OMEGA, PCI_DEVICE_ID_OMEGA_82C092G }, - { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS, - PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832 }, - { "O2Micro OZ6832/OZ6833", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 }, - { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 }, - { "O2Micro OZ6812", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR, - PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6812 }, - { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 }, - { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466 }, - { "Ricoh RL5C475", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475 }, - { "Ricoh RL5C476", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476 }, - { "Ricoh RL5C478", IS_RICOH|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478 }, - { "SMC 34C90", IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_34C90 }, - { "TI 1130", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130 }, - { "TI 1131", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131 }, - { "TI 1250A", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250A }, - { "TI 1220", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220 }, - { "TI 1221", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221 }, - { "TI 1210", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210 }, - { "TI 1251A", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A }, - { "TI 1251B", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B }, - { "TI 1450", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450 }, - { "TI 1225", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225 }, - { "TI 1211", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211 }, - { "TI 1420", IS_TI|IS_CARDBUS|IS_DF_PWR, - PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420 }, - { "Toshiba ToPIC95-A", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, - PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_A }, - { "Toshiba ToPIC95-B", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, - PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_B }, - { "Toshiba ToPIC97", IS_CARDBUS|IS_TOPIC|IS_DF_PWR, - PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97 }, - { "Unknown", IS_PCI|IS_UNKNOWN, 0, 0 }, - { "Unknown", IS_CARDBUS|IS_DF_PWR|IS_UNKNOWN, 0, 0 } -#endif }; #define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t)) @@ -438,18 +291,10 @@ #define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r)) #define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r)) -static void cb_get_power(u_short sock, socket_state_t *state); -static void cb_set_power(u_short sock, socket_state_t *state); - /*====================================================================*/ static u_char i365_get(u_short sock, u_short reg) { -#ifdef CONFIG_PCI - if (socket[sock].cb_virt) - return cb_readb(sock, 0x0800 + reg); - else -#endif { ioaddr_t port = socket[sock].ioaddr; u_char val; @@ -461,11 +306,6 @@ static void i365_set(u_short sock, u_short reg, u_char data) { -#ifdef CONFIG_PCI - if (socket[sock].cb_virt) - cb_writeb(sock, 0x0800 + reg, data); - else -#endif { ioaddr_t port = socket[sock].ioaddr; u_char val = I365_REG(socket[sock].psock, reg); @@ -551,14 +391,6 @@ i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]); } -#ifdef CONFIG_PCI -static int cirrus_set_irq_mode(u_short s, int pcsc, int pint) -{ - flip(socket[s].bcr, PD6832_BCR_MGMT_IRQ_ENA, !pcsc); - return 0; -} -#endif /* CONFIG_PCI */ - static u_int __init cirrus_set_opts(u_short s, char *buf) { socket_info_t *t = &socket[s]; @@ -574,7 +406,7 @@ strcat(buf, " [dyn mode]"); if (p->misc1 & PD67_MC1_INPACK_ENA) strcat(buf, " [inpack]"); - if (!(t->flags & (IS_PCI | IS_CARDBUS))) { + if (!(t->flags & IS_PCI)) { if (p->misc2 & PD67_MC2_IRQ15_RI) mask &= ~0x8000; if (has_led > 0) { @@ -588,13 +420,6 @@ if (p->misc2 & PD67_MC2_FREQ_BYPASS) strcat(buf, " [freq bypass]"); } -#ifdef CONFIG_PCI - } else { - p->misc1 &= ~PD67_MC1_MEDIA_ENA; - flip(p->misc2, PD67_MC2_FAST_PCI, fast_pci); - if (p->misc2 & PD67_MC2_IRQ15_RI) - mask &= (socket[s].type == IS_PD6730) ? ~0x0400 : ~0x8000; -#endif } if (!(t->flags & IS_VIA)) { if (setup_time >= 0) @@ -670,436 +495,6 @@ #endif -/*====================================================================== - - Code to save and restore global state information for TI 1130 and - TI 1131 controllers, and to set and report global configuration - options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void ti113x_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &socket[s].state.ti113x; - config_readl(t, TI113X_SYSTEM_CONTROL, &p->sysctl); - config_readb(t, TI113X_CARD_CONTROL, &p->cardctl); - config_readb(t, TI113X_DEVICE_CONTROL, &p->devctl); - config_readb(t, TI1250_DIAGNOSTIC, &p->diag); -} - -static void ti113x_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &socket[s].state.ti113x; - config_writel(t, TI113X_SYSTEM_CONTROL, p->sysctl); - config_writeb(t, TI113X_CARD_CONTROL, p->cardctl); - config_writeb(t, TI113X_DEVICE_CONTROL, p->devctl); - config_writeb(t, TI1250_MULTIMEDIA_CTL, 0); - config_writeb(t, TI1250_DIAGNOSTIC, p->diag); - i365_set_pair(s, TI113X_IO_OFFSET(0), 0); - i365_set_pair(s, TI113X_IO_OFFSET(1), 0); -} - -static int ti113x_set_irq_mode(u_short s, int pcsc, int pint) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &t->state.ti113x; - t->intr = (pcsc) ? I365_INTR_ENA : 0; - if (t->type <= IS_TI1131) { - p->cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA | - TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC); - if (pcsc) - p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC; - if (pint) - p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ; - } else if (t->type == IS_TI1250A) { - p->diag &= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ; - if (pcsc) - p->diag |= TI1250_DIAG_PCI_CSC; - if (pint) - p->diag |= TI1250_DIAG_PCI_IREQ; - } - return 0; -} - -static u_int __init ti113x_set_opts(u_short s, char *buf) -{ - socket_info_t *t = &socket[s]; - ti113x_state_t *p = &t->state.ti113x; - u_int mask = 0xffff; - int old = (t->type <= IS_TI1131); - - flip(p->sysctl, TI113X_SCR_CLKRUN_ENA, has_clkrun); - flip(p->sysctl, TI113X_SCR_CLKRUN_SEL, clkrun_sel); - flip(p->cardctl, TI113X_CCR_RIENB, has_ring); - p->cardctl &= ~TI113X_CCR_ZVENABLE; - switch (irq_mode) { - case 1: - p->devctl &= ~TI113X_DCR_IMODE_MASK; - p->devctl |= TI113X_DCR_IMODE_ISA; - break; - case 2: - p->devctl &= ~TI113X_DCR_IMODE_MASK; - p->devctl |= TI113X_DCR_IMODE_SERIAL; - break; - case 3: - p->devctl &= ~TI113X_DCR_IMODE_MASK; - p->devctl |= TI12XX_DCR_IMODE_ALL_SERIAL; - break; - default: - if ((p->devctl & TI113X_DCR_IMODE_MASK) == 0) - p->devctl |= TI113X_DCR_IMODE_ISA; - } - if (p->cardctl & TI113X_CCR_RIENB) { - strcat(buf, " [ring]"); - if (old) mask &= ~0x8000; - } - if (old && (p->sysctl & TI113X_SCR_CLKRUN_ENA)) { - if (p->sysctl & TI113X_SCR_CLKRUN_SEL) { - strcat(buf, " [clkrun irq 12]"); - mask &= ~0x1000; - } else { - strcat(buf, " [clkrun irq 10]"); - mask &= ~0x0400; - } - } - if (p->sysctl & TI113X_SCR_PWRSAVINGS) - strcat(buf, " [pwr save]"); - switch (p->devctl & TI113X_DCR_IMODE_MASK) { - case TI12XX_DCR_IMODE_PCI_ONLY: - strcat(buf, " [pci only]"); - mask = 0; - break; - case TI113X_DCR_IMODE_ISA: - strcat(buf, " [isa irq]"); - if (old) mask &= ~0x0018; - break; - case TI113X_DCR_IMODE_SERIAL: - strcat(buf, " [pci + serial irq]"); - mask = 0xffff; - break; - case TI12XX_DCR_IMODE_ALL_SERIAL: - strcat(buf, " [serial pci & irq]"); - mask = 0xffff; - break; - } - return mask; -} - -#endif - -/*====================================================================== - - Code to save and restore global state information for the Ricoh - RL5C4XX controllers, and to set and report global configuration - options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void rl5c4xx_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; - config_readw(t, RL5C4XX_MISC, &p->misc); - config_readw(t, RL5C4XX_16BIT_CTL, &p->ctl); - config_readw(t, RL5C4XX_16BIT_IO_0, &p->io); - config_readw(t, RL5C4XX_16BIT_MEM_0, &p->mem); -} - -static void rl5c4xx_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; - config_writew(t, RL5C4XX_MISC, p->misc); - config_writew(t, RL5C4XX_16BIT_CTL, p->ctl); - config_writew(t, RL5C4XX_16BIT_IO_0, p->io); - config_writew(t, RL5C4XX_16BIT_MEM_0, p->mem); -} - -static u_int __init rl5c4xx_set_opts(u_short s, char *buf) -{ - rl5c4xx_state_t *p = &socket[s].state.rl5c4xx; - u_int mask = 0xffff; - int old = (socket[s].type < IS_RL5C475); - - p->ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; - if (old) p->ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; - - if (setup_time >= 0) { - p->io = (p->io & ~RL5C4XX_SETUP_MASK) + - ((setup_time+1) << RL5C4XX_SETUP_SHIFT); - p->mem = (p->mem & ~RL5C4XX_SETUP_MASK) + - (setup_time << RL5C4XX_SETUP_SHIFT); - } - if (cmd_time >= 0) { - p->io = (p->io & ~RL5C4XX_CMD_MASK) + - (cmd_time << RL5C4XX_CMD_SHIFT); - p->mem = (p->mem & ~RL5C4XX_CMD_MASK) + - (cmd_time << RL5C4XX_CMD_SHIFT); - } - if (hold_time >= 0) { - p->io = (p->io & ~RL5C4XX_HOLD_MASK) + - (hold_time << RL5C4XX_HOLD_SHIFT); - p->mem = (p->mem & ~RL5C4XX_HOLD_MASK) + - (hold_time << RL5C4XX_HOLD_SHIFT); - } - if (!old) { - switch (irq_mode) { - case 1: - p->misc &= ~RL5C47X_MISC_SRIRQ_ENA; break; - case 2: - p->misc |= RL5C47X_MISC_SRIRQ_ENA; break; - } - if (p->misc & RL5C47X_MISC_SRIRQ_ENA) - sprintf(buf, " [serial irq]"); - else - sprintf(buf, " [isa irq]"); - buf += strlen(buf); - } - sprintf(buf, " [io %d/%d/%d] [mem %d/%d/%d]", - (p->io & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT, - (p->io & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT, - (p->io & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT, - (p->mem & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT, - (p->mem & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT, - (p->mem & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT); - return mask; -} - -#endif - -/*====================================================================== - - Code to save and restore global state information for O2Micro - controllers, and to set and report global configuration options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void o2micro_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - o2micro_state_t *p = &socket[s].state.o2micro; - if ((t->revision == 0x34) || (t->revision == 0x62) || - (t->type == IS_OZ6812)) { - p->mode_a = i365_get(s, O2_MODE_A_2); - p->mode_b = i365_get(s, O2_MODE_B_2); - } else { - p->mode_a = i365_get(s, O2_MODE_A); - p->mode_b = i365_get(s, O2_MODE_B); - } - p->mode_c = i365_get(s, O2_MODE_C); - p->mode_d = i365_get(s, O2_MODE_D); - if (t->flags & IS_CARDBUS) { - p->mhpg = i365_get(s, O2_MHPG_DMA); - p->fifo = i365_get(s, O2_FIFO_ENA); - p->mode_e = i365_get(s, O2_MODE_E); - } -} - -static void o2micro_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - o2micro_state_t *p = &socket[s].state.o2micro; - if ((t->revision == 0x34) || (t->revision == 0x62) || - (t->type == IS_OZ6812)) { - i365_set(s, O2_MODE_A_2, p->mode_a); - i365_set(s, O2_MODE_B_2, p->mode_b); - } else { - i365_set(s, O2_MODE_A, p->mode_a); - i365_set(s, O2_MODE_B, p->mode_b); - } - i365_set(s, O2_MODE_C, p->mode_c); - i365_set(s, O2_MODE_D, p->mode_d); - if (t->flags & IS_CARDBUS) { - i365_set(s, O2_MHPG_DMA, p->mhpg); - i365_set(s, O2_FIFO_ENA, p->fifo); - i365_set(s, O2_MODE_E, p->mode_e); - } -} - -static u_int __init o2micro_set_opts(u_short s, char *buf) -{ - socket_info_t *t = &socket[s]; - o2micro_state_t *p = &socket[s].state.o2micro; - u_int mask = 0xffff; - - p->mode_b = (p->mode_b & ~O2_MODE_B_IDENT) | O2_MODE_B_ID_CSTEP; - flip(p->mode_b, O2_MODE_B_IRQ15_RI, has_ring); - p->mode_c &= ~(O2_MODE_C_ZVIDEO | O2_MODE_C_DREQ_MASK); - if (t->flags & IS_CARDBUS) { - p->mode_d &= ~O2_MODE_D_W97_IRQ; - p->mode_e &= ~O2_MODE_E_MHPG_DMA; - p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA; - p->mhpg &= ~O2_MHPG_CHANNEL; - if (t->revision == 0x34) - p->mode_c = 0x20; - } else { - if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000; - } - sprintf(buf, " [a %02x] [b %02x] [c %02x] [d %02x]", - p->mode_a, p->mode_b, p->mode_c, p->mode_d); - if (t->flags & IS_CARDBUS) { - buf += strlen(buf); - sprintf(buf, " [mhpg %02x] [fifo %02x] [e %02x]", - p->mhpg, p->fifo, p->mode_e); - } - return mask; -} - -#endif - -/*====================================================================== - - Code to save and restore global state information for the Toshiba - ToPIC 95 and 97 controllers, and to set and report global - configuration options. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void topic_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - topic_state_t *p = &socket[s].state.topic; - config_readb(t, TOPIC_SLOT_CONTROL, &p->slot); - config_readb(t, TOPIC_CARD_CONTROL, &p->ccr); - config_readb(t, TOPIC_CARD_DETECT, &p->cdr); - config_readl(t, TOPIC_REGISTER_CONTROL, &p->rcr); -} - -static void topic_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - topic_state_t *p = &socket[s].state.topic; - config_writeb(t, TOPIC_SLOT_CONTROL, p->slot); - config_writeb(t, TOPIC_CARD_CONTROL, p->ccr); - config_writeb(t, TOPIC_CARD_DETECT, p->cdr); - config_writel(t, TOPIC_REGISTER_CONTROL, p->rcr); -} - -static int topic_set_irq_mode(u_short s, int pcsc, int pint) -{ - if (socket[s].type == IS_TOPIC97) { - topic_state_t *p = &socket[s].state.topic; - flip(p->ccr, TOPIC97_ICR_IRQSEL, pcsc); - return 0; - } else { - /* no ISA card status change irq */ - return !pcsc; - } -} - -static u_int __init topic_set_opts(u_short s, char *buf) -{ - topic_state_t *p = &socket[s].state.topic; - - p->slot |= TOPIC_SLOT_SLOTON|TOPIC_SLOT_SLOTEN|TOPIC_SLOT_ID_LOCK; - p->cdr |= TOPIC_CDR_MODE_PC32; - p->cdr &= ~(TOPIC_CDR_SW_DETECT); - sprintf(buf, " [slot 0x%02x] [ccr 0x%02x] [cdr 0x%02x] [rcr 0x%02x]", - p->slot, p->ccr, p->cdr, p->rcr); - return 0xffff; -} - -#endif - -/*====================================================================== - - Routines to handle common CardBus options - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void cb_get_state(u_short s) -{ - socket_info_t *t = &socket[s]; - - config_readb(t, PCI_CACHE_LINE_SIZE, &t->cache); - config_readb(t, PCI_LATENCY_TIMER, &t->pci_lat); - config_readb(t, CB_LATENCY_TIMER, &t->cb_lat); - config_readb(t, CB_CARDBUS_BUS, &t->cap.cardbus); - config_readb(t, CB_SUBORD_BUS, &t->sub_bus); - config_readw(t, CB_BRIDGE_CONTROL, &t->bcr); - t->cap.pci_irq = t->pdev->irq; -} - -static void cb_set_state(u_short s) -{ - socket_info_t *t = &socket[s]; - pci_set_power_state(t->pdev, 0); /* FIXME: Do we really need all of this? */ - config_writel(t, CB_LEGACY_MODE_BASE, 0); - config_writel(t, PCI_BASE_ADDRESS_0, t->cb_phys); - config_writew(t, PCI_COMMAND, CMD_DFLT); - config_writeb(t, PCI_CACHE_LINE_SIZE, t->cache); - config_writeb(t, PCI_LATENCY_TIMER, t->pci_lat); - config_writeb(t, CB_LATENCY_TIMER, t->cb_lat); - config_writeb(t, CB_CARDBUS_BUS, t->cap.cardbus); - config_writeb(t, CB_SUBORD_BUS, t->sub_bus); - config_writew(t, CB_BRIDGE_CONTROL, t->bcr); -} - -static int cb_get_irq_mode(u_short s) -{ - return (!(socket[s].bcr & CB_BCR_ISA_IRQ)); -} - -static int cb_set_irq_mode(u_short s, int pcsc, int pint) -{ - socket_info_t *t = &socket[s]; - flip(t->bcr, CB_BCR_ISA_IRQ, !(pint)); - if (t->flags & IS_CIRRUS) - return cirrus_set_irq_mode(s, pcsc, pint); - else if (t->flags & IS_TI) - return ti113x_set_irq_mode(s, pcsc, pint); - else if (t->flags & IS_TOPIC) - return topic_set_irq_mode(s, pcsc, pint); - return 0; -} - -static void __init pci_scan(u_short sock); - -static void __init cb_set_opts(u_short s, char *buf) -{ - socket_info_t *t = &socket[s]; - t->bcr |= CB_BCR_WRITE_POST; - /* some TI1130's seem to exhibit problems with write posting */ - if (((t->type == IS_TI1130) && (t->revision == 4) && - (cb_write_post < 0)) || (cb_write_post == 0)) - t->bcr &= ~CB_BCR_WRITE_POST; - if (t->cache == 0) t->cache = 8; - if (pci_latency >= 0) t->pci_lat = pci_latency; - if (t->pci_lat == 0) t->pci_lat = 0xa8; - if (cb_latency >= 0) t->cb_lat = cb_latency; - if (t->cb_lat == 0) t->cb_lat = 0xb0; - if ((t->cap.pci_irq == 0) && (pci_csc || pci_int) && do_scan) - pci_scan(s); - if (t->cap.pci_irq == 0) - strcat(buf, " [no pci irq]"); - else - sprintf(buf, " [pci irq %d]", t->cap.pci_irq); - buf += strlen(buf); - if ((cb_bus_base > 0) || (t->cap.cardbus == 0)) { - if (cb_bus_base <= 0) cb_bus_base = 0x20; - t->cap.cardbus = cb_bus_base; - t->sub_bus = cb_bus_base+cb_bus_step; - cb_bus_base += cb_bus_step+1; - } - if (!(t->flags & IS_TOPIC)) - t->cap.features |= SS_CAP_PAGE_REGS; - sprintf(buf, " [lat %d/%d] [bus %d/%d]", - t->pci_lat, t->cb_lat, t->cap.cardbus, t->sub_bus); -} - -#endif /*====================================================================== @@ -1116,27 +511,11 @@ else if (t->flags & IS_VADEM) vg46x_get_state(s); #endif -#ifdef CONFIG_PCI - else if (t->flags & IS_O2MICRO) - o2micro_get_state(s); - else if (t->flags & IS_TI) - ti113x_get_state(s); - else if (t->flags & IS_RICOH) - rl5c4xx_get_state(s); - else if (t->flags & IS_TOPIC) - topic_get_state(s); - if (t->flags & IS_CARDBUS) - cb_get_state(s); -#endif } static void set_bridge_state(u_short s) { socket_info_t *t = &socket[s]; -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) - cb_set_state(s); -#endif if (t->flags & IS_CIRRUS) cirrus_set_state(s); else { @@ -1148,16 +527,6 @@ if (t->flags & IS_VADEM) vg46x_set_state(s); #endif -#ifdef CONFIG_PCI - if (t->flags & IS_O2MICRO) - o2micro_set_state(s); - else if (t->flags & IS_TI) - ti113x_set_state(s); - else if (t->flags & IS_RICOH) - rl5c4xx_set_state(s); - else if (t->flags & IS_TOPIC) - topic_set_state(s); -#endif } static u_int __init set_bridge_opts(u_short s, u_short ns) @@ -1179,32 +548,10 @@ else if (socket[i].flags & IS_VADEM) m = vg46x_set_opts(i, buf); #endif -#ifdef CONFIG_PCI - else if (socket[i].flags & IS_O2MICRO) - m = o2micro_set_opts(i, buf); - else if (socket[i].flags & IS_TI) - m = ti113x_set_opts(i, buf); - else if (socket[i].flags & IS_RICOH) - m = rl5c4xx_set_opts(i, buf); - else if (socket[i].flags & IS_TOPIC) - m = topic_set_opts(i, buf); - if (socket[i].flags & IS_CARDBUS) - cb_set_opts(i, buf+strlen(buf)); -#endif set_bridge_state(i); printk(KERN_INFO " host opts [%d]:%s\n", i, (*buf) ? buf : " none"); } -#ifdef CONFIG_PCI - /* Mask out all PCI interrupts */ - for (i = 0; i < sockets; i++) - m &= ~(1<next) - m &= ~(1<irq); - } -#endif return m; } @@ -1219,11 +566,6 @@ static void irq_count(int irq, void *dev, struct pt_regs *regs) { -#ifdef CONFIG_PCI - if (socket[irq_sock].flags & IS_CARDBUS) { - cb_writel(irq_sock, CB_SOCKET_EVENT, -1); - } else -#endif i365_get(irq_sock, I365_CSC); irq_hits++; DEBUG(2, "-> hit on irq %d\n", irq); @@ -1246,23 +588,9 @@ } /* Generate one interrupt */ -#ifdef CONFIG_PCI - if (socket[sock].flags & IS_CARDBUS) { - cb_writel(sock, CB_SOCKET_EVENT, -1); - i365_set(sock, I365_CSCINT, I365_CSC_STSCHG | (csc << 4)); - cb_writel(sock, CB_SOCKET_EVENT, -1); - cb_writel(sock, CB_SOCKET_MASK, CB_SM_CSTSCHG); - cb_writel(sock, CB_SOCKET_FORCE, CB_SE_CSTSCHG); - udelay(1000); - cb_writel(sock, CB_SOCKET_EVENT, -1); - cb_writel(sock, CB_SOCKET_MASK, 0); - } else -#endif - { - i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4)); - i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); - udelay(1000); - } + i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4)); + i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); + udelay(1000); free_irq(irq, NULL); @@ -1286,11 +614,6 @@ mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8)); #endif -#ifdef CONFIG_PCI - /* Only scan if we can select ISA csc irq's */ - if (!(socket[sock].flags & IS_CARDBUS) || - (cb_set_irq_mode(sock, 0, 0) == 0)) -#endif if (do_scan) { set_bridge_state(sock); i365_set(sock, I365_CSCINT, 0); @@ -1326,26 +649,6 @@ #endif /* CONFIG_ISA */ -#ifdef CONFIG_PCI - -static void __init pci_scan(u_short sock) -{ - u_int i; - - cb_set_irq_mode(sock, 1, 0); - set_bridge_state(sock); - i365_set(sock, I365_CSCINT, 0); - /* Only probe irq's 9..11, to be conservative */ - for (i = 9; i < 12; i++) { - if ((test_irq(sock, i, 1) == 0) && - (test_irq(sock, i, 1) == 0)) - break; - } - if (i < 12) socket[sock].cap.pci_irq = i; -} - -#endif /* CONFIG_PCI */ - /*====================================================================*/ /* Time conversion functions */ @@ -1476,16 +779,7 @@ if (base == 0) printk("\n"); printk(KERN_INFO " %s", pcic[type].name); -#ifdef CONFIG_PCI - if (t->flags & IS_UNKNOWN) - printk(" [0x%04x 0x%04x]", t->pdev->vendor, t->pdev->device); - if (t->flags & IS_CARDBUS) - printk(" PCI-to-CardBus at %s, mem 0x%08x", t->pdev->slot_name, t->cb_phys); - else if (t->flags & IS_PCI) - printk(" PCI-to-PCMCIA at %s, port %#x", t->pdev->slot_name, t->ioaddr); - else -#endif - printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", + printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", t->ioaddr, t->psock*0x40); printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : "")); @@ -1504,19 +798,7 @@ #else printk(KERN_INFO " PCI card interrupts,"); #endif - -#ifdef CONFIG_PCI - /* Can we use a PCI interrupt for card status changes? */ - if (pci_csc && t->cap.pci_irq) { - for (i = 0; i < ns; i++) - if (_check_irq(t[i].cap.pci_irq, SA_SHIRQ)) break; - if (i == ns) { - use_pci = 1; - printk(" PCI status changes\n"); - } - } -#endif - + #ifdef CONFIG_ISA /* Poll if only two interrupts available */ if (!use_pci && !poll_interval) { @@ -1554,116 +836,11 @@ t[i].cap.features |= SS_CAP_PCCARD; t[i].cap.map_size = 0x1000; t[i].cap.irq_mask = mask; - if (pci_int && t[i].cap.pci_irq) - t[i].cap.irq_mask |= (1 << t[i].cap.pci_irq); t[i].cs_irq = isa_irq; -#ifdef CONFIG_PCI - if (t[i].flags & IS_CARDBUS) { - t[i].cap.features |= SS_CAP_CARDBUS; - cb_set_irq_mode(i, pci_csc && t[i].cap.pci_irq, - pci_int && t[i].cap.pci_irq); - } -#endif } } /* add_pcic */ -/*====================================================================*/ - -#ifdef CONFIG_PCI - -static void __init add_pci_bridge(int type, struct pci_dev *dev) -{ - socket_info_t *s = &socket[sockets]; - u_short i, ns; - u32 addr = dev->resource[0].start; - - if (type == PCIC_COUNT) type = IS_UNK_PCI; - pci_write_config_word(dev, PCI_COMMAND, CMD_DFLT); - for (i = ns = 0; i < ((type == IS_I82092AA) ? 4 : 2); i++) { - s->pdev = dev; - add_socket(addr, i, type); - ns++; s++; - } - add_pcic(ns, type); -} - -static void __init add_cb_bridge(int type, struct pci_dev *dev0) -{ - socket_info_t *s = &socket[sockets]; - u_short i, ns; - u_char a, b; - - if (type == PCIC_COUNT) - type = IS_UNK_CARDBUS; - - for (ns = 0; ns < 8; ns++, s++) { - struct pci_dev *dev; - - dev = pci_find_slot(dev0->bus->number, dev0->devfn + ns); - if (!dev) - break; - s->pdev = dev; - pci_read_config_byte(dev, PCI_CLASS_REVISION, &s->revision); - - /* Map CardBus registers if they are not already mapped */ - pci_write_config_dword(dev, CB_LEGACY_MODE_BASE, 0); - s->cb_phys = dev->resource[0].start; - if (!s->cb_phys || !(s->cb_virt = ioremap(s->cb_phys, 0x1000))) { - printk("\n"); - printk(KERN_ERR " No control registers found!\n"); - break; - } - request_mem_region(s->cb_phys, 0x1000, "i82365"); - s->cap.cb_bus = dev->subordinate; - add_socket(0, 0, type); - } - if (ns == 0) return; - - s -= ns; - if (ns == 2) { - /* Nasty special check for bad bus mapping */ - config_readb(&s[0], CB_CARDBUS_BUS, &a); - config_readb(&s[1], CB_CARDBUS_BUS, &b); - if (a == b) { - config_writeb(&s[0], CB_CARDBUS_BUS, 0); - config_writeb(&s[1], CB_CARDBUS_BUS, 0); - } - } - add_pcic(ns, type); - - /* Re-do card voltage detection, if needed: this checks for - card presence with no voltage detect bits set */ - for (a = sockets-ns; a < sockets; a++) - if (!(cb_readl(a, CB_SOCKET_STATE) & 0x3c86)) - cb_writel(a, CB_SOCKET_FORCE, CB_SF_CVSTEST); - for (i = 0; i < 200; i++) { - for (a = sockets-ns; a < sockets; a++) - if (!(cb_readl(a, CB_SOCKET_STATE) & 0x3c86)) break; - if (a == sockets) break; - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/20); - } - if (i == 200) - printk(KERN_NOTICE "i82365: card voltage interrogation" - " timed out!\n"); -} - -static void __init pci_probe(u_int class, void (add_fn)(int, struct pci_dev *)) -{ - struct pci_dev *dev = NULL; - u_short i; - - while ((dev = pci_find_class(class << 8, dev))) { - pci_enable_device(dev); - if (PCI_FUNC(dev->devfn) != 0) continue; - for (i = 0; i < PCIC_COUNT; i++) - if ((pcic[i].vendor == dev->vendor) && (pcic[i].device == dev->device)) break; - add_fn(i, dev); - } -} - -#endif /* CONFIG_PCI */ /*====================================================================*/ @@ -1739,13 +916,6 @@ continue; ISA_LOCK(i, flags); csc = i365_get(i, I365_CSC); -#ifdef CONFIG_PCI - if ((socket[i].flags & IS_CARDBUS) && - (cb_readl(i,CB_SOCKET_EVENT) & (CB_SE_CCD1|CB_SE_CCD2))) { - cb_writel(i, CB_SOCKET_EVENT, CB_SE_CCD1|CB_SE_CCD2); - csc |= I365_CSC_DETECT; - } -#endif if ((csc == 0) || (!socket[i].handler) || (i365_get(i, I365_IDENT) & 0x70)) { ISA_UNLOCK(i, flags); @@ -1821,20 +991,6 @@ *value |= (status & I365_CS_READY) ? SS_READY : 0; *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0; -#ifdef CONFIG_PCI - if (socket[sock].flags & IS_CARDBUS) { - status = cb_readl(sock, CB_SOCKET_STATE); -#ifndef CONFIG_CARDBUS - *value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0; -#endif - *value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0; - *value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0; - } else if (socket[sock].flags & IS_O2MICRO) { - status = i365_get(sock, O2_MODE_B); - *value |= (status & O2_MODE_B_VS1) ? 0 : SS_3VCARD; - *value |= (status & O2_MODE_B_VS2) ? 0 : SS_XVCARD; - } -#endif #ifdef CONFIG_ISA if (socket[sock].type == IS_VG469) { status = i365_get(sock, VG469_VSENSE); @@ -1864,11 +1020,6 @@ state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; state->Vcc = state->Vpp = 0; -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) { - cb_get_power(sock, state); - } else -#endif if (t->flags & IS_CIRRUS) { if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) { if (reg & I365_VCC_5V) state->Vcc = 33; @@ -1904,12 +1055,7 @@ reg = i365_get(sock, I365_INTCTL); state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD; -#ifdef CONFIG_PCI - if (cb_get_irq_mode(sock) != 0) - state->io_irq = t->cap.pci_irq; - else -#endif - state->io_irq = reg & I365_IRQ_MASK; + state->io_irq = reg & I365_IRQ_MASK; /* speaker control */ if (t->flags & IS_CIRRUS) { @@ -1946,12 +1092,6 @@ state->Vcc, state->Vpp, state->io_irq, state->csc_mask); /* First set global controller options */ -#ifdef CONFIG_PCI - if ((t->flags & IS_CARDBUS) && t->cap.pci_irq) - cb_set_irq_mode(sock, pci_csc, - (t->cap.pci_irq == state->io_irq)); - t->bcr &= ~CB_BCR_CB_RESET; -#endif set_bridge_state(sock); /* IO card, RESET flag, IO interrupt */ @@ -1965,13 +1105,6 @@ if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) { - cb_set_power(sock, state); - reg |= i365_get(sock, I365_POWER) & - (I365_VCC_MASK|I365_VPP1_MASK); - } else -#endif if (t->flags & IS_CIRRUS) { if (state->Vpp != 0) { if (state->Vpp == 120) @@ -2053,13 +1186,6 @@ } i365_set(sock, I365_CSCINT, reg); i365_get(sock, I365_CSC); -#ifdef CONFIG_PCI - if (t->flags & IS_CARDBUS) { - if (t->cs_irq || (pci_csc && t->cap.pci_irq)) - cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD); - cb_writel(sock, CB_SOCKET_EVENT, -1); - } -#endif return 0; } /* i365_set_socket */ @@ -2145,17 +1271,6 @@ mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0; mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start; mem->card_start &= 0x3ffffff; - -#ifdef CONFIG_PCI - /* Take care of high byte, for PCI controllers */ - if (socket[sock].type == IS_PD6729) { - i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); - addr = i365_get(sock, PD67_EXT_DATA) << 24; - } else if (socket[sock].flags & IS_CARDBUS) { - addr = i365_get(sock, CB_MEM_PAGE(map)) << 24; - mem->sys_stop += addr; mem->sys_start += addr; - } -#endif DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5." "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed, @@ -2178,22 +1293,13 @@ if ((map > 4) || (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) return -EINVAL; - if (!(socket[sock].flags & (IS_PCI | IS_CARDBUS)) && + if (!(socket[sock].flags & IS_PCI) && ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff))) return -EINVAL; /* Turn off the window before changing anything */ if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); - -#ifdef CONFIG_PCI - /* Take care of high byte, for PCI controllers */ - if (socket[sock].type == IS_PD6729) { - i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); - i365_set(sock, PD67_EXT_DATA, (mem->sys_start >> 24)); - } else if (socket[sock].flags & IS_CARDBUS) - i365_set(sock, CB_MEM_PAGE(map), mem->sys_start >> 24); -#endif base = I365_MEM(map); i = (mem->sys_start >> 12) & 0x0fff; @@ -2223,186 +1329,6 @@ /*====================================================================== - Power control for Cardbus controllers: used both for 16-bit and - Cardbus cards. - -======================================================================*/ - -#ifdef CONFIG_PCI - -static void cb_get_power(u_short sock, socket_state_t *state) -{ - u_int reg = cb_readl(sock, CB_SOCKET_CONTROL); - state->Vcc = state->Vpp = 0; - switch (reg & CB_SC_VCC_MASK) { - case CB_SC_VCC_3V: state->Vcc = 33; break; - case CB_SC_VCC_5V: state->Vcc = 50; break; - } - switch (reg & CB_SC_VPP_MASK) { - case CB_SC_VPP_3V: state->Vpp = 33; break; - case CB_SC_VPP_5V: state->Vpp = 50; break; - case CB_SC_VPP_12V: state->Vpp = 120; break; - } -} - -static void cb_set_power(u_short sock, socket_state_t *state) -{ - u_int reg = 0; - switch (state->Vcc) { - case 33: reg = CB_SC_VCC_3V; break; - case 50: reg = CB_SC_VCC_5V; break; - default: reg = 0; break; - } - switch (state->Vpp) { - case 33: reg |= CB_SC_VPP_3V; break; - case 50: reg |= CB_SC_VPP_5V; break; - case 120: reg |= CB_SC_VPP_12V; break; - } - if (reg != cb_readl(sock, CB_SOCKET_CONTROL)) - cb_writel(sock, CB_SOCKET_CONTROL, reg); -} - -#endif - -/*====================================================================== - - All the stuff that is strictly for Cardbus cards goes here. - -======================================================================*/ - -#ifdef CONFIG_CARDBUS - -static int cb_get_status(u_short sock, u_int *value) -{ - u_int s; - s = cb_readl(sock, CB_SOCKET_STATE); - *value = ((s & CB_SS_32BIT) ? SS_CARDBUS : 0); - *value |= ((s & CB_SS_CCD1) || (s & CB_SS_CCD2)) ? 0 : SS_DETECT; - *value |= (s & CB_SS_CSTSCHG) ? SS_STSCHG : 0; - *value |= (s & CB_SS_PWRCYCLE) ? (SS_POWERON|SS_READY) : 0; - *value |= (s & CB_SS_3VCARD) ? SS_3VCARD : 0; - *value |= (s & CB_SS_XVCARD) ? SS_XVCARD : 0; - DEBUG(1, "yenta: GetStatus(%d) = %#4.4x\n", sock, *value); - return 0; -} /* cb_get_status */ - -static int cb_get_socket(u_short sock, socket_state_t *state) -{ - socket_info_t *s = &socket[sock]; - u_short bcr; - - cb_get_power(sock, state); - config_readw(s, CB_BRIDGE_CONTROL, &bcr); - state->flags |= (bcr & CB_BCR_CB_RESET) ? SS_RESET : 0; - if (cb_get_irq_mode(sock) != 0) - state->io_irq = s->cap.pci_irq; - else - state->io_irq = i365_get(sock, I365_INTCTL) & I365_IRQ_MASK; - DEBUG(1, "yenta: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " - "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, - state->Vcc, state->Vpp, state->io_irq, state->csc_mask); - return 0; -} /* cb_get_socket */ - -static int cb_set_socket(u_short sock, socket_state_t *state) -{ - socket_info_t *s = &socket[sock]; - u_int reg; - - DEBUG(1, "yenta: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " - "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, - state->Vcc, state->Vpp, state->io_irq, state->csc_mask); - - /* First set global controller options */ - if (s->cap.pci_irq) - cb_set_irq_mode(sock, pci_csc, - (s->cap.pci_irq == state->io_irq)); - s->bcr &= ~CB_BCR_CB_RESET; - s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0; - set_bridge_state(sock); - - cb_set_power(sock, state); - - /* Handle IO interrupt using ISA routing */ - reg = s->intr; - if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq; - i365_set(sock, I365_INTCTL, reg); - - /* Handle CSC mask */ - reg = (socket[sock].cs_irq << 4); - if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; - i365_set(sock, I365_CSCINT, reg); - i365_get(sock, I365_CSC); - if (s->cs_irq || (pci_csc && s->cap.pci_irq)) - cb_writel(sock, CB_SOCKET_MASK, CB_SM_CCD); - cb_writel(sock, CB_SOCKET_EVENT, -1); - - return 0; -} /* cb_set_socket */ - -static int cb_get_bridge(u_short sock, struct cb_bridge_map *m) -{ - socket_info_t *s = &socket[sock]; - u_char map; - - map = m->map; - if (map > 1) return -EINVAL; - m->flags &= MAP_IOSPACE; - map += (m->flags & MAP_IOSPACE) ? 2 : 0; - config_readl(s, CB_MEM_BASE(map), &m->start); - config_readl(s, CB_MEM_LIMIT(map), &m->stop); - if (m->start || m->stop) { - m->flags |= MAP_ACTIVE; - m->stop |= (map > 1) ? 3 : 0x0fff; - } - if (map > 1) { - u_short bcr; - config_readw(s, CB_BRIDGE_CONTROL, &bcr); - m->flags |= (bcr & CB_BCR_PREFETCH(map)) ? MAP_PREFETCH : 0; - } - DEBUG(1, "yenta: GetBridge(%d, %d) = %#2.2x, %#4.4x-%#4.4x\n", - sock, map, m->flags, m->start, m->stop); - return 0; -} - -static int cb_set_bridge(u_short sock, struct cb_bridge_map *m) -{ - socket_info_t *s = &socket[sock]; - u_char map; - - DEBUG(1, "yenta: SetBridge(%d, %d, %#2.2x, %#4.4x-%#4.4x)\n", - sock, m->map, m->flags, m->start, m->stop); - map = m->map; - if (!(s->flags & IS_CARDBUS) || (map > 1) || (m->stop < m->start)) - return -EINVAL; - if (m->flags & MAP_IOSPACE) { - if ((m->stop > 0xffff) || (m->start & 3) || - ((m->stop & 3) != 3)) - return -EINVAL; - map += 2; - } else { - u_short bcr; - if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff)) - return -EINVAL; - config_readw(s, CB_BRIDGE_CONTROL, &bcr); - bcr &= ~CB_BCR_PREFETCH(map); - bcr |= (m->flags & MAP_PREFETCH) ? CB_BCR_PREFETCH(map) : 0; - config_writew(s, CB_BRIDGE_CONTROL, bcr); - } - if (m->flags & MAP_ACTIVE) { - config_writel(s, CB_MEM_BASE(map), m->start); - config_writel(s, CB_MEM_LIMIT(map), m->stop); - } else { - config_writel(s, CB_MEM_BASE(map), 0); - config_writel(s, CB_MEM_LIMIT(map), 0); - } - return 0; -} - -#endif /* CONFIG_CARDBUS */ - -/*====================================================================== - Routines for accessing socket information and register dumps via /proc/bus/pccard/... @@ -2417,13 +1343,6 @@ char *p = buf; p += sprintf(p, "type: %s\npsock: %d\n", pcic[s->type].name, s->psock); -#ifdef CONFIG_PCI - if (s->flags & (IS_PCI|IS_CARDBUS)) - p += sprintf(p, "bus: %02x\ndevfn: %02x.%1x\n", - s->pdev->bus->number, PCI_SLOT(s->pdev->devfn), PCI_FUNC(s->pdev->devfn)); - if (s->flags & IS_CARDBUS) - p += sprintf(p, "cardbus: %02x\n", s->cap.cardbus); -#endif return (p - buf); } @@ -2439,8 +1358,6 @@ #endif ISA_LOCK(sock, flags); top = 0x40; - if (socket[sock].flags & IS_CARDBUS) - top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50; for (i = 0; i < top; i += 4) { if (i == 0x50) { p += sprintf(p, "\n"); @@ -2455,43 +1372,6 @@ return (p - buf); } -#ifdef CONFIG_PCI -static int proc_read_pci(char *buf, char **start, off_t pos, - int count, int *eof, void *data) -{ - socket_info_t *s = data; - char *p = buf; - u_int a, b, c, d; - int i; - - for (i = 0; i < 0xc0; i += 0x10) { - config_readl(s, i, &a); - config_readl(s, i+4, &b); - config_readl(s, i+8, &c); - config_readl(s, i+12, &d); - p += sprintf(p, "%08x %08x %08x %08x\n", a, b, c, d); - } - return (p - buf); -} -#endif - -#ifdef CONFIG_CARDBUS -static int proc_read_cardbus(char *buf, char **start, off_t pos, - int count, int *eof, void *data) -{ - u_short sock = (socket_info_t *)data - socket; - char *p = buf; - int i, top; - - top = (socket[sock].flags & IS_O2MICRO) ? 0x30 : 0x20; - for (i = 0; i < top; i += 0x10) - p += sprintf(p, "%08x %08x %08x %08x\n", - cb_readl(sock,i+0x00), cb_readl(sock,i+0x04), - cb_readl(sock,i+0x08), cb_readl(sock,i+0x0c)); - return (p - buf); -} -#endif - static void pcic_proc_setup(unsigned int sock, struct proc_dir_entry *base) { #ifdef CONFIG_PROC_FS @@ -2502,14 +1382,6 @@ create_proc_read_entry("info", 0, base, proc_read_info, s); create_proc_read_entry("exca", 0, base, proc_read_exca, s); -#ifdef CONFIG_PCI - if (s->flags & (IS_PCI|IS_CARDBUS)) - create_proc_read_entry("pci", 0, base, proc_read_pci, s); -#endif -#ifdef CONFIG_CARDBUS - if (s->flags & IS_CARDBUS) - create_proc_read_entry("cardbus", 0, base, proc_read_cardbus, s); -#endif s->proc = base; #endif } @@ -2520,14 +1392,6 @@ if (base == NULL) return; remove_proc_entry("info", base); remove_proc_entry("exca", base); -#ifdef CONFIG_PCI - if (socket[sock].flags & (IS_PCI|IS_CARDBUS)) - remove_proc_entry("pci", base); -#endif -#ifdef CONFIG_CARDBUS - if (socket[sock].flags & IS_CARDBUS) - remove_proc_entry("cardbus", base); -#endif } #endif /* CONFIG_PROC_FS */ @@ -2535,23 +1399,6 @@ /*====================================================================*/ /* - * This looks like a lot of duplication, and it is. What we should REALLY - * have is separate functions for the separate cases, instead of having - * duplicate tests in them - and then have the test in the place that sets - * up the ss_entry function pointer table instead! - * - * For example, the IS_CARDBUS thing is something we know _statically_, - * and as such it is a waste of time and space to test it dynamically. - * - * Much of this goes away by splitting off the cases. One small step at a - * time.. - */ - -#ifdef CONFIG_CARDBUS -#define is_cardbus(sock) ((socket[(sock)].flags & IS_CARDBUS) && (cb_readl((sock), CB_SOCKET_STATE) & CB_SS_32BIT)) -#endif - -/* * The locking is rather broken. Why do we only lock for ISA, not for * all other cases? If there are reasons to lock, we should lock. Not * this silly conditional. @@ -2561,15 +1408,12 @@ */ #ifdef CONFIG_ISA #define LOCKED(x) do { \ - if (socket[(sock)].flags & IS_CARDBUS) return x; \ - do { \ - int retval; \ - unsigned long flags; \ - spin_lock_irqsave(&isa_lock, flags); \ - retval = x; \ - spin_unlock_irqrestore(&isa_lock, flags); \ - return retval; \ - } while (0); \ + int retval; \ + unsigned long flags; \ + spin_lock_irqsave(&isa_lock, flags); \ + retval = x; \ + spin_unlock_irqrestore(&isa_lock, flags); \ + return retval; \ } while (0) #else #define LOCKED(x) return x @@ -2583,10 +1427,6 @@ return -EINVAL; } -#ifdef CONFIG_CARDBUS - if (is_cardbus(sock)) - return cb_get_status(sock, value); -#endif LOCKED(i365_get_status(sock, value)); } @@ -2595,10 +1435,6 @@ if (socket[sock].flags & IS_ALIVE) return -EINVAL; -#ifdef CONFIG_CARDBUS - if (is_cardbus(sock)) - return cb_get_socket(sock, state); -#endif LOCKED(i365_get_socket(sock, state)); } @@ -2607,10 +1443,6 @@ if (socket[sock].flags & IS_ALIVE) return -EINVAL; -#ifdef CONFIG_CARDBUS - if (is_cardbus(sock)) - return cb_set_socket(sock, state); -#endif LOCKED(i365_set_socket(sock, state)); } @@ -2646,25 +1478,33 @@ LOCKED(i365_set_mem_map(sock, mem)); } -static int pcic_get_bridge(unsigned int sock, struct cb_bridge_map *m) +static int pcic_init(unsigned int s) { -#ifdef CONFIG_CARDBUS - return cb_get_bridge(sock, m); -#else - return -EINVAL; -#endif + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + mem.sys_stop = 0x1000; + pcic_set_socket(s, &dead_socket); + for (i = 0; i < 2; i++) { + io.map = i; + pcic_set_io_map(s, &io); + } + for (i = 0; i < 5; i++) { + mem.map = i; + pcic_set_mem_map(s, &mem); + } + return 0; } -static int pcic_set_bridge(unsigned int sock, struct cb_bridge_map *m) +static int pcic_suspend(unsigned int sock) { -#ifdef CONFIG_CARDBUS - return cb_set_bridge(sock, m); -#else - return -EINVAL; -#endif + return pcic_set_socket(sock, &dead_socket); } static struct pccard_operations pcic_operations = { + pcic_init, + pcic_suspend, pcic_register_callback, pcic_inquire_socket, pcic_get_status, @@ -2674,8 +1514,6 @@ pcic_set_io_map, pcic_get_mem_map, pcic_set_mem_map, - pcic_get_bridge, - pcic_set_bridge, pcic_proc_setup }; @@ -2694,13 +1532,6 @@ printk(KERN_INFO "Intel PCIC probe: "); sockets = 0; -#ifdef CONFIG_PCI - if (do_pci_probe) { - pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge); - pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge); - } -#endif - #ifdef CONFIG_ISA isa_probe(); #endif @@ -2715,17 +1546,6 @@ if (grab_irq != 0) request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL); #endif -#ifdef CONFIG_PCI - if (pci_csc) { - u_int i, irq, mask = 0; - for (i = 0; i < sockets; i++) { - irq = socket[i].cap.pci_irq; - if (irq && !(mask & (1<op && socket->op->init) + return socket->op->init(socket); + return -EINVAL; +} + +static int pci_suspend_socket(unsigned int sock) +{ + pci_socket_t *socket = pci_socket_array + sock; + + if (socket->op && socket->op->suspend) + return socket->op->suspend(socket); + return -EINVAL; +} + static int pci_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void * info) { pci_socket_t *socket = pci_socket_array + sock; @@ -133,24 +139,6 @@ return -EINVAL; } -static int pci_get_bridge(unsigned int sock, struct cb_bridge_map *m) -{ - pci_socket_t *socket = pci_socket_array + sock; - - if (socket->op && socket->op->get_bridge) - return socket->op->get_bridge(socket, m); - return -EINVAL; -} - -static int pci_set_bridge(unsigned int sock, struct cb_bridge_map *m) -{ - pci_socket_t *socket = pci_socket_array + sock; - - if (socket->op && socket->op->set_bridge) - return socket->op->set_bridge(socket, m); - return -EINVAL; -} - static void pci_proc_setup(unsigned int sock, struct proc_dir_entry *base) { pci_socket_t *socket = pci_socket_array + sock; @@ -160,6 +148,8 @@ } static struct pccard_operations pci_socket_operations = { + pci_init_socket, + pci_suspend_socket, pci_register_callback, pci_inquire_socket, pci_get_status, @@ -169,29 +159,32 @@ pci_set_io_map, pci_get_mem_map, pci_set_mem_map, - pci_get_bridge, - pci_set_bridge, pci_proc_setup }; -static int __init pci_socket_probe(struct pci_dev *dev, int nr, const struct pci_simple_probe_entry * entry, void *data) +static int __init add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops) { pci_socket_t *socket = nr + pci_socket_array; - printk("Found controller %d: %s\n", nr, dev->name); socket->dev = dev; - socket->op = entry->dev_data; - socket->op->open(socket); - return 0; + socket->op = ops; + return socket->op->open(socket); } static int __init pci_socket_init(void) { - int sockets = pci_simple_probe(controller_list, MAX_SOCKETS, pci_socket_probe, NULL); + struct pci_dev *dev = NULL; + int nr = 0; + + while ((dev = pci_find_class(PCI_CLASS_BRIDGE_CARDBUS << 8, dev)) != NULL) { + printk("Adding cardbus controller %d: %s\n", nr, dev->name); + add_pci_socket(nr, dev, ¥ta_operations); + nr++; + } - if (sockets <= 0) + if (nr <= 0) return -1; - register_ss_entry(sockets, &pci_socket_operations); + register_ss_entry(nr, &pci_socket_operations); return 0; } diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/pci_socket.h linux/drivers/pcmcia/pci_socket.h --- v2.3.35/linux/drivers/pcmcia/pci_socket.h Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/pci_socket.h Tue Jan 4 12:06:50 2000 @@ -14,12 +14,15 @@ void *info; struct pci_socket_ops *op; socket_cap_t cap; + struct timer_list timer; } pci_socket_t; struct pci_socket_ops { int (*open)(struct pci_socket *); void (*close)(struct pci_socket *); + int (*init)(struct pci_socket *); + int (*suspend)(struct pci_socket *); int (*inquire)(struct pci_socket *, socket_cap_t *cap); int (*get_status)(struct pci_socket *, unsigned int *); int (*get_socket)(struct pci_socket *, socket_state_t *); @@ -28,9 +31,9 @@ int (*set_io_map)(struct pci_socket *, struct pccard_io_map *); int (*get_mem_map)(struct pci_socket *, struct pccard_mem_map *); int (*set_mem_map)(struct pci_socket *, struct pccard_mem_map *); - int (*get_bridge)(struct pci_socket *, struct cb_bridge_map *); - int (*set_bridge)(struct pci_socket *, struct cb_bridge_map *); void (*proc_setup)(struct pci_socket *, struct proc_dir_entry *base); }; extern struct pci_socket_ops yenta_operations; +extern struct pci_socket_ops ricoh_operations; + diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c --- v2.3.35/linux/drivers/pcmcia/tcic.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/tcic.c Mon Jan 3 16:34:56 2000 @@ -929,18 +929,37 @@ /*====================================================================*/ -int tcic_get_bridge(unsigned int sock, struct cb_bridge_map *m) +static void tcic_proc_setup(unsigned int sock, struct proc_dir_entry *base) { - return -EINVAL; } -#define tcic_set_bridge tcic_get_bridge +static int tcic_init(unsigned int s) +{ + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + mem.sys_stop = 0x1000; + tcic_set_socket(s, &dead_socket); + for (i = 0; i < 2; i++) { + io.map = i; + tcic_set_io_map(s, &io); + } + for (i = 0; i < 5; i++) { + mem.map = i; + tcic_set_mem_map(s, &mem); + } + return 0; +} -void tcic_proc_setup(unsigned int sock, struct proc_dir_entry *base) +static int tcic_suspend(unsigned int sock) { + return tcic_set_socket(sock, &dead_socket); } static struct pccard_operations tcic_operations = { + tcic_init, + tcic_suspend, tcic_register_callback, tcic_inquire_socket, tcic_get_status, @@ -950,8 +969,6 @@ tcic_set_io_map, tcic_get_mem_map, tcic_set_mem_map, - tcic_get_bridge, - tcic_set_bridge, tcic_proc_setup }; diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.3.35/linux/drivers/pcmcia/yenta.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/yenta.c Tue Jan 4 13:29:02 2000 @@ -1,7 +1,7 @@ /* * Regular lowlevel cardbus driver ("yenta") * - * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999, 2000 Linus Torvalds */ #include #include @@ -15,11 +15,59 @@ #include "yenta.h" #include "i82365.h" +#include "ricoh.h" /* Don't ask.. */ #define to_cycles(ns) ((ns)/120) #define to_ns(cycles) ((cycles)*120) +/* + * Generate easy-to-use ways of reading a cardbus sockets + * regular memory space ("cb_xxx"), configuration space + * ("config_xxx") and compatibility space ("exca_xxxx") + */ +#define cb_readl(sock,reg) readl((sock)->base + (reg)) +#define cb_writel(sock,reg,val) writel(val,(sock)->base + (reg)) + +static inline u8 config_readb(pci_socket_t *socket, unsigned offset) +{ + u8 val; + pci_read_config_byte(socket->dev, offset, &val); + return val; +} + +static inline u16 config_readw(pci_socket_t *socket, unsigned offset) +{ + u16 val; + pci_read_config_word(socket->dev, offset, &val); + return val; +} + +static inline u32 config_readl(pci_socket_t *socket, unsigned offset) +{ + u32 val; + pci_read_config_dword(socket->dev, offset, &val); + return val; +} + +#define config_writeb(s,off,val) pci_write_config_byte((s)->dev, (off), (val)) +#define config_writew(s,off,val) pci_write_config_word((s)->dev, (off), (val)) +#define config_writel(s,off,val) pci_write_config_dword((s)->dev, (off), (val)) + +#define exca_readb(sock,reg) readb((sock)->base + 0x800 + (reg)) +#define exca_writeb(sock,reg,v) writeb((v), (sock)->base + 0x800 + (reg)) + +static u16 exca_readw(pci_socket_t *socket, unsigned reg) +{ + return exca_readb(socket, reg) | (exca_readb(socket, reg+1) << 8); +} + +static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val) +{ + exca_writeb(socket, reg, val); + exca_writeb(socket, reg+1, val >> 8); +} + static int yenta_inquire(pci_socket_t *socket, socket_cap_t *cap) { *cap = socket->cap; @@ -27,31 +75,35 @@ } /* - * Silly interface. We convert the cardbus status to a internal status, - * and we probably really should keep it in cardbus status form and - * only convert for old-style 16-bit PCMCIA cards.. + * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend + * on what kind of card is inserted.. */ 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; + u32 state = cb_readl(socket, CB_SOCKET_STATE); - /* Convert from Yenta status to old-style status */ - val = (state & CB_CARDSTS) ? SS_STSCHG : 0; - val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT; - val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0; - val |= (state & CB_CBCARD) ? SS_CARDBUS : 0; - val |= (state & CB_3VCARD) ? SS_3VCARD : 0; + val = (state & CB_3VCARD) ? SS_3VCARD : 0; 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; - -printk("yenta_get_status(%p)= %x\n", socket, val); + if (state & CB_CBCARD) { + val |= SS_CARDBUS; + val |= (state & CB_CARDSTS) ? SS_STSCHG : 0; + val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT; + val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0; + } else { + u8 status = exca_readb(socket, I365_STATUS); + val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; + if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { + val |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; + } else { + val |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; + val |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; + } + val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; + val |= (status & I365_CS_READY) ? SS_READY : 0; + val |= (status & I365_CS_POWERON) ? SS_POWERON : 0; + } *value = val; return 0; @@ -59,32 +111,42 @@ static int yenta_Vcc_power(u32 control) { - switch ((control >> CB_VCCCTRL) & CB_PWRBITS) { - case CB_PWR5V: return 50; - case CB_PWR3V: return 33; + switch (control & CB_SC_VCC_MASK) { + case CB_SC_VCC_5V: return 50; + case CB_SC_VCC_3V: return 33; default: return 0; } } static int yenta_Vpp_power(u32 control) { - switch ((control >> CB_VPPCTRL) & CB_PWRBITS) { - case CB_PWR12V: return 120; - case CB_PWR5V: return 50; - case CB_PWR3V: return 33; + switch (control & CB_SC_VPP_MASK) { + case CB_SC_VPP_12V: return 120; + case CB_SC_VPP_5V: return 50; + case CB_SC_VPP_3V: return 33; default: return 0; } } static int yenta_get_socket(pci_socket_t *socket, socket_state_t *state) { - u32 control = cb_readl(socket, CB_SOCKET_CONTROL); u8 reg; + u32 control; + + control = cb_readl(socket, CB_SOCKET_CONTROL); state->Vcc = yenta_Vcc_power(control); state->Vpp = yenta_Vpp_power(control); state->io_irq = socket->io_irq; + if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { + u16 bridge = config_readw(socket, CB_BRIDGE_CONTROL); + if (bridge & CB_BRIDGE_CRST) + state->flags |= SS_RESET; + return 0; + } + + /* 16-bit card state.. */ reg = exca_readb(socket, I365_POWER); state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; @@ -103,81 +165,75 @@ state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; } -printk("yenta_get_socket(%p) = %d, %d\n", socket, state->Vcc, state->Vpp); - return 0; } +static void yenta_set_power(pci_socket_t *socket, socket_state_t *state) +{ + u32 reg = 0; /* CB_SC_STPCLK? */ + switch (state->Vcc) { + case 33: reg = CB_SC_VCC_3V; break; + case 50: reg = CB_SC_VCC_5V; break; + default: reg = 0; break; + } + switch (state->Vpp) { + case 33: reg |= CB_SC_VPP_3V; break; + case 50: reg |= CB_SC_VPP_5V; break; + case 120: reg |= CB_SC_VPP_12V; break; + } + if (reg != cb_readl(socket, CB_SOCKET_CONTROL)) + cb_writel(socket, CB_SOCKET_CONTROL, reg); +} + static int yenta_set_socket(pci_socket_t *socket, socket_state_t *state) { - u8 reg; u16 bridge; - u32 control; - -printk("yenta_set_socket(%p, %d, %d, %x)\n", socket, state->Vcc, state->Vpp, state->flags); - bridge = config_readw(socket, CB_BRIDGE_CONTROL); - bridge &= ~CB_BRIDGE_CRST; - bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; - config_writew(socket, CB_BRIDGE_CONTROL, bridge); - - /* Set the IO interrupt and socket state */ - reg = state->io_irq; - reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; - reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; - exca_writeb(socket, I365_INTCTL, reg); - - /* Set host interrupt and CSC mask state */ - reg = socket->cb_irq << 4; - reg |= (state->csc_mask & SS_DETECT) ? I365_CSC_DETECT : 0; - if (state->flags & SS_IOCARD) { - reg |= (state->csc_mask & SS_STSCHG) ? I365_CSC_STSCHG : 0; + yenta_set_power(socket, state); + bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_CRST; + if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { + bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; + bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN; + + /* ISA interrupt control? */ + if (bridge & CB_BRIDGE_INTR) { + u8 intr = exca_readb(socket, I365_INTCTL); + intr = (intr & ~0xf) ; // | state->io_irq; + exca_writeb(socket, I365_INTCTL, intr); + } } else { - reg |= (state->csc_mask & SS_BATDEAD) ? I365_CSC_BVD1 : 0; - reg |= (state->csc_mask & SS_BATWARN) ? I365_CSC_BVD2 : 0; - reg |= (state->csc_mask & SS_READY) ? I365_CSC_READY : 0; - } - exca_writeb(socket, I365_CSCINT, reg); - exca_readb(socket, I365_CSC); + u8 reg; - /* - * Set power state.. - * - * I wonder if we could do the Vcc/Vpp part through the - * CB interface only.. - */ - reg = I365_PWR_NORESET; - reg |= (state->flags & SS_PWR_AUTO) ? I365_PWR_AUTO : 0; - reg |= (state->flags & SS_OUTPUT_ENA) ? I365_PWR_OUT : 0; - - control = CB_STOPCLK; - switch (state->Vcc) { - case 33: - control |= CB_PWR3V << CB_VCCCTRL; - reg |= I365_VCC_5V; - break; - case 50: - control |= CB_PWR5V << CB_VCCCTRL; - reg |= I365_VCC_5V; - break; + reg = exca_readb(socket, I365_INTCTL) & I365_RING_ENA; + reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; + reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; + reg |= I365_INTR_ENA; /* CSC to PCI interrupt */ + reg |= state->io_irq; + exca_writeb(socket, I365_INTCTL, reg); + + reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK); + reg |= I365_PWR_NORESET; + if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; + if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; + if (exca_readb(socket, I365_POWER) != reg) + exca_writeb(socket, I365_POWER, reg); + + /* CSC interrupt: no ISA irq for CSC */ + reg = I365_CSC_DETECT; + if (state->flags & SS_IOCARD) { + if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; + } else { + if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1; + if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2; + if (state->csc_mask & SS_READY) reg |= I365_CSC_READY; + } + exca_writeb(socket, I365_CSCINT, reg); + exca_readb(socket, I365_CSC); } - switch (state->Vpp) { - case 33: - control |= CB_PWR3V << CB_VPPCTRL; - reg |= I365_VPP1_5V; - break; - case 50: - control |= CB_PWR5V << CB_VPPCTRL; - reg |= I365_VPP1_5V; - break; - case 120: - control |= CB_PWR12V << CB_VPPCTRL; - reg |= I365_VPP1_12V; - break; - } - exca_writeb(socket, I365_POWER, reg); - cb_writel(socket, CB_SOCKET_CONTROL, control); - + config_writew(socket, CB_BRIDGE_CONTROL, bridge); + /* Socket event mask: get card insert/remove events.. */ + cb_writel(socket, CB_SOCKET_EVENT, -1); + cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); return 0; } @@ -201,8 +257,6 @@ io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0; io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0; -printk("yenta_get_io_map(%d) = %x, %x, %x\n", map, io->start, io->stop, io->flags); - return 0; } @@ -213,8 +267,6 @@ map = io->map; -printk("yenta_set_io_map(%d, %x, %x, %x)\n", map, io->start, io->stop, io->flags); - if (map > 1) return -EINVAL; @@ -260,9 +312,7 @@ start = (start & 0x0fff) << 12; stop = exca_readw(socket, I365_MEM(map) + I365_W_STOP); - mem->speed = (stop & I365_MEM_WS0) ? 1 : 0; - mem->speed += (stop & I365_MEM_WS1) ? 2 : 0; - mem->speed = to_ns(mem->speed); + mem->speed = to_ns(stop >> 14); stop = ((stop & 0x0fff) << 12) + 0x0fff; offset = exca_readw(socket, I365_MEM(map) + I365_W_OFF); @@ -275,8 +325,6 @@ mem->sys_start = start + page; mem->sys_stop = start + page; -printk("yenta_get_map(%d) = %lx, %lx, %x\n", map, mem->sys_start, mem->sys_stop, mem->card_start); - return 0; } @@ -292,9 +340,8 @@ stop = mem->sys_stop; card_start = mem->card_start; -printk("yenta_set_map(%d, %x, %x, %x)\n", map, start, stop, card_start); - - if (map > 4 || start > stop || ((start ^ stop) >> 24) || (card_start >> 26) || mem->speed > 1000) + if (map > 4 || start > stop || ((start ^ stop) >> 24) || + (card_start >> 26) || mem->speed > 1000) return -EINVAL; enable = I365_ENA_MEM(map); @@ -334,69 +381,6 @@ return 0; } -static int yenta_get_bridge(pci_socket_t *socket, struct cb_bridge_map *m) -{ - unsigned map; - - map = m->map; - if (map > 1) - return -EINVAL; - - m->flags &= MAP_IOSPACE; - map += (m->flags & MAP_IOSPACE) ? 2 : 0; - m->start = config_readl(socket, CB_BRIDGE_BASE(map)); - m->stop = config_readl(socket, CB_BRIDGE_LIMIT(map)); - if (m->start || m->stop) { - m->flags |= MAP_ACTIVE; - m->stop |= (map > 1) ? 3 : 0x0fff; - } - - /* Get prefetch state for memory mappings */ - if (map < 2) { - u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map; - - ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - m->flags |= (ctrl & prefetch_mask) ? MAP_PREFETCH : 0; - } - return 0; -} - -static int yenta_set_bridge(pci_socket_t *socket, struct cb_bridge_map *m) -{ - unsigned map; - u32 start, end; - - map = m->map; - if (map > 1 || m->stop < m->start) - return -EINVAL; - - if (m->flags & MAP_IOSPACE) { - if ((m->stop > 0xffff) || (m->start & 3) || - ((m->stop & 3) != 3)) - return -EINVAL; - map += 2; - } else { - u16 ctrl, prefetch_mask = CB_BRIDGE_PREFETCH0 << map; - - if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff)) - return -EINVAL; - ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - ctrl &= ~prefetch_mask; - ctrl |= (m->flags & MAP_PREFETCH) ? prefetch_mask : 0; - config_writew(socket, CB_BRIDGE_CONTROL, ctrl); - } - - start = 0; - end = 0; - if (m->flags & MAP_ACTIVE) { - start = m->start; - end = m->stop; - } - config_writel(socket, CB_BRIDGE_BASE(map), start); - config_writel(socket, CB_BRIDGE_LIMIT(map), end); - return 0; -} - static void yenta_proc_setup(pci_socket_t *socket, struct proc_dir_entry *base) { /* Not done yet */ @@ -425,21 +409,42 @@ events |= (csc & I365_CSC_READY) ? SS_READY : 0; } - printk("Socket interrupt event %08x (%08x %02x)\n", events, cb_event, csc); - if (events && socket->handler) socket->handler(socket->info, events); + + mod_timer(&socket->timer, jiffies + HZ); +} + +static void yenta_timer(unsigned long data) +{ + yenta_interrupt(0, (pci_socket_t *) data, NULL); } static unsigned int yenta_probe_irq(pci_socket_t *socket) { int i; unsigned long val; + u16 bridge_ctrl; + + /* Are we set up to route the IO irq to the PCI irq? */ + bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); + if (!(bridge_ctrl & CB_BRIDGE_INTR)) { + socket->io_irq = socket->cb_irq; + if (socket->cb_irq && socket->cb_irq < 16) + return 1 << socket->cb_irq; + + /* Uhhuh. Try falling back on ISA interrupts */ + printk("CardBus: Hmm.. Bad PCI irq routing (irq%d)\n", socket->cb_irq); + bridge_ctrl |= CB_BRIDGE_INTR; + config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); + } cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); val = probe_irq_on(); for (i = 1; i < 16; i++) { + if (!((val >> i) & 1)) + continue; exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4)); cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); udelay(100); @@ -449,21 +454,156 @@ return probe_irq_mask(val); } +static void yenta_clear_maps(pci_socket_t *socket) +{ + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + mem.sys_stop = 0x0fff; + yenta_set_socket(socket, &dead_socket); + for (i = 0; i < 2; i++) { + io.map = i; + yenta_set_io_map(socket, &io); + } + for (i = 0; i < 5; i++) { + mem.map = i; + yenta_set_mem_map(socket, &mem); + } +} + +/* Called at resume and initialization events */ +static int yenta_init(pci_socket_t *socket) +{ + struct pci_dev *dev = socket->dev; + + pci_set_power_state(socket->dev, 0); + + config_writel(socket, CB_LEGACY_MODE_BASE, 0); + config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); + config_writew(socket, PCI_COMMAND, + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_WAIT); + + /* MAGIC NUMBERS! Fixme */ + config_writeb(socket, PCI_CACHE_LINE_SIZE, 32); + config_writeb(socket, PCI_LATENCY_TIMER, 168); + config_writeb(socket, PCI_SEC_LATENCY_TIMER, 176); + config_writeb(socket, PCI_PRIMARY_BUS, dev->bus->number); + config_writeb(socket, PCI_SECONDARY_BUS, dev->subordinate->number); + config_writeb(socket, PCI_SUBORDINATE_BUS, dev->subordinate->number); + + exca_writeb(socket, I365_GBLCTL, 0x00); + exca_writeb(socket, I365_GENCTL, 0x00); + + yenta_clear_maps(socket); + return 0; +} + +/* + * More of an example than anything else... The standard + * yenta init code works well enough - but this is how + * you'd do it if you wanted to have a special init sequence. + */ +static int ricoh_init(pci_socket_t *socket) +{ + u16 misc = config_readw(socket, RL5C4XX_MISC); + u16 ctl = config_readw(socket, RL5C4XX_16BIT_CTL); + u16 io = config_readw(socket, RL5C4XX_16BIT_IO_0); + u16 mem = config_readw(socket, RL5C4XX_16BIT_MEM_0); + + ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; + + config_writew(socket, RL5C4XX_MISC, misc); + config_writew(socket, RL5C4XX_16BIT_CTL, ctl); + config_writew(socket, RL5C4XX_16BIT_IO_0, io); + config_writew(socket, RL5C4XX_16BIT_MEM_0, mem); + + return yenta_init(socket); +} + + +static int yenta_suspend(pci_socket_t *socket) +{ + yenta_set_socket(socket, &dead_socket); + pci_set_power_state(socket->dev, 3); + return 0; +} + +/* + * Set static data that doesn't need re-initializing.. + */ static void yenta_get_socket_capabilities(pci_socket_t *socket) { - 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; + socket->cap.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; socket->cap.map_size = 0x1000; socket->cap.pci_irq = socket->cb_irq; - socket->cap.cardbus = config_readb(socket, PCI_CB_CARD_BUS); - socket->cap.cb_bus = socket->dev->subordinate; + socket->cap.irq_mask = yenta_probe_irq(socket); + socket->cap.cb_dev = socket->dev; socket->cap.bus = NULL; printk("Yenta IRQ list %04x\n", socket->cap.irq_mask); } +static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type) +{ + struct pci_bus *bus; + struct resource *root, *res; + u32 start, end; + u32 align, size, min, max; + unsigned offset; + + offset = 0x1c + 8*nr; + bus = socket->dev->subordinate; + res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; + printk("dev=%p, bus=%p, parent=%p\n", socket->dev, bus, socket->dev->bus); + printk("res = %p, bus->res = %p\n", res, bus->resource[nr]); + res->name = bus->name; + res->flags = type; + res->start = 0; + res->end = 0; + root = pci_find_parent_resource(socket->dev, res); + + if (!root) + return; + + start = config_readl(socket, offset); + end = config_readl(socket, offset+4) | 0xfff; + if (start && end > start) { + res->start = start; + res->end = end; + request_resource(root, res); + return; + } + + align = size = 4*1024*1024; + min = 0x10000000; max = ~0U; + if (type & IORESOURCE_IO) { + align = 1024; + size = 256; + min = 0x1000; + max = 0xffff; + } + + if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) + return; + + config_writel(socket, offset, res->start); + config_writel(socket, offset+4, res->end); +} + +/* + * Allocate the bridge mappings for the device.. + */ +static void yenta_allocate_resources(pci_socket_t *socket) +{ + yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); + yenta_allocate_res(socket, 1, IORESOURCE_MEM); + yenta_allocate_res(socket, 2, IORESOURCE_IO); +} + /* * Initialize a cardbus controller. Make sure we have a usable * interrupt, and that we can map the cardbus area. Fill in the @@ -493,16 +633,29 @@ if (!socket->base) return -1; + /* Disable all events */ + cb_writel(socket, CB_SOCKET_MASK, 0x0); + + /* Set up the bridge regions.. */ + yenta_allocate_resources(socket); + + /* + * Always poll the socket too, just in case the cardbus interrupt + * doesn't exist (it happens), or we just lose an interrupt.. + */ + init_timer(&socket->timer); + socket->timer.expires = jiffies + HZ; + socket->timer.data = (unsigned long)socket; + socket->timer.function = yenta_timer; + add_timer(&socket->timer); + if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket)) socket->cb_irq = dev->irq; - /* Figure out what the dang thing can do.. */ + /* And figure out what the dang thing can do for the PCMCIA layer... */ yenta_get_socket_capabilities(socket); - /* Enable all events */ - writel(0x0f, socket->base + 4); - - printk("Socket status: %08x\n", readl(socket->base + 8)); + printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); return 0; } @@ -517,9 +670,34 @@ iounmap(sock->base); } +/* + * Standard plain cardbus - no frills, no extensions + */ struct pci_socket_ops yenta_operations = { yenta_open, yenta_close, + yenta_init, + yenta_suspend, + yenta_inquire, + yenta_get_status, + yenta_get_socket, + yenta_set_socket, + yenta_get_io_map, + yenta_set_io_map, + yenta_get_mem_map, + yenta_set_mem_map, + yenta_proc_setup +}; + +/* + * Ricoh cardbus bridge: standard cardbus, except it needs + * some extra init code to set timings etc. + */ +struct pci_socket_ops ricoh_operations = { + yenta_open, + yenta_close, + ricoh_init, + yenta_suspend, yenta_inquire, yenta_get_status, yenta_get_socket, @@ -528,7 +706,5 @@ yenta_set_io_map, yenta_get_mem_map, yenta_set_mem_map, - yenta_get_bridge, - yenta_set_bridge, yenta_proc_setup }; diff -u --recursive --new-file v2.3.35/linux/drivers/pcmcia/yenta.h linux/drivers/pcmcia/yenta.h --- v2.3.35/linux/drivers/pcmcia/yenta.h Wed Dec 29 13:13:17 1999 +++ linux/drivers/pcmcia/yenta.h Tue Jan 4 13:33:59 2000 @@ -4,35 +4,6 @@ #include #include "pci_socket.h" -/* - * Generate easy-to-use ways of reading a cardbus sockets - * regular memory space ("cb_xxx"), configuration space - * ("config_xxx") and compatibility space ("exca_xxxx") - */ - -#define cb_readb(sock,reg) readb((sock)->base + (reg)) -#define cb_readw(sock,reg) readw((sock)->base + (reg)) -#define cb_readl(sock,reg) readl((sock)->base + (reg)) -#define cb_writeb(sock,reg,val) writeb((val), (sock)->base + (reg)) -#define cb_writew(sock,reg,val) writew((val), (sock)->base + (reg)) -#define cb_writel(sock,reg,val) writel((val), (sock)->base + (reg)) - -#define config_readb(sock,offset) ({ __u8 __val; pci_read_config_byte((sock)->dev, (offset), &__val); __val; }) -#define config_readw(sock,offset) ({ __u16 __val; pci_read_config_word((sock)->dev, (offset), &__val); __val; }) -#define config_readl(sock,offset) ({ __u32 __val; pci_read_config_dword((sock)->dev, (offset), &__val); __val; }) - -#define config_writeb(sock,offset,val) pci_write_config_byte((sock)->dev, (offset), (val)) -#define config_writew(sock,offset,val) pci_write_config_word((sock)->dev, (offset), (val)) -#define config_writel(sock,offset,val) pci_write_config_dword((sock)->dev, (offset), (val)) - -#define exca_readb(sock,reg) cb_readb((sock),(reg)+0x0800) -#define exca_readw(sock,reg) cb_readw((sock),(reg)+0x0800) -#define exca_readl(sock,reg) cb_readl((sock),(reg)+0x0800) - -#define exca_writeb(sock,reg,val) cb_writeb((sock),(reg)+0x0800,(val)) -#define exca_writew(sock,reg,val) cb_writew((sock),(reg)+0x0800,(val)) -#define exca_writel(sock,reg,val) cb_writel((sock),(reg)+0x0800,(val)) - #define CB_SOCKET_EVENT 0x00 #define CB_CSTSEVENT 0x00000001 /* Card status event */ #define CB_CD1EVENT 0x00000002 /* Card detect 1 change event */ @@ -81,17 +52,20 @@ #define CB_CVSTEST 0x00004000 /* Card VS test */ #define CB_SOCKET_CONTROL 0x10 -#define CB_VPPCTRL 0 /* Shift for Vpp */ -#define CB_VCCCTRL 4 /* Shift for Vcc */ -#define CB_STOPCLK 0x00000080 /* CLKRUN can slow CB clock when idle */ - -#define CB_PWRBITS 0x7 -#define CB_PWROFF 0x0 -#define CB_PWR12V 0x1 /* Only valid for Vpp */ -#define CB_PWR5V 0x2 -#define CB_PWR3V 0x3 -#define CB_PWRXV 0x4 -#define CB_PWRYV 0x5 +#define CB_SC_VPP_MASK 0x00000007 +#define CB_SC_VPP_OFF 0x00000000 +#define CB_SC_VPP_12V 0x00000001 +#define CB_SC_VPP_5V 0x00000002 +#define CB_SC_VPP_3V 0x00000003 +#define CB_SC_VPP_XV 0x00000004 +#define CB_SC_VPP_YV 0x00000005 +#define CB_SC_VCC_MASK 0x00000070 +#define CB_SC_VCC_OFF 0x00000000 +#define CB_SC_VCC_5V 0x00000020 +#define CB_SC_VCC_3V 0x00000030 +#define CB_SC_VCC_XV 0x00000040 +#define CB_SC_VCC_YV 0x00000050 +#define CB_SC_CCLK_STOP 0x00000080 #define CB_SOCKET_POWER 0x20 #define CB_SKTACCES 0x02000000 /* A PC card access has occurred (clear on read) */ @@ -115,6 +89,7 @@ #define CB_BRIDGE_PREFETCH0 0x00000100 #define CB_BRIDGE_PREFETCH1 0x00000200 #define CB_BRIDGE_POSTEN 0x00000400 +#define CB_LEGACY_MODE_BASE 0x44 /* * ExCA area extensions in Yenta diff -u --recursive --new-file v2.3.35/linux/drivers/sbus/char/jsflash.c linux/drivers/sbus/char/jsflash.c --- v2.3.35/linux/drivers/sbus/char/jsflash.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/sbus/char/jsflash.c Tue Jan 4 09:41:45 2000 @@ -22,7 +22,6 @@ * instead. We should discuss this. */ -#include #include #include #include diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.3.35/linux/drivers/scsi/Makefile Mon Dec 20 18:48:22 1999 +++ linux/drivers/scsi/Makefile Wed Dec 29 17:16:30 1999 @@ -13,7 +13,7 @@ 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 diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/README.aha152x linux/drivers/scsi/README.aha152x --- v2.3.35/linux/drivers/scsi/README.aha152x Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/README.aha152x Wed Dec 29 17:16:30 1999 @@ -0,0 +1,183 @@ +$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 +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=[,[,[,[,[,[, [,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. diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.3.35/linux/drivers/scsi/advansys.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/scsi/advansys.c Wed Dec 29 17:00:54 1999 @@ -1,5 +1,5 @@ -/* $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 @@ -673,6 +673,10 @@ 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. @@ -5389,9 +5393,14 @@ /* 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 @@ -5423,7 +5432,12 @@ * 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; } @@ -7476,7 +7490,7 @@ slp = (struct scatterlist *) scp->request_buffer; sg_elem_cnt = scp->use_sg; prev_sg_block = NULL; - reqp->sgblkp == NULL; + reqp->sgblkp = NULL; do { diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h --- v2.3.35/linux/drivers/scsi/advansys.h Thu Nov 11 20:11:44 1999 +++ linux/drivers/scsi/advansys.h Mon Jan 3 16:55:35 2000 @@ -1,4 +1,4 @@ -/* $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 @@ -40,9 +40,20 @@ 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 *); @@ -50,6 +61,118 @@ /* * 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, \ @@ -61,7 +184,7 @@ 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 \ @@ -77,4 +200,5 @@ */ \ use_clustering: ENABLE_CLUSTERING, \ } +#endif /* version >= v2.3.28 */ #endif /* _ADVANSYS_H */ diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.3.35/linux/drivers/scsi/aha152x.c Tue Nov 23 22:42:21 1999 +++ linux/drivers/scsi/aha152x.c Wed Dec 29 17:16:30 1999 @@ -1,13 +1,6 @@ /* 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 @@ -20,9 +13,30 @@ * 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) * @@ -181,152 +195,18 @@ * * ************************************************************************** - - - - 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=[,[,[,[,[,[, [,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 -#ifdef PCMCIA +#if defined(PCMCIA) #undef MODULE #endif @@ -342,10 +222,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include "aha152x.h" #include @@ -365,53 +248,55 @@ #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) +#if defined(AHA152X_DEBUG) +#define DEBUG_DEFAULT debug_eh -#endif +#define DPRINTK(when,msgs...) \ + do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0) -/* END OF DEFINES */ +#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 @@ -421,33 +306,76 @@ #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; @@ -461,7 +389,8 @@ int synchronous; int delay; int ext_trans; -#ifdef DEBUG_AHA152X + int tc1550; +#if defined(AHA152X_DEBUG) int debug; #endif char *conf; @@ -469,73 +398,259 @@ 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 */ + + spinlock_t lock; + /* host lock */ - int swint; - int service; +#if defined(AHA152X_DEBUG) + char *locker; /* which function has the lock */ + int lockerl; /* where did it get it */ + + int debug; /* current debugging setting */ +#endif + +#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 message[256]; - int message_len; + 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 */ -#ifdef DEBUG_AHA152X - int debug; -#endif + 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 */ @@ -562,71 +677,52 @@ 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; } } @@ -635,135 +731,113 @@ 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"); + 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] : 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; + 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=[,[," + printk(KERN_NOTICE "aha152x: usage: aha152x=[,[," "[,[,[,[,[,[,]]]]]]]]\n"); #else - if (ints[0] > 8) { - printk("aha152x: usage: aha152x=[,[," + if (ints[0] > 8) { /*}*/ + printk(KERN_NOTICE "aha152x: usage: aha152x=[,[," "[,[,[,[,[,]]]]]]]\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 countswint++; } @@ -835,29 +933,28 @@ #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, @@ -871,13 +968,13 @@ } #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, @@ -892,23 +989,39 @@ #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, @@ -918,23 +1031,39 @@ 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, @@ -953,14 +1082,14 @@ 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; @@ -971,6 +1100,26 @@ 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); @@ -979,10 +1128,10 @@ 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++; @@ -996,40 +1145,75 @@ printk("detected %d controller(s)\n", setup_count); - for (i = 0; i < setup_count; i++) { + for (i=0; iio_port = setup[i].io_port; + shpnt->io_port = setup[i].io_port; shpnt->n_io_port = IO_RANGE; - shpnt->irq = setup[i].irq; + shpnt->irq = setup[i].irq; + + 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; + } - 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 + ISSUE_SC = 0; + CURRENT_SC = 0; + DONE_SC = 0; + DISCONNECTED_SC = 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)->aborting = 0; - HOSTDATA(shpnt)->abortion_complete = 0; - HOSTDATA(shpnt)->abort_result = 0; + HOSTDATA(shpnt)->in_intr = 0; HOSTDATA(shpnt)->commands = 0; - HOSTDATA(shpnt)->message_len = 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; jcount[j]=0; + HOSTDATA(shpnt)->count_trans[j]=0; + HOSTDATA(shpnt)->time[j]=0; + } +#endif - for (j = 0; j < 8; j++) + 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; @@ -1037,59 +1221,73 @@ 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); - - 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, +#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 + + 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) { @@ -1099,7 +1297,7 @@ 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--; @@ -1109,60 +1307,114 @@ } 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"); - } - } - - return (registered_count > 0); -} - + 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; +} + int aha152x_release(struct Scsi_Host *shpnt) { 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 @@ -1170,193 +1422,265 @@ 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); + + /* + * FIXME: + * for current command: queue ABORT for message out and raise ATN + * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? + * + */ - if (!CURRENT_SC) - printk("bus busy w/o current command, "); + printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt)); - restore_flags(flags); + return FAILED; +} - return SCSI_ABORT_BUSY; - } - /* bus is free */ +static void timer_expired(unsigned long p) +{ + struct semaphore *sem = (void *)p; - if (CURRENT_SC) { - HOSTDATA(shpnt)->commands--; + printk(KERN_INFO "aha152x: timer expired\n"); + up(sem); +} - /* 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); - - 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); - - if (!ptr) { - /* command wasn't found */ - printk("command not found\n"); - restore_flags(flags); +/* + * 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 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; + } +} + +void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs) +{ + Scsi_Cmnd *ptr; + unsigned long flags; - restore_flags(flags); + DO_LOCK(flags); - /* sleep until the abortion is complete */ - while (!HOSTDATA(shpnt)->abortion_complete) - barrier(); - HOSTDATA(shpnt)->aborting = 0; + ptr=*SCs; + while(ptr) { + Scsi_Cmnd *next = SCNEXT(ptr); - return HOSTDATA(shpnt)->abort_result; - } else { - /* we're already aborting a command */ - restore_flags(flags); + 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); @@ -1364,7 +1688,7 @@ SETPORT(SXFRCTL1, 0); SETPORT(SCSISIG, 0); - SETPORT(SCSIRATE, 0); + SETRATE(0); /* clear all interrupt conditions */ SETPORT(SSTAT0, 0x7f); @@ -1377,106 +1701,41 @@ 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); - - /* Reset, if bus hangs */ - if (TESTLO(SSTAT1, BUSFREE)) { - CLRBITS(DMACNTRL0, INTEN); - -#if defined(DEBUG_RESET) - if (HOSTDATA(shpnt)->debug & debug_reset) { - printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); - show_queues(shpnt); - } -#endif - - 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 + DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt); - /* RESET OUT */ - SETPORT(SCSISEQ, SCSIRSTO); - do_pause(30); - SETPORT(SCSISEQ, 0); - do_pause(DELAY); + aha152x_bus_reset(SCpnt); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt)); + reset_ports(SCpnt->host); - 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; @@ -1490,16 +1749,18 @@ 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]; @@ -1507,1158 +1768,1211 @@ 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 - - save_flags(flags); - cli(); + if(DONE_SC) + printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC); - 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; + SETPORT(SSTAT1, CLRBUSFREE); + + if(CURRENT_SC) { +#if defined(AHA152X_STAT) + action++; +#endif + 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; - /* 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+, "); -#endif - save_flags(flags); - cli(); - append_SC(&ISSUE_SC, CURRENT_SC); - CURRENT_SC = NULL; - restore_flags(flags); + } else { + done(shpnt, DID_ERROR << 16); } - /* 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, "); +#if defined(AHA152X_STAT) + } else { + HOSTDATA(shpnt)->busfree_without_old_command++; #endif + } - i = GETPORT(SELID) & ~(1 << shpnt->this_id); - target = 0; + DO_LOCK(flags); - if (i == 0) - aha152x_panic(shpnt, "reconnecting target unknown"); + if(DONE_SC) { +#if defined(AHA152X_STAT) + action++; +#endif + if(SCDONE(DONE_SC)) { + Scsi_Cmnd *ptr=DONE_SC; + DONE_SC=SCDONE(DONE_SC); - for (; (i & 1) == 0; target++, i >>= 1); +#if 0 + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(ERR_LEAD "received sense: ", CMDINFO(ptr)); + print_sense("bh", DONE_SC); + } +#endif -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ + + 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 - SETPORT(SCSIID, (shpnt->this_id << OID_) | target); - SETPORT(SCSISEQ, ENRESELI); - if (TESTLO(SSTAT0, SELDI)) - aha152x_panic(shpnt, "RESELI failed"); + if(!(DONE_SC->SCp.Status & not_issued)) { + Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); - SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f); + if(cmnd) { + Scsi_Cmnd *ptr=DONE_SC; + DONE_SC=0; - SETPORT(SCSISIG, P_MSGI); +#if 0 + DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr)); +#endif - /* 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"); + 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); - identify_msg = GETPORT(SCSIBUS); - - if (!(identify_msg & IDENTIFY_BASE)) { - printk("target=%d, inbound message (%02x) != IDENTIFY\n", - target, identify_msg); - aha152x_panic(shpnt, "unknown lun"); + 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 */ + + kfree(DONE_SC->host_scribble); + DONE_SC->host_scribble=0; + + 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); + DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC)); - make_acklow(shpnt); - if (getphase(shpnt) != P_MSGI) { - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); -#if defined(DEBUG_RACE) - leave_driver("(reselected) intr"); + /* 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, "); -#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); + +#if defined(AHA152X_STAT) + if(!action) + HOSTDATA(shpnt)->busfree_without_any_action++; #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); +} - /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ - SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER); +/* + * 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 TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); + CURRENT_SC->SCp.phase &= ~(selecting|not_issued); - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + SETPORT(SCSISEQ, 0); - } 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); - } + if (TESTLO(SSTAT0, SELDO)) { + printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_NO_CONNECT << 16); + return; + } -#if defined(DEBUG_RACE) - leave_driver("(selecting) intr"); -#endif - SETBITS(DMACNTRL0, INTEN); + 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 */ + } + + 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); - - /* Disable SELECTION OUT DONE interrupt */ - CLRBITS(SIMODE0, ENSELDO); - CLRBITS(SIMODE1, ENSELTIMO); - - if (TESTLO(SSTAT0, SELDO)) { - printk("aha152x: passing bus free condition\n"); - -#if defined(DEBUG_RACE) - leave_driver("(passing bus free) intr"); -#endif - SETBITS(DMACNTRL0, INTEN); - - if (CURRENT_SC->SCp.phase & aborted) { - HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } - aha152x_done(shpnt, DID_NO_CONNECT << 16); + 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); + } +} - return; - } -#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) - printk("SELDO (SELID=%x), ", GETPORT(SELID)); -#endif +/* + * 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; - /* selection was done */ - SETPORT(SSTAT0, CLRSELDO); + SETPORT(SCSISIG, 0); + SETPORT(SSTAT0, CLRSELDI); + SETPORT(SSTAT1, CLRBUSFREE); + SETPORT(SSTAT1, CLRPHASECHG); -#if defined(DEBUG_ABORT) - if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) - printk("(ABORT) target selected, "); -#endif + if(CURRENT_SC) { + if(!(CURRENT_SC->SCp.phase & not_issued)) + printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC)); - CURRENT_SC->SCp.phase &= ~in_selection; - CURRENT_SC->SCp.phase |= in_other; + DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC)); - ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)); + DO_LOCK(flags); + append_SC(&ISSUE_SC, CURRENT_SC); + DO_UNLOCK(flags); - if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) { - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - ADDMSG(50); - ADDMSG(8); + CURRENT_SC = 0; + } - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN - 5)); + if(!DISCONNECTED_SC) { + DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC)); + return; + } - SYNCRATE = 0x80; - CURRENT_SC->SCp.phase |= in_sync; - } -#if defined(DEBUG_RACE) - leave_driver("(SELDO) intr"); -#endif - SETPORT(SCSIRATE, SYNCRATE & 0x7f); + RECONN_TARGET=-1; - SETPORT(SCSISIG, P_MSGO); + selid = GETPORT(SELID) & ~(1 << shpnt->this_id); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); - SETBITS(DMACNTRL0, INTEN); + if (selid==0) { + printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid); + return; + } - 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); - - /* timeout */ - SETPORT(SSTAT1, CLRSELTIMO); - - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS(DMACNTRL0, INTEN); -#if defined(DEBUG_RACE) - leave_driver("(SELTO) intr"); -#endif - - 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); + for(target=7; !(selid & (1 << target)); target--) + ; - return; - } + if(selid & ~(1 << target)) { + printk("aha152x%d: multiple targets reconnected (%02x)\n", + HOSTNO, selid); } - /* 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, "); + + SETPORT(SCSIID, (shpnt->this_id << OID_) | target); + SETPORT(SCSISEQ, 0); + + SETRATE(HOSTDATA(shpnt)->syncrate[target]); + + RECONN_TARGET=target; + DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid); +} + +/* + * 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(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"); + } #endif + + if(!CURRENT_SC) { + if(LASTSTATE!=seldi) { + printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO); } - CLRBITS(SXFRCTL0, ENDMA); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); + /* + * Handle reselection + */ + if(!(MSGI(0) & IDENTIFY_BASE)) { + printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO); + continue; + } - /* wait for data latch to become ready or a phase change */ - while (TESTLO(DMASTAT, INTSTAT)) - barrier(); + CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f); -#if defined(DEBUG_MSGO) - if (HOSTDATA(shpnt)->debug & debug_msgo) { - int i; - - 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 || MSGILENsynchronous) + break; - for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { - SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); + printk(INFO_LEAD, CMDINFO(CURRENT_SC)); + print_msg(&MSGI(0)); + printk("\n"); + + ticks = (MSGI(3) * 4 + 49) / 50; + + 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); + } - make_acklow(shpnt); - getphase(shpnt); - } + SYNCNEG=2; /* negotiation completed */ + SETRATE(SYNCRATE); + } + break; - if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS)) - aha152x_panic(shpnt, "target left COMMAND"); + case BUS_DEVICE_RESET: + { + int i; + + for(i=0; i<8; i++) { + HOSTDATA(shpnt)->syncrate[i]=0; + HOSTDATA(shpnt)->syncneg[i]=0; + } - CURRENT_SC->SCp.sent_command++; - } else - aha152x_panic(shpnt, "Nothing to send while in COMMAND"); - break; + } + break; - case P_MSGI: /* MESSAGE IN phase */ - { - int start_sync = 0; - -#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 EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + case EXTENDED_WDTR: + default: + ADDMSGO(MESSAGE_REJECT); + break; + } + break; + } - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENBUSFREE); + MSGILEN=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 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; - - case SAVE_POINTERS: -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (SAVE DATA POINTERS), "); -#endif - break; - - case RESTORE_POINTERS: -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (RESTORE DATA POINTERS), "); -#endif - break; - - case EXTENDED_MESSAGE: - { - char buffer[16]; - int i; - -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (EXTENDED MESSAGE), "); -#endif - make_acklow(shpnt); - if (getphase(shpnt) != P_MSGI) - 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); + + if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) { + DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC)); + SETPORT(SCSISIG, P_MSGI | SIG_ATNO); + } +} - buffer[0] = EXTENDED_MESSAGE; - buffer[1] = GETPORT(SCSIDAT); +/* + * 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); + } + } - for (i = 0; i < buffer[1] && - (make_acklow(shpnt), getphase(shpnt) == P_MSGI); i++) - buffer[2 + i] = GETPORT(SCSIDAT); +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_msgo) { + int i; -#if defined(DEBUG_MSGI) - if (HOSTDATA(shpnt)->debug & debug_msgi) - print_msg(buffer); + printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC)); + for (i=0; isynchronous) - break; + while(MSGO_ISCp.phase & in_sync) { - /* we initiated SDTR */ - if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8) - aha152x_panic(shpnt, "received SDTR invalid"); - SYNCRATE |= ((ticks - 2) << 4) + buffer[4]; - } else if (ticks <= 9 && buffer[4] >= 1) { - if (buffer[4] > 8) - buffer[4] = 8; + if (MSGO(MSGO_I) & IDENTIFY_BASE) + CURRENT_SC->SCp.phase |= identified; - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - if (ticks < 4) { - ticks = 4; - ADDMSG(50); - } else - ADDMSG(buffer[3]); + if (MSGO(MSGO_I)==ABORT) + CURRENT_SC->SCp.phase |= aborted; - ADDMSG(buffer[4]); + if (MSGO(MSGO_I)==BUS_DEVICE_RESET) + CURRENT_SC->SCp.phase |= resetted; - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN - 5)); + SETPORT(SCSIDAT, MSGO(MSGO_I++)); + } +} - CURRENT_SC->SCp.phase |= in_sync; +static void msgo_end(struct Scsi_Host *shpnt) +{ + if(MSGO_ISCp.sent_command) { + printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_ERROR << 16); + return; + } - start_sync++; - } else { - /* requested SDTR is too slow, do it asynchronously */ - ADDMSG(MESSAGE_REJECT); - SYNCRATE = 0; - } +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_cmd) { + printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC)); + print_command(CURRENT_SC->cmnd); + } +#endif - SETPORT(SCSIRATE, SYNCRATE & 0x7f); - } - break; + CMD_I=0; +} - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - case EXTENDED_WDTR: - default: - ADDMSG(MESSAGE_REJECT); - break; - } - } - break; +/* + * 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); + } - default: - printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); - break; + while(CMD_Icmd_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); - } + if(TESTLO(SSTAT0, SPIORDY)) { + DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; + } - make_acklow(shpnt); - phase = getphase(shpnt); - } + SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]); + } +} - if (start_sync) - CURRENT_SC->SCp.phase |= in_sync; - else - CURRENT_SC->SCp.phase &= ~in_sync; +static void cmd_end(struct Scsi_Host *shpnt) +{ + if(CMD_Icmd_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++; +} - if (MSGLEN > 0) - SETPORT(SCSISIG, P_MSGI | ATNO); +/* + * 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; + } - /* clear SCSI fifo on BUSFREE */ - if (phase == P_BUSFREE) - SETPORT(SXFRCTL0, CH1 | CLRCH1); + CURRENT_SC->SCp.Status = GETPORT(SCSIDAT); - if (CURRENT_SC->SCp.phase & disconnected) { - save_flags(flags); - cli(); -#if defined(DEBUG_QUEUES) - if (HOSTDATA(shpnt)->debug & debug_queues) - printk("d+, "); +#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 - append_SC(&DISCONNECTED_SC, CURRENT_SC); - CURRENT_SC->SCp.phase |= 1 << 16; - CURRENT_SC = NULL; - restore_flags(flags); - - SETBITS(SCSISEQ, ENRESELI); +} - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); +/* + * data in phase + * + */ +static void datai_init(struct Scsi_Host *shpnt) +{ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO|ENDMA); - SETBITS(DMACNTRL0, INTEN); + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); - return; - } - } - break; + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE); - 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); + 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, 0); - SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); +static void datai_run(struct Scsi_Host *shpnt) +{ + unsigned int the_time; + int fifodata, data_count; - if (TESTHI(SSTAT1, PHASEMIS)) - printk("aha152x: passing STATUS phase"); + /* + * 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(); - CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); - make_acklow(shpnt); - getphase(shpnt); - -#if defined(DEBUG_STATUS) - if (HOSTDATA(shpnt)->debug & debug_status) { - printk("inbound status "); - print_status(CURRENT_SC->SCp.Status); - printk(", "); + if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) { + printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; } -#endif - break; - case P_DATAI: /* DATA IN phase */ - { - int fifodata, data_count, done; - -#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(TESTHI(DMASTAT, DFIFOFULL)) { + fifodata = 128; + } else { + the_time=jiffies + 100; + while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time)) + barrier(); -#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(TESTLO(SSTAT2, SEMPTY)) { + printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; + } - /* reset host fifo */ - SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(DMACNTRL0, RSTFIFO | ENDMA); + fifodata = GETPORT(FIFOSTAT); + } - SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN); + 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; + } + } - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); + 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; + } + } - /* done is set when the FIFO is empty after the target left DATA IN */ - done = 0; + 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); + } - /* 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(); + 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); + } +} -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("ok, "); -#endif +static void datai_end(struct Scsi_Host *shpnt) +{ + CURRENT_SC->resid -= GETSTCNT(); - if (TESTHI(DMASTAT, DFIFOFULL)) - fifodata = GETPORT(FIFOSTAT); - else { - /* wait for SCSI fifo to get empty */ - while (TESTLO(SSTAT2, SEMPTY)) - barrier(); + 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()); - /* rest of data in FIFO */ - fifodata = GETPORT(FIFOSTAT); -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("last transfer, "); -#endif - done = 1; - } + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(DMACNTRL0, 0); +} -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("fifodata=%d, ", fifodata); -#endif +/* + * data out phase + * + */ +static void datao_init(struct Scsi_Host *shpnt) +{ + SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); + SETPORT(DMACNTRL0, WRITE_READ | ENDMA); - while (fifodata && CURRENT_SC->SCp.this_residual) { - data_count = fifodata; + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); - /* limit data transfer to size of first sg buffer */ - if (data_count > CURRENT_SC->SCp.this_residual) - data_count = CURRENT_SC->SCp.this_residual; + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ); - fifodata -= data_count; + DATA_LEN = CURRENT_SC->resid; -#if defined(DEBUG_DATAI) - if (HOSTDATA(shpnt)->debug & debug_datai) - printk("data_count=%d, ", data_count); -#endif + DPRINTK(debug_datao, + DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n", + CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid); +} - 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 +static void datao_run(struct Scsi_Host *shpnt) +{ + unsigned int the_time; + int data_count; - 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; - } - } + /* 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; - /* - * 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 - } + if(TESTLO(DMASTAT, DFIFOEMP)) { + printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT)); + disp_ports(shpnt); + break; + } -#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); + 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); + } + + 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) || defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr)) - printk("got %d bytes, ", GETSTCNT()); -#endif + the_time=jiffies+100; + while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time)) + barrier(); - CURRENT_SC->SCp.have_data_in++; + if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) { + printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; } - break; - - case P_DATAO: /* DATA OUT phase */ - { - int data_count; - -#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 (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); +static void datao_end(struct Scsi_Host *shpnt) +{ + if(TESTLO(DMASTAT, DFIFOEMP)) { + int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT(); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); + 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()); - /* 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 - - 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 - - /* 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; - } - } + CURRENT_SC->resid += data_count; - if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { - /* target leaves DATA OUT for an other phase (perhaps disconnect) */ + 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; + } - /* data in fifos has to be resend */ - data_count = GETPORT(SSTAT2) & (SFULL | SFCNT); + 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()); - 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); - - /* transfer can be considered ended, when SCSIEN reads back zero */ - while (TESTHI(SXFRCTL0, SCSIEN)) - barrier(); + SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1); - CLRBITS(DMACNTRL0, ENDMA); - } + SETPORT(DMACNTRL0, 0); +} -#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) - if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr)) - printk("sent %d data bytes, ", GETSTCNT()); -#endif +/* + * 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_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); + if((stat0 & SELDI) && STATE!=seldi && !dataphase) { + printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + } - aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ - return; - break; + if(STATE!=PREVSTATE) { + LASTSTATE=PREVSTATE; + } - case P_PARITY: /* parity error in DATA phase */ -#if defined(DEBUG_RACE) - leave_driver("(DID_PARITY) intr"); -#endif - printk("PARITY error in DATA phase, "); + return dataphase; +} - CURRENT_SC->SCp.phase &= ~(P_MASK << 16); +/* + * 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); +} - SETBITS(DMACNTRL0, INTEN); - aha152x_done(shpnt, DID_PARITY << 16); - return; - break; +/* + * handle reset in + * + */ +static void rsti_run(struct Scsi_Host *shpnt) +{ + Scsi_Cmnd *ptr; - default: - printk("aha152x: unexpected phase\n"); - break; - } + printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO); + + ptr=DISCONNECTED_SC; + while(ptr) { + Scsi_Cmnd *next = SCNEXT(ptr); - 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 + if (!ptr->device->soft_reset) { + remove_SC(&DISCONNECTED_SC, ptr); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + kfree(ptr->host_scribble); + ptr->host_scribble=0; - SETBITS(DMACNTRL0, INTEN); + ptr->result = DID_RESET << 16; + ptr->scsi_done(ptr); + } - aha152x_done(shpnt, - (CURRENT_SC->SCp.Status & 0xff) - | ((CURRENT_SC->SCp.Message & 0xff) << 8) - | (DID_OK << 16)); - -#if defined(DEBUG_RACE) - printk("done returned (DID_OK: Status=%x; Message=%x).\n", - CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); -#endif - return; + ptr = next; } - if (CURRENT_SC) - CURRENT_SC->SCp.phase |= 1 << 16; - 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 + if(CURRENT_SC && !CURRENT_SC->device->soft_reset) + done(shpnt, DID_RESET << 16 ); +} + +/* + * bottom-half handler + * + */ +static void complete(struct Scsi_Host *shpnt) +{ + int dataphase; + unsigned long flags; + int pending; + + DO_LOCK(flags); + if(HOSTDATA(shpnt)->in_intr!=0) + aha152x_error(shpnt, "bottom-half already running!?"); + HOSTDATA(shpnt)->in_intr++; + DO_UNLOCK(flags); + + /* + * 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"); } /* @@ -2666,18 +2980,16 @@ */ 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) @@ -2696,7 +3008,7 @@ printk("SCSIRSTO "); printk(");"); - printk(" SCSISIG ("); + printk(" SCSISIG("); s = GETPORT(SCSISIG); switch (s & P_MASK) { case P_DATAO: @@ -2726,7 +3038,7 @@ printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - printk("SSTAT ("); + printk("SSTAT( "); s = GETPORT(SSTAT0); if (s & TARGET) printk("TARGET "); @@ -2765,7 +3077,7 @@ printk("); "); - printk("SSTAT ("); + printk("SSTAT( "); s = GETPORT(SSTAT0) & GETPORT(SIMODE0); @@ -2806,7 +3118,7 @@ printk("REQINIT "); printk("); "); - printk("SXFRCTL0 ("); + printk("SXFRCTL0( "); s = GETPORT(SXFRCTL0); if (s & SCSIEN) @@ -2823,24 +3135,26 @@ 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) @@ -2854,7 +3168,7 @@ 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 "); @@ -2864,7 +3178,7 @@ printk("FRERR "); printk("); "); - printk("DMACNTRL0 ("); + printk("DMACNTRL0( "); s = GETPORT(DMACNTRL0); printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); printk("%s ", s & DMA ? "DMA" : "PIO"); @@ -2879,7 +3193,7 @@ printk("SWINT "); printk("); "); - printk("DMASTAT ("); + printk("DMASTAT( "); s = GETPORT(DMASTAT); if (s & ATDONE) printk("ATDONE "); @@ -2889,9 +3203,7 @@ printk("DFIFOFULL "); if (s & DFIFOEMP) printk("DFIFOEMP "); - printk(")"); - - printk("\n"); + printk(")\n"); #endif } @@ -2902,7 +3214,7 @@ { int s; - printk("enabled interrupts ("); + printk(KERN_DEBUG "enabled interrupts ( "); s = GETPORT(SIMODE0); if (s & ENSELDO) @@ -2938,100 +3250,38 @@ 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)); } /* @@ -3039,33 +3289,27 @@ */ 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 @@ -3082,49 +3326,26 @@ 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); } @@ -3134,15 +3355,10 @@ 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) @@ -3161,7 +3377,7 @@ SPRINTF("SCSIRSTO "); SPRINTF(");"); - SPRINTF(" SCSISIG ("); + SPRINTF(" SCSISIG("); s = GETPORT(SCSISIG); switch (s & P_MASK) { case P_DATAO: @@ -3191,7 +3407,7 @@ SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - SPRINTF("SSTAT ("); + SPRINTF("SSTAT( "); s = GETPORT(SSTAT0); if (s & TARGET) SPRINTF("TARGET "); @@ -3230,7 +3446,7 @@ SPRINTF("); "); - SPRINTF("SSTAT ("); + SPRINTF("SSTAT( "); s = GETPORT(SSTAT0) & GETPORT(SIMODE0); @@ -3271,7 +3487,7 @@ SPRINTF("REQINIT "); SPRINTF("); "); - SPRINTF("SXFRCTL0 ("); + SPRINTF("SXFRCTL0( "); s = GETPORT(SXFRCTL0); if (s & SCSIEN) @@ -3288,24 +3504,26 @@ 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) @@ -3319,7 +3537,7 @@ 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 "); @@ -3329,7 +3547,7 @@ SPRINTF("FRERR "); SPRINTF("); "); - SPRINTF("DMACNTRL0 ("); + SPRINTF("DMACNTRL0( "); s = GETPORT(DMACNTRL0); SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); SPRINTF("%s ", s & DMA ? "DMA" : "PIO"); @@ -3344,7 +3562,7 @@ SPRINTF("SWINT "); SPRINTF("); "); - SPRINTF("DMASTAT ("); + SPRINTF("DMASTAT( "); s = GETPORT(DMASTAT); if (s & ATDONE) SPRINTF("ATDONE "); @@ -3354,9 +3572,9 @@ SPRINTF("DFIFOFULL "); if (s & DFIFOEMP) SPRINTF("DFIFOEMP "); - SPRINTF(")\n\n"); + SPRINTF(")\n"); - SPRINTF("enabled interrupts ("); + SPRINTF("enabled interrupts( "); s = GETPORT(SIMODE0); if (s & ENSELDO) @@ -3394,8 +3612,52 @@ 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; icount[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) @@ -3403,48 +3665,39 @@ 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) @@ -3453,14 +3706,14 @@ (((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"); @@ -3470,23 +3723,22 @@ 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"); @@ -3496,25 +3748,62 @@ 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; icount_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 #include "scsi.h" #include +#include 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); @@ -24,69 +27,79 @@ (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 */ @@ -118,33 +131,33 @@ #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 */ @@ -315,38 +328,31 @@ /* 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 diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.3.35/linux/drivers/scsi/aha1542.c Wed Dec 15 10:43:16 1999 +++ linux/drivers/scsi/aha1542.c Wed Dec 29 17:00:54 1999 @@ -9,7 +9,7 @@ * 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 @@ -18,7 +18,7 @@ * 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 + * Modified by Chris Faulhaber * Added module command-line options * 19-Jul-99 */ @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include #include @@ -46,32 +48,32 @@ #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 @@ -81,75 +83,83 @@ #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=[,,[,]] * * Where: is any of the valid AHA addresses: - * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 - * 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) - * 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. - * 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 + * 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) + * 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. + * 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); @@ -182,543 +192,567 @@ 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; + 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; + 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); -} - -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 */ + 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) +{ + 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!"); + 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; + 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))); - }; -#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); - + { + 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(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]); + 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++; + }; +} + +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 */ +#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(KERN_CRIT "aha1542: Wrong buffer length supplied " + "for request sense (%d)\n", bufflen); +#endif + 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(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 - /* - 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 *)) -{ - 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); -#endif - SCpnt->result = 0; - done(SCpnt); - return 0; - } + /* Use the outgoing mailboxes in a round-robin fashion, because this + is how the host adapter will scan for them */ -#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 */ -#endif -/* 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; - - 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); + 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"); + 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; iuse_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;iuse_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]); -#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; + 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; #ifdef DEBUG - { int i; - printk("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; + { + 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; } static void internal_done(Scsi_Cmnd * SCpnt) @@ -728,107 +762,107 @@ 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; imb; + 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) +{ + 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 @@ -836,364 +870,394 @@ 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; - }; + 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 */ + /* 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); + *transl = aha1542_mbenable(base_io); - return 0; + 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=[,,[,]]\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; - } + const char *ahausage = "aha1542: usage: aha1542=[,,[,]]\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; - if (setup_portbase != 0) - bases[setup_idx] = setup_portbase; + 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; + ++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; - } -#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); + 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 + /* + * Hunt for ISA Plug'n'Pray Adaptecs (AHA1535) + */ + + if(isapnp) + { + struct pci_dev *pdev = NULL; + for(indx = 0; indx 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; } /* @@ -1202,240 +1266,226 @@ */ 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); + 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 */ - printk("aha1542.c: Trying device reset for target %d\n", SCpnt->target); + 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; - 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; + 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]; + /* + * 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->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; - } + /* + * 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); - if (SCtmp->host_scribble) - { - scsi_free(SCtmp->host_scribble, 512); - } - - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; + 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; + 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]; + /* + * 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->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; - } + /* + * 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); - if (SCtmp->host_scribble) - { - scsi_free(SCtmp->host_scribble, 512); - } - - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; + 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; } /* @@ -1445,68 +1495,68 @@ 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 @@ -1517,136 +1567,132 @@ 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); + /* + * We need to do this too before the 1542 can interact with + * us again. + */ + setup_mailboxes(SCpnt->host->io_port, SCpnt->host); - 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); + /* + * 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; + int translation_algorithm; + int size = disk->capacity; - translation_algorithm = HOSTDATA(disk->device->host)->bios_translation; + 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; - } + 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; + return 0; } @@ -1656,4 +1702,3 @@ #include "scsi_module.c" #endif - diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.3.35/linux/drivers/scsi/ide-scsi.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/scsi/ide-scsi.c Tue Jan 4 11:17:47 2000 @@ -636,10 +636,9 @@ { ide_drive_t *drive = idescsi_drives[dev->id]; idescsi_scsi_t *scsi = drive->driver_data; - int enable = (int) arg; if (cmd == SG_SET_TRANSFORM) { - if (enable) + if (arg) set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); else clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.3.35/linux/drivers/scsi/megaraid.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/scsi/megaraid.c Wed Dec 29 17:00:54 1999 @@ -139,6 +139,7 @@ MODULE_DESCRIPTION ("AMI MegaRAID driver"); #endif +#include #include #include #include @@ -232,6 +233,8 @@ * *================================================================ */ +static int __init megaraid_setup(char *); + static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, mega_scb * scb, @@ -268,8 +271,8 @@ /* 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; @@ -1509,18 +1512,12 @@ { 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); @@ -1876,6 +1873,23 @@ 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; diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.3.35/linux/drivers/scsi/scsi.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/scsi/scsi.c Tue Jan 4 07:53:02 2000 @@ -265,6 +265,7 @@ {"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. @@ -292,8 +293,8 @@ {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST}, {"HITACHI", "GF-1050","*", BLIST_GHOST}, /* Hitachi SCSI DVD-RAM */ {"TOSHIBA","CDROM","*", BLIST_ISROM}, - {"Toshiba","DVD-RAM SD-W1101","*", BLIST_GHOST}, - {"Toshiba","DVD-RAM SD-W1111","*", BLIST_GHOST}, + {"TOSHIBA","DVD-RAM SD-W1101","*", BLIST_GHOST}, + {"TOSHIBA","DVD-RAM SD-W1111","*", BLIST_GHOST}, /* * Must be at end of list... diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c --- v2.3.35/linux/drivers/scsi/scsi_merge.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/scsi/scsi_merge.c Thu Dec 30 23:24:22 1999 @@ -290,30 +290,6 @@ count = bh->b_size >> 9; sector = bh->b_rsector; -#if CONFIG_HIGHMEM - /* - * This is a temporary hack for the time being. - * In some cases, the ll_rw_blk layer is creating - * bounce buffers for us - this implies that we don't - * need to down here, but queue management becomes quite - * difficult otherwise. When the ll_rw_blk layer gets - * cleaned up to handle bounce buffers better, then - * this hack can be cleaned up. - */ - if( sector == -1 ) - { - struct buffer_head * bh_new; - bh_new = (struct buffer_head *) bh->b_dev_id; - if( bh_new != NULL ) - { - sector = bh_new->b_rsector; - } - if( sector == -1 ) - { - panic("Unable to merge ambiguous block request"); - } - } -#endif /* * We come in here in one of two cases. The first is that we diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.35/linux/drivers/scsi/st.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/scsi/st.c Tue Jan 4 13:01:53 2000 @@ -8,10 +8,10 @@ order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. - Copyright 1992 - 1999 Kai Makisara + Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Thu Dec 16 23:08:29 1999 by makisara@kai.makisara.local + Last modified: Tue Jan 4 21:43:17 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 */ @@ -2915,7 +2915,7 @@ static ST_buffer * new_tape_buffer(int from_initialization, int need_dma) { - int i, priority, b_size, got = 0, segs = 0; + int i, priority, b_size, order, got = 0, segs = 0; ST_buffer *tb; if (st_nbr_buffers >= st_template.dev_max) @@ -2927,20 +2927,20 @@ priority = GFP_KERNEL; i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = (ST_buffer *) scsi_init_malloc(i, priority); + tb = (ST_buffer *) kmalloc(i, priority); if (tb) { - tb->this_size = i; if (need_dma) priority |= GFP_DMA; /* Try to allocate the first segment up to ST_FIRST_ORDER and the others big enough to reach the goal */ - for (b_size = PAGE_SIZE << ST_FIRST_ORDER; - b_size / 2 >= st_buffer_size && b_size > PAGE_SIZE;) - b_size /= 2; - for (; b_size >= PAGE_SIZE; b_size /= 2) { + for (b_size = PAGE_SIZE, order=0; + b_size < st_buffer_size && order < ST_FIRST_ORDER; + order++, b_size *= 2) + ; + for ( ; b_size >= PAGE_SIZE; order--, b_size /= 2) { tb->sg[0].address = - (unsigned char *) scsi_init_malloc(b_size, priority); + (unsigned char *) __get_free_pages(priority, order); if (tb->sg[0].address != NULL) { tb->sg[0].alt_address = NULL; tb->sg[0].length = b_size; @@ -2948,30 +2948,33 @@ } } if (tb->sg[segs].address == NULL) { - scsi_init_free((char *) tb, tb->this_size); + kfree(tb); tb = NULL; } else { /* Got something, continue */ - for (b_size = PAGE_SIZE; + for (b_size = PAGE_SIZE, order=0; st_buffer_size > - tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;) - b_size *= 2; - + tb->sg[0].length + (ST_FIRST_SG - 1) * b_size; + order++, b_size *= 2) + ; for (segs = 1, got = tb->sg[0].length; - got < st_buffer_size && segs < ST_FIRST_SG;) { + got < st_buffer_size && segs < ST_FIRST_SG;) { tb->sg[segs].address = - (unsigned char *) scsi_init_malloc(b_size, priority); + (unsigned char *) __get_free_pages(priority, + order); if (tb->sg[segs].address == NULL) { if (st_buffer_size - got <= (ST_FIRST_SG - segs) * b_size / 2) { b_size /= 2; /* Large enough for the rest of the buffers */ + order--; continue; } - for (i = 0; i < segs - 1; i++) - scsi_init_free(tb->sg[i].address, - tb->sg[i].length); - scsi_init_free((char *) tb, tb->this_size); + tb->sg_segs = segs; + tb->orig_sg_segs = 0; + DEB(tb->buffer_size = got); + normalize_buffer(tb); + kfree(tb); tb = NULL; break; } @@ -3011,7 +3014,7 @@ /* Try to allocate a temporary enlarged tape buffer */ static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma) { - int segs, nbr, max_segs, b_size, priority, got; + int segs, nbr, max_segs, b_size, priority, order, got; normalize_buffer(STbuffer); @@ -3025,20 +3028,23 @@ priority = GFP_KERNEL; if (need_dma) priority |= GFP_DMA; - for (b_size = PAGE_SIZE; b_size * nbr < new_size - STbuffer->buffer_size;) - b_size *= 2; + for (b_size = PAGE_SIZE, order=0; + b_size * nbr < new_size - STbuffer->buffer_size; + order++, b_size *= 2); for (segs = STbuffer->sg_segs, got = STbuffer->buffer_size; segs < max_segs && got < new_size;) { STbuffer->sg[segs].address = - (unsigned char *) scsi_init_malloc(b_size, priority); + (unsigned char *) __get_free_pages(priority, order); if (STbuffer->sg[segs].address == NULL) { if (new_size - got <= (max_segs - segs) * b_size / 2) { b_size /= 2; /* Large enough for the rest of the buffers */ + order--; continue; } printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n", new_size); + DEB(STbuffer->buffer_size = got); normalize_buffer(STbuffer); return FALSE; } @@ -3060,16 +3066,20 @@ /* Release the extra buffer */ static void normalize_buffer(ST_buffer * STbuffer) { - int i; + int i, order, b_size; for (i = STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) { - scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length); + for (b_size=PAGE_SIZE, order=0; b_size < STbuffer->sg[i].length; + order++, b_size *= 2) + ; + free_pages((unsigned long)(STbuffer->sg[i].address), order); STbuffer->buffer_size -= STbuffer->sg[i].length; } DEB( if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n", - STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); + STbuffer->sg[0].address, STbuffer->buffer_size, + STbuffer->sg_segs); ) /* end DEB */ STbuffer->sg_segs = STbuffer->orig_sg_segs; } @@ -3320,7 +3330,7 @@ /* Driver initialization (not __init because may be called later) */ static int st_init() { - int i; + int i, j; Scsi_Tape *STp; int target_nbr; @@ -3346,8 +3356,8 @@ if (st_template.dev_max > 128 / ST_NBR_MODES) printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES); scsi_tapes = - (Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape), - GFP_ATOMIC); + (Scsi_Tape *) kmalloc(st_template.dev_max * sizeof(Scsi_Tape), + GFP_ATOMIC); if (scsi_tapes == NULL) { printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n"); unregister_chrdev(SCSI_TAPE_MAJOR, "st"); @@ -3361,21 +3371,30 @@ for (i = 0; i < st_template.dev_max; ++i) { STp = &(scsi_tapes[i]); STp->capacity = 0xfffff; - STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget), - GFP_ATOMIC); + STp->mt_status = (struct mtget *) kmalloc(sizeof(struct mtget), + GFP_ATOMIC); + if (STp->mt_status == NULL) { + for (j=0; j < i; j++) + kfree(scsi_tapes[j].mt_status); + kfree(scsi_tapes); + unregister_chrdev(SCSI_TAPE_MAJOR, "st"); + return 1; + } /* Initialize status */ memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget)); } /* Allocate the buffers */ st_buffers = - (ST_buffer **) scsi_init_malloc(st_template.dev_max * sizeof(ST_buffer *), - GFP_ATOMIC); + (ST_buffer **) kmalloc(st_template.dev_max * sizeof(ST_buffer *), + GFP_ATOMIC); if (st_buffers == NULL) { printk(KERN_ERR "Unable to allocate tape buffer pointers.\n"); unregister_chrdev(SCSI_TAPE_MAJOR, "st"); - scsi_init_free((char *) scsi_tapes, - st_template.dev_max * sizeof(Scsi_Tape)); + for (i=0; i < st_template.dev_max; i++) + kfree(scsi_tapes[i].mt_status); + kfree(scsi_tapes); + unregister_chrdev(SCSI_TAPE_MAJOR, "st"); return 1; } target_nbr = st_template.dev_noticed; @@ -3420,42 +3439,32 @@ int __init init_module(void) { - int result; - validate_options(); st_template.module = &__this_module; - result = scsi_register_module(MODULE_SCSI_DEV, &st_template); - if (result) - return result; - - return 0; + return scsi_register_module(MODULE_SCSI_DEV, &st_template); } void cleanup_module(void) { - int i, j; + int i; scsi_unregister_module(MODULE_SCSI_DEV, &st_template); unregister_chrdev(SCSI_TAPE_MAJOR, "st"); st_registered--; if (scsi_tapes != NULL) { - scsi_init_free((char *) scsi_tapes, - st_template.dev_max * sizeof(Scsi_Tape)); - + for (i=0; i < st_template.dev_max; ++i) + kfree(scsi_tapes[i].mt_status); + kfree(scsi_tapes); if (st_buffers != NULL) { - for (i = 0; i < st_nbr_buffers; i++) - { + for (i = 0; i < st_nbr_buffers; i++) { if (st_buffers[i] != NULL) { - for (j = 0; j < st_buffers[i]->sg_segs; j++) - scsi_init_free((char *) st_buffers[i]->sg[j].address, - st_buffers[i]->sg[j].length); - scsi_init_free((char *) st_buffers[i], - st_buffers[i]->this_size); + st_buffers[i]->orig_sg_segs = 0; + normalize_buffer(st_buffers[i]); + kfree(st_buffers[i]); } } - scsi_init_free((char *) st_buffers, - st_template.dev_max * sizeof(ST_buffer *)); + kfree(st_buffers); } } st_template.dev_max = 0; diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.3.35/linux/drivers/scsi/st.h Fri Oct 22 13:21:50 1999 +++ linux/drivers/scsi/st.h Tue Jan 4 13:01:53 2000 @@ -13,7 +13,6 @@ typedef struct { unsigned char in_use; unsigned char dma; /* DMA-able buffer */ - int this_size; /* allocated size of the structure */ int buffer_size; int buffer_blocks; int buffer_bytes; diff -u --recursive --new-file v2.3.35/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h --- v2.3.35/linux/drivers/scsi/st_options.h Mon Aug 9 10:23:42 1999 +++ linux/drivers/scsi/st_options.h Tue Jan 4 13:01:53 2000 @@ -1,9 +1,9 @@ /* The compile-time configurable defaults for the Linux SCSI tape driver. - Copyright 1995-1999 Kai Makisara. + Copyright 1995-2000 Kai Makisara. - Last modified: Sat Aug 7 13:42:21 1999 by makisara@kai.makisara.local + Last modified: Sat Jan 1 18:34:38 2000 by makisara@kai.makisara.local */ #ifndef _ST_OPTIONS_H diff -u --recursive --new-file v2.3.35/linux/drivers/sound/msnd.h linux/drivers/sound/msnd.h --- v2.3.35/linux/drivers/sound/msnd.h Sat May 15 15:05:37 1999 +++ linux/drivers/sound/msnd.h Wed Dec 29 17:00:54 1999 @@ -189,7 +189,7 @@ typedef u16 USHORT; typedef u16 WORD; typedef u32 DWORD; -typedef volatile BYTE * LPDAQD; +typedef unsigned long LPDAQD; /* Generic FIFO */ typedef struct { @@ -208,12 +208,12 @@ 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; diff -u --recursive --new-file v2.3.35/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.3.35/linux/drivers/sound/msnd_pinnacle.c Mon Jul 5 19:58:24 1999 +++ linux/drivers/sound/msnd_pinnacle.c Wed Dec 29 17:00:54 1999 @@ -104,18 +104,18 @@ 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); } } @@ -126,25 +126,25 @@ 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); } } @@ -180,9 +180,9 @@ 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; @@ -312,9 +312,9 @@ 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; @@ -355,9 +355,9 @@ 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; @@ -394,28 +394,28 @@ } } -#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); @@ -444,23 +444,23 @@ /* 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 */ @@ -834,18 +834,18 @@ 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) */ @@ -868,8 +868,8 @@ 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; @@ -904,12 +904,12 @@ 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); @@ -1110,15 +1110,15 @@ 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); } } @@ -1211,7 +1211,7 @@ } 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, @@ -1225,12 +1225,12 @@ 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) @@ -1244,22 +1244,22 @@ #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; @@ -1286,19 +1286,19 @@ /* 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); -#endif - writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD); - writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft); - writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight); + 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 + 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; @@ -1307,12 +1307,12 @@ 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) { @@ -1342,7 +1342,7 @@ 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; @@ -1395,7 +1395,7 @@ } timeout = 200; - while (readw(dev.base)) { + while (isa_readw(dev.base)) { mdelay(1); if (!timeout--) { printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n"); @@ -1897,7 +1897,7 @@ 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; diff -u --recursive --new-file v2.3.35/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.3.35/linux/drivers/sound/trident.c Tue Dec 7 09:32:46 1999 +++ linux/drivers/sound/trident.c Wed Dec 29 17:29:43 1999 @@ -1,36 +1,41 @@ -/***************************************************************************** +/* * - * 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 * * Built from: - * Low level code: from ALSA - * Framework: Thomas Sailer - * Extended by: Zach Brown + * Low level code: from ALSA + * Framework: Thomas Sailer + * Extended by: Zach Brown * - * Hacked up by: - * Aaron Holtzman + * Hacked up by: + * Aaron Holtzman + * Ollie Lho 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 #include @@ -61,17 +66,10 @@ /* --------------------------------------------------------------------- */ -#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 @@ -79,33 +77,53 @@ #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 { @@ -149,7 +167,7 @@ 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; @@ -172,7 +190,31 @@ 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; @@ -180,23 +222,23 @@ 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]; @@ -208,41 +250,12 @@ 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 @@ -252,12 +265,12 @@ 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. ---------------------------------------------------------------------------*/ @@ -279,105 +292,171 @@ 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 = 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)); - M_printk("(trident) globctl=%02X\n", GlobalControl); - M_printk("(trident) enabled end interrupts\n"); + 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; + } + + outl(GlobalControl, TRID_REG(trident, T4D_LFO_GC_CIR)); + +#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 } /*--------------------------------------------------------------------------- @@ -391,29 +470,38 @@ ---------------------------------------------------------------------------*/ -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; } @@ -423,19 +511,29 @@ 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)); } } @@ -443,113 +541,127 @@ 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; } @@ -558,11 +670,11 @@ 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) @@ -579,8 +691,9 @@ 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; } @@ -588,13 +701,13 @@ 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, @@ -622,17 +735,19 @@ 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); @@ -663,19 +778,18 @@ 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; @@ -683,25 +797,16 @@ 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; } @@ -710,29 +815,36 @@ 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; } @@ -761,94 +873,87 @@ 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 + switch (trident->pci_id) { - 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--); + 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; } - if ( count == 0 ) - { - printk("trident: AC97 CODEC read timed out.\n"); + + 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.. */ @@ -876,7 +981,7 @@ 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}, @@ -895,35 +1000,35 @@ 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<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<scale) / 100; left = (left * mh->scale) / 100; @@ -980,25 +1091,31 @@ } 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 @@ -1011,8 +1128,8 @@ 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[] = { @@ -1035,12 +1152,11 @@ }; /* 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; @@ -1052,125 +1168,91 @@ } /* 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. - - DTemp = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)); - outl(DTemp | 0x0010, TRID_REG(trident, NX_ACR0_AC97_COM_STAT)); - - } - 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 + /* 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; } - - // 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)); - } + 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); + + /* 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); + + /* 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; + 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; @@ -1182,38 +1264,28 @@ 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; @@ -1221,25 +1293,25 @@ 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) @@ -1260,16 +1332,24 @@ 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 @@ -1367,35 +1447,42 @@ } -/* 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) @@ -1403,26 +1490,36 @@ 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) @@ -1430,24 +1527,13 @@ 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)); @@ -1471,9 +1557,9 @@ 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]); @@ -1503,8 +1589,9 @@ 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); } @@ -1520,25 +1607,65 @@ 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++) @@ -1549,72 +1676,37 @@ 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; - - 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; + spin_unlock_irqrestore(&state->card->lock, flags); - 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<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) { @@ -1623,13 +1715,8 @@ 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) { @@ -1644,22 +1731,23 @@ 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; @@ -1701,13 +1789,16 @@ } } } + /* 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) @@ -1719,7 +1810,9 @@ 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; @@ -1747,94 +1840,76 @@ /* * 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;ichannels[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; @@ -1842,23 +1917,23 @@ } 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); @@ -1866,83 +1941,71 @@ 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); - - 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 (_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 */ + 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); @@ -1954,6 +2017,7 @@ return -ENODEV; file->private_data = card; + //FIXME put back in //MOD_INC_USE_COUNT; return 0; @@ -1970,7 +2034,8 @@ 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; @@ -1979,6 +2044,11 @@ 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 */ @@ -1997,11 +2067,13 @@ 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; @@ -2011,8 +2083,7 @@ 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); @@ -2023,20 +2094,20 @@ 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; @@ -2045,82 +2116,86 @@ 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; @@ -2128,92 +2203,92 @@ 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; - } - 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); + 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 = 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; } @@ -2259,11 +2334,11 @@ 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 @@ -2284,336 +2359,315 @@ { 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); + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + fmtd = 0; + fmtm = ~0; - return 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; } @@ -2621,74 +2675,74 @@ 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;ichannels[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; @@ -2696,27 +2750,28 @@ 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; @@ -2726,31 +2781,31 @@ &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; @@ -2760,16 +2815,16 @@ 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 */ @@ -2778,79 +2833,62 @@ 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;ilock); + + for (i = 0; i < NR_DSPS; i++) { struct trident_state *s=&card->channels[i]; s->card = card; @@ -2859,99 +2897,80 @@ 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(;ichannels[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;ichannels[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 @@ -2960,34 +2979,24 @@ { 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; } @@ -2997,44 +3006,33 @@ #ifdef MODULE MODULE_AUTHOR("Alan Cox "); -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;ichannels[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 */ diff -u --recursive --new-file v2.3.35/linux/drivers/sound/trident.h linux/drivers/sound/trident.h --- v2.3.35/linux/drivers/sound/trident.h Tue Dec 7 09:32:46 1999 +++ linux/drivers/sound/trident.h Wed Dec 29 17:29:43 1999 @@ -24,13 +24,23 @@ */ #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_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_TRIDENT_4DWAVE_NX -#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 + +#ifndef PCI_DEVICE_ID_SI_7018 +#define PCI_DEVICE_ID_SI_7018 0x7018 #endif /* @@ -44,84 +54,165 @@ #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 ID_4DWAVE_DX 0x2000 -#define ID_4DWAVE_NX 0x2001 +#define CHANNEL_REGS 5 +#define CHANNEL_START 0xe0 // The first bytes of the contiguous register space. +#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 +#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 */ +#endif /* __TRID4DWAVE_H */ diff -u --recursive --new-file v2.3.35/linux/drivers/telephony/Config.in linux/drivers/telephony/Config.in --- v2.3.35/linux/drivers/telephony/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/telephony/Config.in Wed Dec 29 17:13:59 1999 @@ -0,0 +1,9 @@ +# +# 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 diff -u --recursive --new-file v2.3.35/linux/drivers/telephony/Makefile linux/drivers/telephony/Makefile --- v2.3.35/linux/drivers/telephony/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/telephony/Makefile Wed Dec 29 17:13:59 1999 @@ -0,0 +1,35 @@ +# +# 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 diff -u --recursive --new-file v2.3.35/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c --- v2.3.35/linux/drivers/telephony/ixj.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/telephony/ixj.c Tue Jan 4 09:41:45 2000 @@ -0,0 +1,7517 @@ +/* + * 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, + * + * Contributors: Greg Herlein, + * David W. Erhart, + * John Sellers, + * Mike Preston, + * + * 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 +#include +#include +#include +#include /* printk() */ +#include /* everything... */ +#include /* error codes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_ISAPNP +#include +#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 "); + +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; +} diff -u --recursive --new-file v2.3.35/linux/drivers/telephony/ixj.h linux/drivers/telephony/ixj.h --- v2.3.35/linux/drivers/telephony/ixj.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/telephony/ixj.h Wed Dec 29 17:13:59 1999 @@ -0,0 +1,974 @@ +/* + * 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, + * + * Contributors: Greg Herlein, + * David W. Erhart, + * John Sellers, + * Mike Preston, + * + * 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 +#endif + +#include +#include + +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); diff -u --recursive --new-file v2.3.35/linux/drivers/telephony/phonedev.c linux/drivers/telephony/phonedev.c --- v2.3.35/linux/drivers/telephony/phonedev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/telephony/phonedev.c Wed Dec 29 17:13:59 1999 @@ -0,0 +1,167 @@ +/* + * 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, + * + * Fixes: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#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); diff -u --recursive --new-file v2.3.35/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.35/linux/drivers/usb/Config.in Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/Config.in Sun Jan 2 12:13:47 2000 @@ -10,7 +10,7 @@ dep_tristate ' UHCI (Intel PIIX4, VIA, and others) support' CONFIG_USB_UHCI \ $CONFIG_USB - dep_tristate ' OHCI-HCD (Compaq, iMacs, OPTi, SiS, and others) support' \ + dep_tristate ' OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, and others) support' \ CONFIG_USB_OHCI_HCD $CONFIG_USB comment 'Miscellaneous USB options' @@ -19,14 +19,31 @@ fi comment 'USB Devices' - dep_tristate ' USB keyboard support' CONFIG_USB_KBD $CONFIG_USB - dep_tristate ' USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB + dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB + if [ "$CONFIG_USB_HID" != "y" ]; then + dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB + dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB + fi + if [ "$CONFIG_USB_HID" != "n" ]; then + dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB_HID + dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB_HID + if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then + bool ' Mix all mice into one device' CONFIG_INPUT_MOUSEDEV_MIX $CONFIG_USB_HID + fi + dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB_HID + dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB_HID + bool ' USB HID debug output' CONFIG_USB_HID_DEBUG + if [ "$CONFIG_USB_HID_DEBUG" != "n" ]; then + bool ' USB HID lots of debug output' CONFIG_USB_HID_DEBUG_LOTS + fi + fi dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB dep_tristate ' USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB + dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB dep_tristate ' USB SCSI (mass storage) support' CONFIG_USB_SCSI $CONFIG_USB if [ "$CONFIG_USB_SCSI" != "n" ]; then diff -u --recursive --new-file v2.3.35/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.35/linux/drivers/usb/Makefile Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/Makefile Tue Jan 4 11:17:50 2000 @@ -1,33 +1,27 @@ # -# Makefile for the kernel usb device drivers. +# Makefile for the kernel USB device 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 := usb.a -M_OBJS := -L_OBJS := MOD_LIST_NAME := USB_MODULES ifeq ($(CONFIG_USB),y) - L_OBJS += usbcore.o + L_OBJS += usb-debug.o usb-core.o hub.o + LX_OBJS += usb.o ifeq ($(CONFIG_USB_PROC),y) L_OBJS += proc_usb.o endif endif ifeq ($(CONFIG_USB),m) M_OBJS += usbcore.o - MIX_OBJS += usb.o usb-debug.o usb-core.o + MI_OBJS += usb-debug.o usb-core.o hub.o + MIX_OBJS += usb.o ifeq ($(CONFIG_USB_PROC),y) - MIX_OBJS += proc_usb.o + MI_OBJS += proc_usb.o endif endif @@ -48,13 +42,6 @@ MI_OBJS += ohci-hcd.o endif -ifeq ($(CONFIG_USB_MOUSE),y) - L_OBJS += mouse.o -endif -ifeq ($(CONFIG_USB_MOUSE),m) - M_OBJS += mouse.o -endif - ifeq ($(CONFIG_USB_SCANNER),y) L_OBJS += scanner.o endif @@ -85,21 +72,6 @@ M_OBJS += usb-serial.o endif -ifneq ($(CONFIG_ADB_KEYBOARD),y) -KEYMAP=keymap -else -KEYMAP=keymap-mac -endif - -ifeq ($(CONFIG_USB_KBD),y) - L_OBJS += keyboard.o $(KEYMAP).o -endif - -ifeq ($(CONFIG_USB_KBD),m) - M_OBJS += usb-keyboard.o - MI_OBJS += keyboard.o $(KEYMAP).o -endif - ifeq ($(CONFIG_USB_AUDIO),y) L_OBJS += audio.o endif @@ -116,6 +88,14 @@ M_OBJS += cpia.o endif +ifeq ($(CONFIG_USB_OV511),y) + L_OBJS += ov511.o +endif + +ifeq ($(CONFIG_USB_OV511),m) + M_OBJS += ov511.o +endif + ifeq ($(CONFIG_USB_DC2XX),y) L_OBJS += dc2xx.o endif @@ -146,6 +126,71 @@ M_OBJS += ezusb.o endif +ifeq ($(CONFIG_USB_HID),y) + L_OBJS += hid.o + ILX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_HID),m) + M_OBJS += hid.o + IMX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_KBD),y) + L_OBJS += usbkbd.o + ILX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_KBD),m) + M_OBJS += usbkbd.o + IMX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_MOUSE),y) + L_OBJS += usbmouse.o + ILX_OBJS := input.o +endif + +ifeq ($(CONFIG_USB_MOUSE),m) + M_OBJS += usbmouse.o + IMX_OBJS := input.o +endif + +LX_OBJS += $(ILX_OBJS) +MX_OBJS += $(IMX_OBJS) + +ifeq ($(CONFIG_INPUT_KEYBDEV),y) + L_OBJS += keybdev.o +endif + +ifeq ($(CONFIG_INPUT_KEYBDEV),m) + M_OBJS += keybdev.o +endif + +ifeq ($(CONFIG_INPUT_MOUSEDEV),y) + L_OBJS += mousedev.o +endif + +ifeq ($(CONFIG_INPUT_MOUSEDEV),m) + M_OBJS += mousedev.o +endif + +ifeq ($(CONFIG_INPUT_JOYDEV),y) + L_OBJS += joydev.o +endif + +ifeq ($(CONFIG_INPUT_JOYDEV),m) + M_OBJS += joydev.o +endif + +ifeq ($(CONFIG_INPUT_EVDEV),y) + L_OBJS += evdev.o +endif + +ifeq ($(CONFIG_INPUT_EVDEV),m) + M_OBJS += evdev.o +endif + ifeq ($(CONFIG_USB_USS720),y) L_OBJS += uss720.o endif @@ -163,18 +208,6 @@ endif include $(TOPDIR)/Rules.make - -keymap.o: keymap.c - -keymap.c: maps/serial.map maps/usb.map maps/fixup.map - ./mkmap > $@ - -keymap-mac.o: keymap-mac.c -keymap-mac.c: maps/mac.map maps/usb.map - ./mkmap.adb > $@ - -usb-keyboard.o: $(KEYMAP).o keyboard.o - $(LD) $(LD_RFLAG) -r -o $@ $(KEYMAP).o keyboard.o ifeq ($(CONFIG_USB_SCSI_DEBUG),y) usb-scsi.o: usb_scsi.o usb_scsi_debug.o diff -u --recursive --new-file v2.3.35/linux/drivers/usb/README.hid linux/drivers/usb/README.hid --- v2.3.35/linux/drivers/usb/README.hid Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/README.hid Sun Jan 2 12:12:59 2000 @@ -0,0 +1,162 @@ + Linux HID driver v0.8 + (c) 1999 Vojtech Pavlik + (c) 1999 Andreas Gal + Sponsored by SuSE +---------------------------------------------------------------------------- + +0. Disclaimer +~~~~~~~~~~~~~ + This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + + This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + + You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., 59 +Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Should you need to contact me, the author, you can do so either by e-mail +- mail your message to , or by paper mail: Vojtech Pavlik, +Ucitelska 1576, Prague 8, 182 00 Czech Republic + + For your convenience, the GNU General Public License version 2 is included +in the package: See the file COPYING. + +1. Introduction +~~~~~~~~~~~~~~~ + This is a driver for USB devices conforming to the USB HID (Human Input +Device) standard. These devices include namely keyboards, mice and +joysticks. + + However many other devices (monitors, speakers, UPSs ...) also communicate +through the same protocol, which makes its specification somewhat bloated. +This isn't a problem, though, because the driver doesn't need to know about +all the possible devices it can control, and can just parse the protocol and +leave the rest of the job (for example understanding what the UPS wants to +say) to the userland. + + Because of this, the USB HID driver has two interfaces. One is via the +proc filesystem, allowing userland applications send and read arbitrary +reports to and from a connected USB device. The other is via a very simple +yet generic input device driver, which dispatches input events (keystrokes, +mouse or joystick movements) to specific, backward compatible userland +interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver +interface are emulated, and allow applications to immediately work with USB +mice, USB keyboards and USB joysticks without any changes. + + The input driver is aimed for a little more than USB device handling in +the future, though. It's generic enough so that it can be used for any +mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a +serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to +use this as well as the AT keyboard and Sun keyboard drivers. This will +hopefully allow conversion of all Linux keyboard and mouse and joystick +drivers to this scheme. + + This effort has it's home page at: + + http://www.suse.cz/development/input/ + +You'll find both the latest HID driver and the complete Input driver there. +There is also a mailing list for this: + + listproc@atrey.karlin.mff.cuni.cz + +Send "subscribe linux-joystick Your Name" to subscribe to it. + +2. Usage +~~~~~~~~ + Since the driver comes with recent 2.3 kernels, all that's needed to use +it is to enable it either as a module or compiled-in into the kernel. + + After that, after reboot (and possibly also inserting the USB and HID +modules) the following will happen: + +* If you selected keyboard support, all USB keystrokes will be also routed + to the Linux keyboard driver as if being input through the ordinary system + keyboard. + +* If you selected mouse support, there will be (one or more) simulated PS/2 + mouse devices on major 10, minor 32, 33 and more. These simulated mice can + in addition to a standard 3-button PS/2 mouse behave like MS Intellimice, + with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm + and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse + device can be open by any number of processes (unlike the /dev/psaux), and + for each of them the emulation is separate, each can use a different mode. + The mousedev driver, which emulates the mice, can also emulate a Genius + NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2 + mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X + can decode the 5 buttons yet, so this isn't very useful right now. + +* If you selected joystick support, the driver will take over major 15, the + joystick major number, and will emulate joysticks on it. This means the + normal joystick driver can't be used together with it (now, after the + normal joystick drivers are converted to the input scheme, all will work + nicely together). Also, you'll probably need to calibrate your joystick + manually ('man jscal') to be able to use it, because the USB + autocalibration is far from perfect yet. + +* If you selected event device support, there will be devices on major 10, + minors 64, 65 and more for each input device connected through this + driver. These devices output raw events the input driver dispatches. Each + has a timestamp. This hopefully will be THE way X will talk to keyboard + and mice, because it's hardware independent, and not limited by existing + de-facto standards. + +3. Verifying if it works +~~~~~~~~~~~~~~~~~~~~~~~~ + Typing a couple keys on the keyboard should be enough to check that a USB +keyboard works and is correctly connected to the kernel keyboard driver. + + Doing a cat /dev/hidmouse (c, 10, 32) will verify that a mouse is also +emulated, characters should appear if you move it. + + You can test the joystick emulation with the 'jstest' utility, available +in the joystick package (see Documentation/joystick.txt). + + You can test the event devics with the 'evtest' utitily available on the +input driver homepage (see the URL above). + +4. FAQ +~~~~~~ +Q: Why aren't any questions here yet? +A: Because none were frequent enough yet. + +5. Event interface +~~~~~~~~~~~~~~~~~~ + Should you want to add event device support into any application (X, gpm, +svgalib ...) I (vojtech@suse.cz) will be happy to provide you any help I +can. Here goes a description of the current state of things, which is going +to be extended, but not changed incompatibly as time goes: + + You can use blocking and nonblocking reads, also select() on the +/dev/inputX devices, and you'll always get a whole number of input events on +a read. Their layout is: + +struct input_event { + struct timeval time; + unsigned short type; + unsigned short code; + unsigned int value; +}; + + 'time' is the timestamp, it returns the time at which the event happened. +Type is for example EV_REL for relative momement, REL_KEY for a keypress or +release. More types are defined in include/linux/input.h. + + 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete +list is in include/linux/input.h. + + 'value' is the value the event carries. Either a relative change for +EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for +release, 1 for keypress and 2 for autorepeat. + +6. Proc interface +~~~~~~~~~~~~~~~~~ + For HID-specific devices there is also the /proc interface. It isn't +present in this release yet, though, so it's description will appear here +together with the code in the driver. diff -u --recursive --new-file v2.3.35/linux/drivers/usb/README.kbd linux/drivers/usb/README.kbd --- v2.3.35/linux/drivers/usb/README.kbd Wed Apr 21 10:29:09 1999 +++ linux/drivers/usb/README.kbd Wed Dec 31 16:00:00 1969 @@ -1,65 +0,0 @@ -This is a simple USB keyboard driver written from Linus' -USB driver (started with Greg's usb-0.03b.tar.gz source -tree) - -It works fine with my BTC keyboard but I'm still investigating -trouble with my MS keyboard (trouble starts with an inability -to set into boot protocol mode, though, this very well could -be all due to crappy hardware). - -Anyway, I would appreciate you taking a look if you have -any USB keyboards lying around. Oh also, I'm doing this on -UHCI so sorry if it breaks with OHCI. - --ham - - - -Keyboard patch --------------- - -Instead of using the multiple keyboard patch and then running into all -of the kernel version problems that the current Linux-USB project has -had, I'm just mapping the USB keycodes to the standard AT-101 keycodes -and sending them directly to "handle_scancode". - -This may or may not be considered a hack. Anyway it is effective, and -I think safe, and allows USB keyboards to coexist with a serial -keyboard (oh yeah, one side effect is that you can for example hold -down the control key on the serial keyboard and press "a" on the USB -keyboard and you get Control-a like with Windows USB) and works -fine for console and X. - -You do need to make a *tiny* patch the kernel source tree so that the -function "handle_scancode" is exported from keyboard.c though. - - $ cd /usr/src/linux - $ patch -p0 < kbd.patch - -And, of course, then, you need to rebuild and install the kernel. - -** [Vojtech]: Alternately, just 'insmod kbd-stub', if you don't want -to use the keyboard and are too lazy to patch the kernel. - -Keyboard map ------------- - -I'm including a stupid utility "mkmap" which generates the USB->serial -keymap. It takes in maps/serial.map (the current serial keymap, -generated by "dumpkeys"), maps/usb.map (the USB keymap), and -maps/fixup.map (fixes for e0 keys and misc.) and spits out keymap.c -Anyway, it is not beautiful but should serve its purpose for the -moment. - -Other changes -------------- -uhci.c: - * added a context value to the irq callback function - (this is exactly like the "dev_id" field to request_irq) - * played with uhci_reset_port to get better hot-plug results - (eg. do a wait_ms(200) before calling uhci_reset_port) -usb.c: - * disconnect all devices after uhci-control thread is killed - * skip over the HID descriptor - * disconnect the high-level driver in usb_disconnect - diff -u --recursive --new-file v2.3.35/linux/drivers/usb/README.ov511 linux/drivers/usb/README.ov511 --- v2.3.35/linux/drivers/usb/README.ov511 Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/README.ov511 Sun Jan 2 12:13:47 2000 @@ -0,0 +1,70 @@ +------------------------------------------------------------------------------- +Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC +------------------------------------------------------------------------------- + +INTRODUCTION: + +This is a preliminary version of my OV511 Linux device driver. At the moment, +it does not do much more than detect the chip and initialize it. As trivial +as this sounds, it represents many hours of my work. Since OmniVision refused +to release the full specs to me, I had to write code to probe out the register +read/write commands. Some code is in place to allow a frame to be grabbed, but +it is nowhere near complete. + +SUPPORTED CAMERAS: +____________________________________________ +Manufacturer | Model | Custom ID +-----------------+--------------+----------- +D-Link | DSB-C300 | 3 +Creative Labs | WebCam 3 | 21 +-------------------------------------------- + +Any camera using the OV511 and the OV7610 CCD should work with this driver. The +driver only detects known cameras though, based on their custom id number. If +you have a currently unsupported camera, the ID number should be reported to you +in the kernel logs. If you have an unsupported camera, please send me the model, +manufacturer and ID number and I will add it to the detection code. In the +meantime, you can add to the code yourself in the function ov511_probe() + +WHAT YOU NEED: + +- If you want to help with the development, get the chip's specification docs at + http://www.ovt.com/omniusbp.html + +- A Video4Linux compatible frame grabber program (I recommend vidcat) + (see: http://www.exploits.org/v4l/ ) + +WHAT NEEDS TO BE DONE: + +In short, a lot. + +UPDATE: +Currently, the control messages are working fine ("vendor commands"; for +reading and writing the OV511 registers.) The I2C bus commands for reading and +writing the camera (OV7610) registers are implemented and working, with at least +one person's camera. The isochronous-in endpoint for video data is finally +producing data, but since ov511_parse_data() is not implemented you will not see +a picture yet. + +Support for specific CCD's will have to be implemented as well (such as the +OV7610.) + +The rest of the work will involve implementing support for all the different +resolutions, color depths, etc. Also, while support for the OV511's proprietary +lossy compression is apparently not necessary (the code currently disables it,) +it would be a nice addition as it improves performance quite a bit. OmniVision +wouldn't tell me how the algorithm works, so we can't really work on that yet. +Please kindly inform OmniVision that you would like them to release their +specifications to the Linux community. + +HOW TO CONTACT ME: + +You can email me at mmcclelland@delphi.com . Please prefix the subject line +with "OV511: " so that I am certain to notice your message. + +CREDITS: + +The code is based in no small part on the CPiA driver by Johannes Erdfelt, +Randy Dunlap, and others. Big thanks to them for their pioneering work on that +and the USB stack. Thanks to Bret Wallach for getting camera reg IO and ISOC +working. diff -u --recursive --new-file v2.3.35/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.35/linux/drivers/usb/acm.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/acm.c Tue Jan 4 11:30:23 2000 @@ -243,13 +243,10 @@ if (!acm->present) return -EINVAL; - if (acm->used++) { - MOD_INC_USE_COUNT; - return 0; - } - MOD_INC_USE_COUNT; + if (acm->used++) return 0; + if (usb_submit_urb(&acm->ctrlurb)) acm_debug("usb_submit_urb(ctrl irq) failed"); @@ -265,18 +262,18 @@ { struct acm *acm = tty->driver_data; - if (!ACM_READY(acm)) return; - - if (--acm->used) { - MOD_DEC_USE_COUNT; - return; - } - - acm_set_control(acm->ctrlout = 0, acm); - usb_unlink_urb(&acm->writeurb); - usb_unlink_urb(&acm->readurb); + if (!acm->used) return; MOD_DEC_USE_COUNT; + + if (--acm->used) return; + + if (acm->present) { + acm_set_control(acm->ctrlout = 0, acm); + usb_unlink_urb(&acm->ctrlurb); + usb_unlink_urb(&acm->writeurb); + usb_unlink_urb(&acm->readurb); + } } static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) @@ -348,7 +345,6 @@ struct usb_endpoint_descriptor *epctrl, *epread, *epwrite; int readsize, ctrlsize, minor, i; unsigned char *buf; - char *s = NULL; for (minor = 0; minor < ACM_TTY_MINORS && (acm_table[minor].present || acm_table[minor].used); minor++); @@ -422,6 +418,8 @@ usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 0, acm); usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 1, acm); + + acm_set_control(acm->ctrlout, acm); acm->present = 1; diff -u --recursive --new-file v2.3.35/linux/drivers/usb/evdev.c linux/drivers/usb/evdev.c --- v2.3.35/linux/drivers/usb/evdev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/evdev.c Sun Jan 2 12:12:59 2000 @@ -0,0 +1,275 @@ +/* + * evdev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Event char devices, giving access to raw input device events. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#define EVDEV_MINOR_BASE 64 +#define EVDEV_BUFFER_SIZE 64 + +#include +#include +#include +#include +#include +#include + +struct evdev { + char name[32]; + int used; + struct input_handle handle; + struct miscdevice misc; + wait_queue_head_t wait; + struct evdev_list *list; +}; + +struct evdev_list { + struct input_event buffer[EVDEV_BUFFER_SIZE]; + int head; + int tail; + struct fasync_struct *fasync; + struct evdev *evdev; + struct evdev_list *next; +}; + +static unsigned long evdev_miscbits = 0; +static struct evdev *evdev_base[BITS_PER_LONG]; + +static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct evdev *evdev = handle->private; + struct evdev_list *list = evdev->list; + + while (list) { + + get_fast_time(&list->buffer[list->head].time); + list->buffer[list->head].type = type; + list->buffer[list->head].code = code; + list->buffer[list->head].value = value; + list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&evdev->wait); +} + +static int evdev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct evdev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int evdev_release(struct inode * inode, struct file * file) +{ + struct evdev_list *list = file->private_data; + struct evdev_list **listptr = &list->evdev->list; + + evdev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->evdev->used) { + clear_bit(list->evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits); + misc_deregister(&list->evdev->misc); + kfree(list->evdev); + } + + kfree(list); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int evdev_open(struct inode * inode, struct file * file) +{ + struct evdev_list *list; + int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE; + + if (i > BITS_PER_LONG || !test_bit(i, &evdev_miscbits)) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) + return -ENOMEM; + + memset(list, 0, sizeof(struct evdev_list)); + + list->evdev = evdev_base[i]; + list->next = evdev_base[i]->list; + evdev_base[i]->list = list; + + file->private_data = list; + + list->evdev->used++; + + MOD_INC_USE_COUNT; + return 0; +} + +static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct evdev_list *list = file->private_data; + int retval = 0; + + if (list->head == list->tail) { + + add_wait_queue(&list->evdev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (list->head == list->tail) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->evdev->wait, &wait); + } + + if (retval) + return retval; + + while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { + if (copy_to_user(buffer + retval, list->buffer + list->tail, + sizeof(struct input_event))) return -EFAULT; + list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); + retval += sizeof(struct input_event); + } + + return retval; +} + +static unsigned int evdev_poll(struct file *file, poll_table *wait) +{ + struct evdev_list *list = file->private_data; + poll_wait(file, &list->evdev->wait, wait); + if (list->head != list->tail) + return POLLIN | POLLRDNORM; + return 0; +} + +static struct file_operations evdev_fops = { + read: evdev_read, + write: evdev_write, + poll: evdev_poll, + open: evdev_open, + release: evdev_release, + fasync: evdev_fasync, +}; + +static int evdev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct evdev *evdev; + + if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL))) + return -1; + + memset(evdev, 0, sizeof(struct evdev)); + + init_waitqueue_head(&evdev->wait); + + evdev->misc.minor = ffz(evdev_miscbits); + set_bit(evdev->misc.minor, &evdev_miscbits); + evdev_base[evdev->misc.minor] = evdev; + + sprintf(evdev->name, "evdev%d", evdev->misc.minor); + evdev->misc.name = evdev->name; + evdev->misc.minor += EVDEV_MINOR_BASE; + evdev->misc.fops = &evdev_fops; + + evdev->handle.dev = dev; + evdev->handle.handler = handler; + evdev->handle.private = evdev; + + evdev->used = 1; + + misc_register(&evdev->misc); + input_open_device(&evdev->handle); + + printk("%s: Event device for input%d on misc%d - /dev/input%d\n", + evdev->name, dev->number, evdev->misc.minor, evdev->misc.minor - EVDEV_MINOR_BASE); + + return 0; +} + +static void evdev_disconnect(struct input_handle *handle) +{ + struct evdev *evdev = handle->private; + + input_close_device(handle); + + if (!--evdev->used) { + clear_bit(evdev->misc.minor - EVDEV_MINOR_BASE, &evdev_miscbits); + misc_deregister(&evdev->misc); + kfree(evdev); + } +} + +static struct input_handler evdev_handler = { + event: evdev_event, + connect: evdev_connect, + disconnect: evdev_disconnect, +}; + +#ifdef MODULE +int init_module(void) +#else +int __init evdev_init(void) +#endif +{ + input_register_handler(&evdev_handler); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + input_unregister_handler(&evdev_handler); +} +#endif diff -u --recursive --new-file v2.3.35/linux/drivers/usb/hid-debug.h linux/drivers/usb/hid-debug.h --- v2.3.35/linux/drivers/usb/hid-debug.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hid-debug.h Sun Jan 2 12:12:59 2000 @@ -0,0 +1,233 @@ +/* + * driver/usb/hid-debug.h + * + * (c) 1999 Andreas Gal + * (c) 1999 Vojtech Pavlik + * + * Some debug stuff for the HID parser. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +struct hid_usage_entry { + unsigned page; + unsigned usage; + char *description; +}; + +static struct hid_usage_entry hid_usage_table[] = { + { 1, 0, "GenericDesktop" }, + {0, 0x01, "Pointer"}, + {0, 0x02, "Mouse"}, + {0, 0x04, "Joystick"}, + {0, 0x05, "GamePad"}, + {0, 0x06, "Keyboard"}, + {0, 0x07, "Keypad"}, + {0, 0x08, "MultiAxis"}, + {0, 0x30, "X"}, + {0, 0x31, "Y"}, + {0, 0x32, "Z"}, + {0, 0x33, "Rx"}, + {0, 0x34, "Ry"}, + {0, 0x35, "Rz"}, + {0, 0x36, "Slider"}, + {0, 0x37, "Dial"}, + {0, 0x38, "Wheel"}, + {0, 0x39, "HatSwitch"}, + {0, 0x3a, "CountedBuffer"}, + {0, 0x3b, "ByteCount"}, + {0, 0x3c, "MotionWakeup"}, + {0, 0x3d, "Start"}, + {0, 0x3e, "Select"}, + {0, 0x40, "Vx"}, + {0, 0x41, "Vy"}, + {0, 0x42, "Vz"}, + {0, 0x43, "Vbrx"}, + {0, 0x44, "Vbry"}, + {0, 0x45, "Vbrz"}, + {0, 0x46, "Vno"}, + {0, 0x80, "SystemControl"}, + {0, 0x81, "System PowerDown"}, + {0, 0x82, "System Sleep"}, + {0, 0x83, "System WakeUp"}, + {0, 0x84, "System ContextMenu"}, + {0, 0x85, "System MainMenu"}, + {0, 0x86, "System AppMenu"}, + {0, 0x87, "System MenuHelp"}, + {0, 0x88, "System MenuExit"}, + {0, 0x89, "System MenuSelect"}, + {0, 0x8a, "System MenuRight"}, + {0, 0x8b, "System MenuLeft"}, + {0, 0x8c, "System MenuUp"}, + {0, 0x8d, "System MenuDown"}, + {0, 0x90, "D-padUp"}, + {0, 0x91, "D-padDown"}, + {0, 0x92, "D-padRight"}, + {0, 0x93, "D-padLeft"}, + { 7, 0, "Keyboard" }, + { 8, 0, "LED" }, + { 9, 0, "Button" }, + { 13, 0, "Digitizers" }, + {0, 0x01, "Digitizer"}, + {0, 0x02, "Pen"}, + {0, 0x03, "LightPen"}, + {0, 0x04, "TouchScreen"}, + {0, 0x05, "TouchPad"}, + {0, 0x20, "Stylus"}, + {0, 0x21, "Puck"}, + {0, 0x22, "Finger"}, + {0, 0x30, "TipPressure"}, + {0, 0x31, "BarrelPressure"}, + {0, 0x32, "InRange"}, + {0, 0x33, "Touch"}, + {0, 0x34, "UnTouch"}, + {0, 0x35, "Tap"}, + {0, 0x39, "TabletFunctionKey"}, + {0, 0x3a, "ProgramChangeKey"}, + {0, 0x42, "TipSwitch"}, + {0, 0x43, "SecondaryTipSwitch"}, + {0, 0x44, "BarrelSwitch"}, + {0, 0x45, "Eraser"}, + {0, 0x46, "TabletPick"}, + { 15, 0, "PhysicalInterfaceDevice" }, + { 0, 0, NULL } +}; + +static void resolv_usage_page(unsigned page) { + struct hid_usage_entry *p; + + for (p = hid_usage_table; p->description; p++) + if (p->page == page) { + printk("%s", p->description); + return; + } + printk("%04x", page); +} + +static void resolv_usage(unsigned usage) { + struct hid_usage_entry *p; + + resolv_usage_page(usage >> 16); + printk("."); + for (p = hid_usage_table; p->description; p++) + if (p->page == (usage >> 16)) { + for(++p; p->description && p->page == 0; p++) + if (p->usage == (usage & 0xffff)) { + printk("%s", p->description); + return; + } + break; + } + printk("%04x", usage & 0xffff); +} + +__inline__ static void tab(int n) { + while (n--) printk(" "); +} + +static void hid_dump_field(struct hid_field *field, int n) { + int j; + + if (field->physical) { + tab(n); + printk("Physical("); + resolv_usage(field->physical); printk(")\n"); + } + if (field->logical) { + tab(n); + printk("Logical("); + resolv_usage(field->logical); printk(")\n"); + } + tab(n); printk("Usage(%d)\n", field->maxusage); + for (j = 0; j < field->maxusage; j++) { + tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); + } + if (field->logical_minimum != field->logical_maximum) { + tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); + tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); + } + if (field->physical_minimum != field->physical_maximum) { + tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); + tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); + } + if (field->unit_exponent) { + tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); + } + if (field->unit) { + tab(n); printk("Unit(%u)\n", field->unit); + } + tab(n); printk("Report Size(%u)\n", field->report_size); + tab(n); printk("Report Count(%u)\n", field->report_count); + tab(n); printk("Report Offset(%u)\n", field->report_offset); + + tab(n); printk("Flags( "); + j = field->flags; + printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); + printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); + printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); + printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); + printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); + printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); + printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); + printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); + printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); + printk(")\n"); +} + +void hid_dump_device(struct hid_device *device) { + struct hid_report_enum *report_enum; + struct hid_report *report; + struct list_head *list; + unsigned i,k; + static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; + + printk("Application("); + resolv_usage(device->application); + printk(")\n"); + + for (i = 0; i < HID_REPORT_TYPES; i++) { + report_enum = device->report_enum + i; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + tab(2); + printk("%s", table[i]); + if (report->id) + printk("(%d)", report->id); + printk("[%s]", table[report->type]); + printk("\n"); + for (k = 0; k < report->maxfield; k++) { + tab(4); + printk("Field(%d)\n", k); + hid_dump_field(report->field[k], 6); + } + list = list->next; + } + } +} + +void hid_dump_input(struct hid_usage *usage, __s32 value) { + printk("hidd: input "); + resolv_usage(usage->hid); + printk(" = %d\n", value); +} diff -u --recursive --new-file v2.3.35/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.3.35/linux/drivers/usb/hid.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hid.c Tue Jan 4 11:17:47 2000 @@ -0,0 +1,1201 @@ +/* + * hid.c Version 0.8 + * + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 1999 Vojtech Pavlik + * + * USB HID support for the Linux input drivers + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb.h" +#include "hid.h" + +#ifdef CONFIG_USB_HID_DEBUG_LOTS +#include "hid-debug.h" +#else +#define hid_dump_input(a,b) do { } while (0) +#define hid_dump_device(c) do { } while (0) +#endif + +static unsigned char hid_keyboard[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43,192, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123,192,138,192,192,128,129,131,137,133,135,136,113, + 115,114,192,192,192,192,192,124,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 29, 42, 56,125, 97, 54,100,126 +}; + +static struct { + __s32 x; + __s32 y; +} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + +/* + * Register a new report for a device. + */ + +static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) +{ + struct hid_report_enum *report_enum = device->report_enum + type; + struct hid_report *report; + + if (report_enum->report_id_hash[id]) + return report_enum->report_id_hash[id]; + + if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL))) + return NULL; + memset(report, 0, sizeof(struct hid_report)); + + if (id != 0) report_enum->numbered = 1; + + report->id = id; + report->type = type; + report->size = 0; + report->device = device; + report_enum->report_id_hash[id] = report; + + list_add_tail(&report->list, &report_enum->report_list); + + return report; +} + +/* + * Register a new field for this report. + */ + +static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) +{ + if (report->maxfield < HID_MAX_FIELDS) { + struct hid_field *field; + + if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + + values * sizeof(unsigned), GFP_KERNEL))) + return NULL; + memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + + values * sizeof(unsigned)); + + report->field[report->maxfield++] = field; + field->usage = (struct hid_usage *)(field + 1); + field->value = (unsigned *)(field->usage + usages); + field->report = report; + + return field; + } + + hid_debug("too many fields in report"); + return NULL; +} + +/* + * Open a collection. The type/usage is pushed on the stack. + */ + +static int open_collection(struct hid_parser *parser, unsigned type) +{ + unsigned usage; + + usage = parser->local.usage[0]; + + if (type == HID_COLLECTION_APPLICATION) + parser->device->application = usage; + + if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */ + struct hid_collection *collection = parser->collection_stack + parser->collection_stack_ptr++; + collection->type = type; + collection->usage = usage; + return 0; + } + + hid_debug("collection stack overflow"); + return -1; +} + +/* + * Close a collection. + */ + +static int close_collection(struct hid_parser *parser) +{ + if (parser->collection_stack_ptr > 0) { /* POP from stack */ + parser->collection_stack_ptr--; + return 0; + } + hid_debug("collection stack underflow"); + return -1; +} + +/* + * Climb up the stack, search for the specified collection type + * and return the usage. + */ + +static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) +{ + int n; + for (n = parser->collection_stack_ptr - 1; n >= 0; n--) + if (parser->collection_stack[n].type == type) + return parser->collection_stack[n].usage; + return 0; /* we know nothing about this usage type */ +} + +/* + * Add a usage to the temporary parser table. + */ + +static int hid_add_usage(struct hid_parser *parser, unsigned usage) +{ + if (parser->local.usage_index >= MAX_USAGES) { + hid_debug("usage index exceeded"); + return -1; + } + parser->local.usage[parser->local.usage_index++] = usage; + return 0; +} + +/* + * Register a new field for this report. + */ + +static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) +{ + struct hid_report *report; + struct hid_field *field; + int usages; + unsigned offset; + int i; + + if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { + hid_debug("hid_register_report failed"); + return -1; + } + + if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */ + if (parser->global.logical_maximum <= parser->global.logical_minimum) { + hid_debug("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); + return -1; + } + usages = parser->local.usage_index; + /* Hint: we can assume usages < MAX_USAGE here */ + } else { /* VARIABLE */ + usages = parser->global.report_count; + } + offset = report->size; + report->size += parser->global.report_size * + parser->global.report_count; + if (usages == 0) + return 0; /* ignore padding fields */ + if ((field = hid_register_field(report, usages, + parser->global.report_count)) == NULL) + return 0; + field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); + field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); + for (i = 0; i < usages; i++) field->usage[i].hid = parser->local.usage[i]; + field->maxusage = usages; + field->flags = flags; + field->report_offset = offset; + field->report_type = report_type; + field->report_size = parser->global.report_size; + field->report_count = parser->global.report_count; + field->logical_minimum = parser->global.logical_minimum; + field->logical_maximum = parser->global.logical_maximum; + field->physical_minimum = parser->global.physical_minimum; + field->physical_maximum = parser->global.physical_maximum; + field->unit_exponent = parser->global.unit_exponent; + field->unit = parser->global.unit; + return 0; +} + +/* + * Read data value from item. + */ + +static __inline__ __u32 item_udata(struct hid_item *item) +{ + switch (item->size) { + case 1: return item->data.u8; + case 2: return item->data.u16; + case 4: return item->data.u32; + } + return 0; +} + +static __inline__ __s32 item_sdata(struct hid_item *item) +{ + switch (item->size) { + case 1: return item->data.s8; + case 2: return item->data.s16; + case 4: return item->data.s32; + } + return 0; +} + +/* + * Process a global item. + */ + +static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) +{ + switch (item->tag) { + + case HID_GLOBAL_ITEM_TAG_PUSH: + + if (parser->global_stack_ptr < HID_GLOBAL_STACK_SIZE) { + memcpy(parser->global_stack + parser->global_stack_ptr++, + &parser->global, sizeof(struct hid_parser)); + return 0; + } + hid_debug("global enviroment stack overflow"); + return -1; + + case HID_GLOBAL_ITEM_TAG_POP: + + if (parser->global_stack_ptr > 0) { + memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, + sizeof(struct hid_parser)); + return 0; + } + hid_debug("global enviroment stack underflow"); + return -1; + + case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: + parser->global.usage_page = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: + parser->global.logical_minimum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: + parser->global.logical_maximum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: + parser->global.physical_minimum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: + parser->global.physical_maximum = item_sdata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: + parser->global.unit_exponent = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_UNIT: + parser->global.unit = item_udata(item); + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: + if ((parser->global.report_size = item_udata(item)) > 32) { + hid_debug("invalid report_size %d", parser->global.report_size); + return -1; + } + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: + if ((parser->global.report_count = item_udata(item)) > MAX_USAGES) { + hid_debug("invalid report_count %d", parser->global.report_count); + return -1; + } + return 0; + + case HID_GLOBAL_ITEM_TAG_REPORT_ID: + if ((parser->global.report_id = item_udata(item)) == 0) { + hid_debug("report_id 0 is invalid"); + return -1; + } + return 0; + + default: + hid_debug("unknown global tag 0x%x", item->tag); + return -1; + } +} + +/* + * Process a local item. + */ + +static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) +{ + __u32 data; + + if (item->size == 0) { + hid_debug("item data expected for local item"); + return -1; + } + + data = item_udata(item); + + switch (item->tag) { + + case HID_LOCAL_ITEM_TAG_DELIMITER: + + if (data) { + /* + * We treat items before the first delimiter + * as global to all usage sets (branch 0). + * In the moment we process only these global + * items and the first delimiter set. + */ + if (parser->local.delimiter_depth != 0) { + hid_debug("nested delimiters"); + return -1; + } + parser->local.delimiter_depth++; + parser->local.delimiter_branch++; + } else { + if (parser->local.delimiter_depth < 1) { + hid_debug("bogus close delimiter"); + return -1; + } + parser->local.delimiter_depth--; + } + return 1; + + case HID_LOCAL_ITEM_TAG_USAGE: + + if (parser->local.delimiter_branch < 2) { + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + return hid_add_usage(parser, data); + } + hid_debug("alternative usage ignored"); + return 0; + + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: + + if (parser->local.delimiter_branch < 2) { + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + parser->local.usage_minimum = data; + return 0; + } + hid_debug("alternative usage ignored"); + return 0; + + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: + + if (parser->local.delimiter_branch < 2) { + unsigned n; + if (item->size <= 2) + data = (parser->global.usage_page << 16) + data; + for (n = parser->local.usage_minimum; n <= data; n++) + if (hid_add_usage(parser, n)) { + hid_debug("hid_add_usage failed\n"); + return -1; + } + return 0; + } + hid_debug("alternative usage ignored"); + return 0; + + default: + + hid_debug("unknown local item tag 0x%x", item->tag); + return 0; + } +} + +/* + * Process a main item. + */ + +static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) +{ + __u32 data; + int ret; + + data = item_udata(item); + + switch (item->tag) { + case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: + ret = open_collection(parser, data & 3); + break; + case HID_MAIN_ITEM_TAG_END_COLLECTION: + ret = close_collection(parser); + break; + case HID_MAIN_ITEM_TAG_INPUT: + ret = hid_add_field(parser, HID_INPUT_REPORT, data); + break; + case HID_MAIN_ITEM_TAG_OUTPUT: + ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); + break; + case HID_MAIN_ITEM_TAG_FEATURE: + ret = hid_add_field(parser, HID_FEATURE_REPORT, data); + break; + default: + hid_debug("unknown main item tag 0x%x", item->tag); + ret = 0; + } + + memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ + + return ret; +} + +/* + * Process a reserved item. + */ + +static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) +{ + hid_debug("reserved item type, tag 0x%x", item->tag); + return 0; +} + +/* + * Free a report and all registered fields. The field->usage and + * field->value table's are allocated behind the field, so we need + * only to free(field) itself. + */ + +static void hid_free_report(struct hid_report *report) +{ + unsigned n; + + for (n = 0; n < report->maxfield; n++) + kfree(report->field[n]); + kfree(report); +} + +/* + * Free a device structure, all reports, and all fields. + */ + +static void hid_free_device(struct hid_device *device) +{ + unsigned i,j; + + for (i = 0; i < HID_REPORT_TYPES; i++) { + struct hid_report_enum *report_enum = device->report_enum + i; + + for (j = 0; j < 256; j++) { + struct hid_report *report = report_enum->report_id_hash[j]; + if (report) hid_free_report(report); + } + } + + if (device->rdesc) kfree(device->rdesc); +} + +/* + * Fetch a report description item from the data stream. We support long + * items, though they are not used yet. + */ + +static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) +{ + if ((end - start) > 0) { + + __u8 b = *start++; + item->type = (b >> 2) & 3; + item->tag = (b >> 4) & 15; + + if (item->tag == HID_ITEM_TAG_LONG) { + + item->format = HID_ITEM_FORMAT_LONG; + + if ((end - start) >= 2) { + + item->size = *start++; + item->tag = *start++; + + if ((end - start) >= item->size) { + item->data.longdata = start; + start += item->size; + return start; + } + } + } else { + + item->format = HID_ITEM_FORMAT_SHORT; + item->size = b & 3; + switch (item->size) { + + case 0: + return start; + + case 1: + if ((end - start) >= 1) { + item->data.u8 = *start++; + return start; + } + break; + + case 2: + if ((end - start) >= 2) { + item->data.u16 = le16_to_cpu( *((__u16*)start)++); + return start; + } + + case 3: + item->size++; + if ((end - start) >= 4) { + item->data.u32 = le32_to_cpu( *((__u32*)start)++); + return start; + } + } + } + } + return NULL; +} + +/* + * Parse a report description into a hid_device structure. Reports are + * enumerated, fields are attached to these reports. + */ + +static struct hid_device *hid_parse_report(__u8 *start, unsigned size) +{ + struct hid_device *device; + struct hid_parser *parser; + struct hid_item item; + __u8 *end; + unsigned i; + static int (*dispatch_type[])(struct hid_parser *parser, + struct hid_item *item) = { + hid_parser_main, + hid_parser_global, + hid_parser_local, + hid_parser_reserved + }; + + if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL))) + return NULL; + memset(device, 0, sizeof(struct hid_device)); + + for (i = 0; i < HID_REPORT_TYPES; i++) + INIT_LIST_HEAD(&device->report_enum[i].report_list); + + if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { + kfree(device); + return NULL; + } + memcpy(device->rdesc, start, size); + + if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) { + kfree(device->rdesc); + kfree(device); + return NULL; + } + memset(parser, 0, sizeof(struct hid_parser)); + parser->device = device; + + end = start + size; + while ((start = fetch_item(start, end, &item)) != 0) { + if (item.format != HID_ITEM_FORMAT_SHORT) { + hid_debug("unexpected long global item"); + hid_free_device(device); + kfree(parser); + return NULL; + } + if (dispatch_type[item.type](parser, &item)) { + hid_debug("item %u %u %u %u parsing failed\n", + item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); + hid_free_device(device); + kfree(parser); + return NULL; + } + + if (start == end) { + if (parser->collection_stack_ptr) { + hid_debug("unbalanced collection at end of report description"); + hid_free_device(device); + kfree(parser); + return NULL; + } + if (parser->local.delimiter_depth) { + hid_debug("unbalanced delimiter at end of report description"); + hid_free_device(device); + kfree(parser); + return NULL; + } + kfree(parser); + return device; + } + } + + hid_debug("item fetching failed at offset %d\n", (int)(end - start)); + hid_free_device(device); + kfree(parser); + return NULL; +} + +/* + * Convert a signed n-bit integer to signed 32-bit integer. Common + * cases are done through the compiler, the screwed things has to be + * done by hand. + */ + +static __inline__ __s32 snto32(__u32 value, unsigned n) +{ + switch (n) { + case 8: return ((__s8)value); + case 16: return ((__s16)value); + case 32: return ((__s32)value); + } + return value & (1 << (n - 1)) ? value | (-1 << n) : value; +} + +/* + * Convert a signed 32-bit integer to a signed n-bit integer. + */ + +static __inline__ __u32 s32ton(__s32 value, unsigned n) +{ + __s32 a = value >> (n - 1); + if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1; + return value & ((1 << n) - 1); +} + +/* + * Extract/implement a data field from/to a report. We use 64-bit unsigned, + * 32-bit aligned, so that we can possibly have alignment problems on some + * odd architectures. + */ + +static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) +{ + report += (offset >> 5) << 2; offset &= 31; + return (le64_to_cpu(*(__u64*)report) >> offset) & ((1 << n) - 1); +} + +static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) +{ + report += (offset >> 5) << 2; offset &= 31; + *(__u64*)report &= cpu_to_le64(~((1ULL << n) - 1) << offset); + *(__u64*)report |= cpu_to_le64((__u64)value << offset); +} + +static void hid_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage) +{ + struct input_dev *input = &device->input; + int max; + unsigned long *bit; + + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_KEYBOARD: + + if ((usage->hid & HID_USAGE) < 256) { + if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE])) + return; + } else + usage->code = KEY_UNKNOWN; + + set_bit(EV_REP, input->evbit); + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + break; + + case HID_UP_BUTTON: + + usage->code = ((usage->hid - 1) & 0xf) + 0x100; + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + + switch (device->application) { + case HID_GD_GAMEPAD: usage->code += 0x10; + case HID_GD_JOYSTICK: usage->code += 0x10; + case HID_GD_MOUSE: usage->code += 0x10; + } + break; + + case HID_UP_GENDESK: + + usage->code = usage->hid & 0xf; + + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + usage->type = EV_REL; bit = input->relbit; max = REL_MAX; + break; + } + + usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; + + if (usage->hid == HID_GD_HATSWITCH) { + usage->code = ABS_HAT0X; + usage->hat = 1 + (field->logical_maximum == 4); + } + break; + + default: + + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + usage->code = REL_MISC; + usage->type = EV_REL; bit = input->relbit; max = REL_MAX; + break; + } + + if (field->logical_minimum == 0 && field->logical_maximum == 1) { + usage->code = BTN_MISC; + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; + break; + } + + usage->code = ABS_MISC; + usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; + break; + } + + set_bit(usage->type, input->evbit); + + while (usage->code <= max && test_and_set_bit(usage->code, bit)) { + usage->code = find_next_zero_bit(bit, max + 1, usage->code); + } + + if (usage->type == EV_ABS) { + int a = field->logical_minimum; + int b = field->logical_maximum; + + input->absmin[usage->code] = a; + input->absmax[usage->code] = b; + input->absfuzz[usage->code] = (b - a) >> 8; + input->absflat[usage->code] = (b - a) >> 4; + } + + if (usage->hat) { + int i; + for (i = usage->code; i < usage->code + 2; i++) { + input->absmax[i] = 1; + input->absmin[i] = -1; + input->absfuzz[i] = 0; + input->absflat[i] = 0; + } + set_bit(usage->code + 1, input->absbit); + } +} + +static void hid_process_event(struct input_dev *input, struct hid_usage *usage, __s32 value) +{ + hid_dump_input(usage, value); + + if (usage->hat) { + if (usage->hat == 2) value = value * 2 - 1; + input_event(input, usage->type, usage->code , hid_hat_to_axis[value].x); + input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y); + return; + } + + input_event(input, usage->type, usage->code, value); +} + +/* + * Search an array for a value. + */ + +static __inline__ int search(__s32 *array, __s32 value, unsigned n) +{ + while (n--) if (*array++ == value) return 0; + return -1; +} + +/* + * Analyse a received field, and fetch the data from it. The field + * content is stored for next report processing (we do differential + * reporting to the layer). + */ + +static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u8 *data) +{ + unsigned n; + unsigned count = field->report_count; + unsigned offset = field->report_offset; + unsigned size = field->report_size; + __s32 min = field->logical_minimum; + __s32 max = field->logical_maximum; + __s32 value[count]; /* WARNING: gcc specific */ + + for (n = 0; n < count; n++) + value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : + extract(data, offset + n * size, size); + + for (n = 0; n < count; n++) { + + if (HID_MAIN_ITEM_VARIABLE & field->flags) { + + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + if (!value[n]) continue; + } else { + if (value[n] == field->value[n]) continue; + } + hid_process_event(&dev->input, &field->usage[n], value[n]); + + } else { + + if (field->value[n] >= min && field->value[n] <= max /* non-NULL value */ + && field->usage[field->value[n] - min].hid /* nonzero usage */ + && search(value, field->value[n], count)) + hid_process_event(&dev->input, &field->usage[field->value[n] - min], 0); + + if (value[n] >= min && value[n] <= max /* non-NULL value */ + && field->usage[value[n] - min].hid /* nonzero usage */ + && search(field->value, value[n], count)) + hid_process_event(&dev->input, &field->usage[value[n] - min], 1); + } + } + + memcpy(field->value, value, count * sizeof(__s32)); +} + +/* + * Interrupt input handler - analyse a received report. + */ + +static void hid_irq(struct urb *urb) +{ + struct hid_device *device = urb->context; + struct hid_report_enum *report_enum = device->report_enum + HID_INPUT_REPORT; + struct hid_report *report; + __u8 *data = urb->transfer_buffer; + int len = urb->actual_length; + int n; + + if (urb->status) { + hid_debug("nonzero status in irq %d", urb->status); + return; + } + + if (!len) { + hid_debug("empty report"); + return; + } + +#ifdef CONFIG_USB_HID_DEBUG_LOTS + printk(KERN_DEBUG "hid: report (size %u) (%snumbered) = ", len, report_enum->numbered ? "" : "un"); + for (n = 0; n < len; n++) + printk(" %02x", data[n]); + printk("\n"); +#endif + + n = 0; /* Normally report number is 0 */ + + if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ + n = *data++; + len--; + } + + if (!(report = report_enum->report_id_hash[n])) { + hid_debug("undefined report_id %d received", n); +#ifdef CONFIG_USB_HID_DEBUG + printk(KERN_DEBUG "hid: report (size %u) = ", len); + for (n = 0; n < len; n++) + printk(" %02x", data[n]); + printk("\n"); +#endif + + return; + } + + if (len < ((report->size - 1) >> 3) + 1) { + hid_debug("report %d is too short, (%d < %d)", report->id, len, ((report->size - 1) >> 3) + 1); + return; + } + + for (n = 0; n < report->maxfield; n++) + hid_input_field(device, report->field[n], data); + + return; +} + +/* + * Configure the input layer interface + * Read all reports and initalize the absoulte field values. + */ + +static void hid_init_input(struct hid_device *hid) +{ + struct hid_report_enum *report_enum = hid->report_enum + HID_INPUT_REPORT; + struct list_head *list; + int i, j; + + list = report_enum->report_list.next; + + while (list != &report_enum->report_list) { + + struct hid_report *report = (struct hid_report *) list; + int rlen = ((report->size - 1) >> 3) + 1 + report_enum->numbered; + int read; + + list = list->next; + + for (i = 0; i < report->maxfield; i++) + for (j = 0; j < report->field[i]->maxusage; j++) + hid_configure_usage(hid, report->field[i], report->field[i]->usage + j); + +#if 1 + { + char rdata[rlen]; + struct urb urb; + + memset(&urb, 0, sizeof(struct urb)); + memset(rdata, 0, rlen); + + urb.transfer_buffer = rdata; + urb.actual_length = rlen; + urb.context = hid; + + hid_debug("getting report type %d id %d len %d", report->type + 1, report->id, rlen); + + if ((read = usb_get_report(hid->dev, report->type + 1, report->id, hid->ifnum, rdata, rlen)) != rlen) { + hid_debug("reading report failed rlen %d read %d", rlen, read); +#ifdef CONFIG_USB_HID_DEBUG + printk(KERN_DEBUG "hid: report = "); + for (j = 0; j < rlen; j++) printk(" %02x", rdata[j]); + printk("\n"); +#endif + continue; + } + + hid_irq(&urb); + } +#endif + } +} + +/* + * Output the field into the report. + */ + +static void hid_output_field(struct hid_field *field, __u8 *data) +{ + unsigned count = field->report_count; + unsigned offset = field->report_offset; + unsigned size = field->report_size; + unsigned n; + + for (n = 0; n < count; n++) { + if (field->logical_minimum < 0) /* signed values */ + implement(data, offset + n * size, size, s32ton(field->value[n], size)); + else /* unsigned values */ + implement(data, offset + n * size, size, field->value[n]); + } +} + +/* + * Create a report. + */ + +void hid_output_report(struct hid_report *report, __u8 *data) +{ + unsigned n; + + /* skip the ID if we have a single report */ + if (report->device->report_enum[report->type].numbered) + *data++ = report->id; + + for (n = 0; n < report->maxfield; n++) + hid_output_field(report->field[n], data); +}; + +/* + * Set a field value. The report this field belongs to has to be + * created and transfered to the device, to set this value in the + * device. + */ + +int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) +{ + unsigned size = field->report_size; + + if (offset >= field->report_count) { + hid_debug("offset exceeds report_count"); + return -1; + } + if (field->logical_minimum < 0) { + if (value != snto32(s32ton(value, size), size)) { + hid_debug("value %d is out of range", value); + return -1; + } + } + if ( (value > field->logical_maximum) + || (value < field->logical_minimum)) { + hid_debug("value %d is invalid", value); + return -1; + } + field->value[offset] = value; + return 0; +} + +static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) +{ + struct usb_interface_descriptor *interface = &dev->actconfig->interface[ifnum].altsetting[0]; + struct usb_hid_descriptor *hdesc; + struct hid_device *hid; + unsigned rsize = 0; + int n; + + if (interface->bInterfaceClass != USB_INTERFACE_CLASS_HID) + return NULL; + + if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) + && usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc)) { + hid_debug("class descriptor not present\n"); + return NULL; + } + + for (n = 0; n < hdesc->bNumDescriptors; n++) + if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT) + rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); + + if (!rsize || rsize > 1024) { + hid_debug("weird size of report descriptor (%u)", rsize); + return NULL; + } + + { + __u8 rdesc[rsize]; + + if ((n = usb_get_class_descriptor(dev, USB_DT_REPORT, 0, ifnum, rdesc, rsize)) < 0) { + hid_debug("reading report descriptor failed"); + return NULL; + } + +#ifdef CONFIG_USB_HID_DEBUG + printk(KERN_DEBUG "hid: report (size %u, read %d) = ", rsize, n); + for (n = 0; n < rsize; n++) + printk(" %02x", (unsigned) rdesc[n]); + printk("\n"); +#endif + + if (!(hid = hid_parse_report(rdesc, rsize))) { + hid_debug("parsing report descriptor failed"); + return NULL; + } + } + + for (n = 0; n < interface->bNumEndpoints; n++) { + + struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; + int pipe, maxp; + + if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ + continue; + + if (!(endpoint->bEndpointAddress & 0x80)) /* Not an input endpoint */ + continue; + + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval); + + if (usb_submit_urb(&hid->urb)) { + hid_debug("submitting interrupt URB failed"); + continue; + } + + break; + } + + if (n == interface->bNumEndpoints) { + hid_debug("couldn't find an input interrupt endpoint"); + hid_free_device(hid); + return NULL; + } + + hid->version = hdesc->bcdHID; + hid->country = hdesc->bCountryCode; + hid->dev = dev; + hid->ifnum = ifnum; + + return hid; +} + +static void* hid_probe(struct usb_device *dev, unsigned int ifnum) +{ + char *hid_name[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", + "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; + struct hid_device *hid; + + hid_debug("HID probe called for ifnum %d", ifnum); + + if (!(hid = usb_hid_configure(dev, ifnum))) + return NULL; + + hid_dump_device(hid); + + hid_init_input(hid); + input_register_device(&hid->input); + + printk(KERN_INFO "input%d: USB HID v%d.%d %s\n", + hid->input.number, hid->version >> 8, hid->version & 0xff, + (hid->application & 0xffff) <= 8 ? hid_name[hid->application & 0xffff] : "device"); + + return hid; +} + +static void hid_disconnect(struct usb_device *dev, void *ptr) +{ + struct hid_device *hid = ptr; + + hid_debug("cleanup called"); + usb_unlink_urb(&hid->urb); + input_unregister_device(&hid->input); + hid_free_device(hid); +} + +static struct usb_driver hid_driver = { + name: "hid", + probe: hid_probe, + disconnect: hid_disconnect +}; + +#ifdef MODULE +void cleanup_module(void) +{ + usb_deregister(&hid_driver); +} + +int init_module(void) +#else +int hid_init(void) +#endif +{ + usb_register(&hid_driver); + return 0; +} diff -u --recursive --new-file v2.3.35/linux/drivers/usb/hid.h linux/drivers/usb/hid.h --- v2.3.35/linux/drivers/usb/hid.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/hid.h Tue Jan 4 12:21:47 2000 @@ -0,0 +1,345 @@ +#ifndef __HID_H +#define __HID_H + +/* + * drivers/usb/hid.h Version 0.8 + * + * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999 Andreas Gal + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include + +/* + * Enable/Disable debug information. + */ + +#ifdef CONFIG_USB_HID_DEBUG +#define hid_debug(fmt,arg...) printk(KERN_DEBUG "hid: " fmt "\n" , ##arg) +#else +#define hid_debug(fmt,arg...) do { } while (0) +#endif + +/* + * USB HID (Human Interface Device) interface class code + */ + +#define USB_INTERFACE_CLASS_HID 3 + +/* + * USB interface subclass codes. + */ + +#define USB_INTERFACE_SUBCLASS_NONE 0 +#define USB_INTERFACE_SUBCLASS_HID_BP 1 + +/* + * HID protocol codes (only for boot protocol) + */ + +#define HID_PROTOCOL_NONE 0 +#define HID_PROTOCOL_KBD 1 +#define HID_PROTOCOL_MOUSE 2 + +/* + * We parse each description item into this structure. Short items data + * values are expanded to 32-bit signed int, long items contain a pointer + * into the data area. + */ + +struct hid_item { + unsigned format; + __u8 size; + __u8 type; + __u8 tag; + union { + __u8 u8; + __s8 s8; + __u16 u16; + __s16 s16; + __u32 u32; + __s32 s32; + __u8 *longdata; + } data; +}; + +/* + * HID report item format + */ + +#define HID_ITEM_FORMAT_SHORT 0 +#define HID_ITEM_FORMAT_LONG 1 + +/* + * Special tag indicating long items + */ + +#define HID_ITEM_TAG_LONG 15 + +/* + * HID report descriptor item type (prefix bit 2,3) + */ + +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 + +/* + * HID report descriptor main item tags + */ + +#define HID_MAIN_ITEM_TAG_INPUT 8 +#define HID_MAIN_ITEM_TAG_OUTPUT 9 +#define HID_MAIN_ITEM_TAG_FEATURE 11 +#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 +#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 + +/* + * HID report descriptor main item contents + * Warning: VOLATILE is not available for TAG_INPUT + */ + +#define HID_MAIN_ITEM_CONSTANT 0x001 +#define HID_MAIN_ITEM_VARIABLE 0x002 +#define HID_MAIN_ITEM_RELATIVE 0x004 +#define HID_MAIN_ITEM_WRAP 0x008 +#define HID_MAIN_ITEM_NONLINEAR 0x010 +#define HID_MAIN_ITEM_NO_PREFERRED 0x020 +#define HID_MAIN_ITEM_NULL_STATE 0x040 +#define HID_MAIN_ITEM_VOLATILE 0x080 +#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 + +/* + * HID report descriptor collection item types + */ + +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 +#define HID_COLLECTION_LOGICAL 2 + +/* + * HID report descriptor global item tags + */ + +#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 +#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 +#define HID_GLOBAL_ITEM_TAG_UNIT 6 +#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 +#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 +#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 +#define HID_GLOBAL_ITEM_TAG_PUSH 10 +#define HID_GLOBAL_ITEM_TAG_POP 11 + +/* + * HID report descriptor local item tags + */ + +#define HID_LOCAL_ITEM_TAG_USAGE 0 +#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 +#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 +#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 +#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 +#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 +#define HID_LOCAL_ITEM_TAG_DELIMITER 10 + +/* + * HID usage tables + */ + +#define HID_USAGE_PAGE 0xffff0000 + +#define HID_UP_GENDESK 0x00010000 +#define HID_UP_KEYBOARD 0x00070000 +#define HID_UP_LED 0x00080000 +#define HID_UP_BUTTON 0x00090000 +#define HID_UP_DIGITIZER 0x000d0000 +#define HID_UP_PID 0x000f0000 + +#define HID_USAGE 0x0000ffff + +#define HID_GD_MOUSE 0x00010002 +#define HID_GD_JOYSTICK 0x00010004 +#define HID_GD_GAMEPAD 0x00010005 +#define HID_GD_HATSWITCH 0x00010039 + +/* + * HID interface requests (this belongs here, the USB_REQ_xxx stuff should + * disapear). + */ + +#define HID_REQ_GET_REPORT 0x01 +#define HID_REQ_GET_IDLE 0x02 +#define HID_REQ_GET_PROTOCOL 0x03 +#define HID_REQ_SET_REPORT 0x09 +#define HID_REQ_SET_IDLE 0x0A +#define HID_REQ_SET_PROTOCOL 0x0B + +/* + * HID report types --- Ouch! HID spec says 1 2 3! + */ + +#define HID_INPUT_REPORT 0 +#define HID_OUTPUT_REPORT 1 +#define HID_FEATURE_REPORT 2 + +/* + * HID protocols + */ + +#define HID_PROTOCOL_BOOT 0 +#define HID_PROTOCOL_REPORT 1 + +/* + * This is the global enviroment of the parser. This information is + * persistent for main-items. The global enviroment can be saved and + * restored with PUSH/POP statements. + */ + +struct hid_global { + unsigned usage_page; + __s32 logical_minimum; + __s32 logical_maximum; + __s32 physical_minimum; + __s32 physical_maximum; + unsigned unit_exponent; + unsigned unit; + unsigned report_id; + unsigned report_size; + unsigned report_count; +}; + +/* + * This is the local enviroment. It is resistent up the the next main-item. + */ + +#define MAX_USAGES 256 + +struct hid_local { + unsigned usage[MAX_USAGES]; /* usage array */ + unsigned usage_index; + unsigned usage_minimum; + unsigned delimiter_depth; + unsigned delimiter_branch; +}; + +/* + * This is the collection stack. We climb up the stack to determine + * application and function of each field. + */ + +struct hid_collection { + unsigned type; + unsigned usage; +}; + +struct hid_usage { + unsigned hid; /* hid usage code */ + __u16 code; /* input driver code */ + __u8 type; /* input driver type */ + __u8 hat; /* hat switch fun */ +}; + +struct hid_field { + unsigned physical; /* physical usage for this field */ + unsigned logical; /* logical usage for this field */ + struct hid_usage *usage; /* usage table for this function */ + unsigned maxusage; /* maximum usage index */ + unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ + unsigned report_offset; /* bit offset in the report */ + unsigned report_size; /* size of this field in the report */ + unsigned report_count; /* number of this field in the report */ + unsigned report_type; /* (input,output,feature) */ + __s32 *value; /* last known value(s) */ + __s32 logical_minimum; + __s32 logical_maximum; + __s32 physical_minimum; + __s32 physical_maximum; + unsigned unit_exponent; + unsigned unit; + struct hid_report *report; /* associated report */ +}; + +#define HID_MAX_FIELDS 64 + +struct hid_report { + struct list_head list; + unsigned id; /* id of this report */ + unsigned type; /* report type */ + struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ + unsigned maxfield; /* maximum valid field index */ + unsigned size; /* size of the report (bits) */ + struct hid_device *device; /* associated device */ +}; + +struct hid_report_enum { + unsigned numbered; + struct list_head report_list; + struct hid_report *report_id_hash[256]; +}; + +#define HID_REPORT_TYPES 3 + +struct hid_device { /* device report descriptor */ + __u8 *rdesc; + unsigned rsize; + unsigned application; /* HID application, i.e. Digitizer */ + unsigned version; /* HID version */ + unsigned country; /* HID country */ + struct hid_report_enum report_enum[HID_REPORT_TYPES]; + + struct usb_device *dev; /* USB device */ + int ifnum; /* USB interface number */ + + char buffer[32]; /* Receive buffer */ + struct urb urb; /* USB URB structure */ + struct input_dev input; /* input device structure */ +}; + +#define HID_GLOBAL_STACK_SIZE 4 +#define HID_COLLECTION_STACK_SIZE 4 + +struct hid_parser { + struct hid_global global; + struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; + unsigned global_stack_ptr; + struct hid_local local; + struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE]; + unsigned collection_stack_ptr; + struct hid_device *device; +}; + +#endif + diff -u --recursive --new-file v2.3.35/linux/drivers/usb/inits.h linux/drivers/usb/inits.h --- v2.3.35/linux/drivers/usb/inits.h Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/inits.h Wed Dec 31 16:00:00 1969 @@ -1,24 +0,0 @@ -int usb_acm_init(void); -void usb_acm_cleanup(void); -int usb_audio_init(void); -int usb_cpia_init(void); -void usb_cpia_cleanup(void); -int usb_dc2xx_init(void); -void usb_dc2xx_cleanup(void); -int usb_hub_init(void); -void usb_hub_cleanup(void); -int usb_kbd_init(void); -void usb_kbd_cleanup(void); -void usb_major_init(void); -void usb_major_cleanup(void); -int usb_mouse_init(void); -void usb_mouse_cleanup(void); -int usb_scanner_init(void); -void usb_scanner_cleanup(void); -int usb_printer_init(void); -int usb_scsi_init(void); -int usb_serial_init(void); -int dabusb_init(void); -void dabusb_cleanup(void); -int proc_usb_init(void); -void proc_usb_cleanup(void); diff -u --recursive --new-file v2.3.35/linux/drivers/usb/input.c linux/drivers/usb/input.c --- v2.3.35/linux/drivers/usb/input.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/input.c Sun Jan 2 12:12:59 2000 @@ -0,0 +1,335 @@ +/* + * input.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * The input layer module itself + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Vojtech Pavlik "); + +#ifndef MODULE +EXPORT_SYMBOL(input_register_device); +EXPORT_SYMBOL(input_unregister_device); +EXPORT_SYMBOL(input_register_handler); +EXPORT_SYMBOL(input_unregister_handler); +EXPORT_SYMBOL(input_open_device); +EXPORT_SYMBOL(input_close_device); +EXPORT_SYMBOL(input_event); +#endif + +static struct input_dev *input_dev = NULL; +static struct input_handler *input_handler = NULL; + +static int input_number = 0; + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct input_handle *handle = dev->handle; + +/* + * Filter non-events, and bad input values out. + */ + + if (type > EV_MAX || !test_bit(type, dev->evbit)) + return; + + switch (type) { + + case EV_KEY: + + if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) + return; + + if (value == 2) break; + + change_bit(code, dev->key); + + if (test_bit(EV_REP, dev->evbit) && dev->timer.function) { + if (value) { + mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]); + dev->repeat_key = code; + break; + } + if (dev->repeat_key == code) + del_timer(&dev->timer); + } + + break; + + case EV_ABS: + + if (code > ABS_MAX || !test_bit(code, dev->absbit) || (value == dev->abs[code])) + return; + + dev->abs[code] = value; + + break; + + case EV_REL: + + if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0)) + return; + + break; + + case EV_LED: + + if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) + return; + + change_bit(code, dev->led); + if (dev->event) dev->event(dev, type, code, value); + + break; + + case EV_SND: + + if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value) + return; + + change_bit(code, dev->snd); + if (dev->event) dev->event(dev, type, code, value); + + break; + + case EV_REP: + + if (code > REP_MAX || dev->rep[code] == value) return; + + dev->rep[code] = value; + if (dev->event) dev->event(dev, type, code, value); + + break; + } +/* + * Add randomness. + */ + +#if 0 /* BUG */ + add_input_randomness(((unsigned long) dev) ^ (type << 24) ^ (code << 16) ^ value); +#endif + +/* + * Distribute the event to handler modules. + */ + + while (handle) { + handle->handler->event(handle, type, code, value); + handle = handle->dnext; + } +} + +static void input_repeat_key(unsigned long data) +{ + struct input_dev *dev = (void *) data; + input_event(dev, EV_KEY, dev->repeat_key, 2); + mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]); +} + +void input_register_device(struct input_dev *dev) +{ + struct input_handler *handler = input_handler; + +/* + * Initialize repeat timer to default values. + */ + + init_timer(&dev->timer); + dev->timer.data = (long) dev; + dev->timer.function = input_repeat_key; + dev->rep[REP_DELAY] = HZ/4; + dev->rep[REP_PERIOD] = HZ/33; + +/* + * Add the device. + */ + + MOD_INC_USE_COUNT; + dev->number = input_number++; + dev->next = input_dev; + input_dev = dev; + +/* + * Notify handlers. + */ + + while (handler) { + handler->connect(handler, dev); + handler = handler->next; + } +} + +void input_unregister_device(struct input_dev *dev) +{ + struct input_handle *handle = dev->handle; + struct input_dev **devptr = &input_dev; + +/* + * Kill any pending repeat timers. + */ + + del_timer(&dev->timer); + +/* + * Notify handlers. + */ + + while (handle) { + handle->handler->disconnect(handle); + handle = handle->dnext; + } + +/* + * Remove the device. + */ + + while (*devptr && (*devptr != dev)) + devptr = &((*devptr)->next); + *devptr = (*devptr)->next; + + input_number--; + MOD_DEC_USE_COUNT; +} + +void input_register_handler(struct input_handler *handler) +{ + struct input_dev *dev = input_dev; + +/* + * Add the handler. + */ + + handler->next = input_handler; + input_handler = handler; + +/* + * Notify it about all existing devices. + */ + + while (dev) { + handler->connect(handler, dev); + dev = dev->next; + } +} + +void input_unregister_handler(struct input_handler *handler) +{ + struct input_handler **handlerptr = &input_handler; + struct input_handle *handle = handler->handle; + +/* + * Tell the handler to disconnect from all devices it keeps open. + */ + + while (handle) { + handler->disconnect(handle); + handle = handle->hnext; + } + +/* + * Remove it. + */ + + while (*handlerptr && (*handlerptr != handler)) + handlerptr = &((*handlerptr)->next); + + *handlerptr = (*handlerptr)->next; + +} + +void input_open_device(struct input_handle *handle) +{ + handle->dnext = handle->dev->handle; + handle->hnext = handle->handler->handle; + handle->dev->handle = handle; + handle->handler->handle = handle; + + if (handle->dev->open) + handle->dev->open(handle->dev); +} + +void input_close_device(struct input_handle *handle) +{ + struct input_handle **handleptr; + + if (handle->dev->close) + handle->dev->close(handle->dev); +/* + * Remove from device list of handles. + */ + + handleptr = &handle->dev->handle; + + while (*handleptr && (*handleptr != handle)) + handleptr = &((*handleptr)->dnext); + *handleptr = (*handleptr)->dnext; + +/* + * Remove from handler list of handles. + */ + + handleptr = &handle->handler->handle; + + while (*handleptr && (*handleptr != handle)) + handleptr = &((*handleptr)->hnext); + *handleptr = (*handleptr)->hnext; +} + + +#ifdef MODULE +int init_module(void) +#else +int __init input_init(void) +#endif +{ +#ifndef MODULE +#ifdef CONFIG_INPUT_KEYBDEV + keybdev_init(); +#endif +#ifdef CONFIG_INPUT_MOUSEDEV + mousedev_init(); +#endif +#ifdef CONFIG_INPUT_JOYDEV + joydev_init(); +#endif +#ifdef CONFIG_INPUT_EVDEV + evdev_init(); +#endif +#endif + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.3.35/linux/drivers/usb/joydev.c linux/drivers/usb/joydev.c --- v2.3.35/linux/drivers/usb/joydev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/joydev.c Sun Jan 2 12:12:59 2000 @@ -0,0 +1,476 @@ +/* + * joydev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * Copyright (c) 1999 Colin Van Dyke + * + * Joystick device driver for the input driver suite. + * + * Sponsored by SuSE and Intel + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define JOYDEV_MAJOR 15 +#define JOYDEV_BUFFER_SIZE 64 + +struct joydev { + char name[32]; + int used; + struct input_handle handle; + int minor; + wait_queue_head_t wait; + struct joydev *next; + struct joydev_list *list; + struct js_corr corr[ABS_MAX]; + struct JS_DATA_SAVE_TYPE glue; + int nabs; + int nkey; + __u16 keymap[KEY_MAX - BTN_0]; + __u16 keypam[KEY_MAX - BTN_0]; + __u8 absmap[ABS_MAX]; + __u8 abspam[ABS_MAX]; +}; + +struct joydev_list { + struct js_event buffer[JOYDEV_BUFFER_SIZE]; + int head; + int tail; + int startup; + struct fasync_struct *fasync; + struct joydev *joydev; + struct joydev_list *next; +}; + +static unsigned long joydev_minors = 0; +static struct joydev *joydev_base[BITS_PER_LONG]; + +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_SUPPORTED_DEVICE("js"); + +static int js_correct(int value, struct js_corr *corr) +{ + switch (corr->type) { + case JS_CORR_NONE: + break; + case JS_CORR_BROKEN: + value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : + ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : + ((corr->coef[2] * (value - corr->coef[0])) >> 14); + break; + default: + return 0; + } + + if (value < -32767) return -32767; + if (value > 32767) return 32767; + + return value; +} + +static void js_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct joydev *joydev = handle->private; + struct joydev_list *list = joydev->list; + struct js_event event; + + switch (type) { + + case EV_KEY: + if (code < BTN_0 || value == 2) return; + event.type = JS_EVENT_BUTTON; + event.number = joydev->keymap[code - BTN_0]; + event.value = value; + break; + + case EV_ABS: + event.type = JS_EVENT_AXIS; + event.number = joydev->absmap[code]; + event.value = js_correct(value, &joydev->corr[event.number]); + break; + + default: + return; + } + + event.time = jiffies * (1000 / HZ); + + while (list) { + + memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); + + if (list->startup == joydev->nabs + joydev->nkey) + if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) + list->startup = 0; + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&joydev->wait); +} + +static int joydev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct joydev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int joydev_release(struct inode * inode, struct file * file) +{ + struct joydev_list *list = file->private_data; + struct joydev_list **listptr = &list->joydev->list; + + joydev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + + if (!--list->joydev->used) { + clear_bit(list->joydev->minor, &joydev_minors); + kfree(list->joydev); + } + + kfree(list); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int joydev_open(struct inode *inode, struct file *file) +{ + struct joydev_list *list; + int i = MINOR(inode->i_rdev); + + if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR) + return -EINVAL; + + if (i > BITS_PER_LONG || !test_bit(i, &joydev_minors)) + return -ENODEV; + + if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) + return -ENOMEM; + + memset(list, 0, sizeof(struct joydev_list)); + + list->joydev = joydev_base[i]; + list->next = joydev_base[i]->list; + joydev_base[i]->list = list; + + file->private_data = list; + + list->joydev->used++; + + MOD_INC_USE_COUNT; + return 0; +} + +static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + struct input_dev *input = joydev->handle.dev; + int retval = 0; + + if (count < sizeof(struct js_event)) + return -EINVAL; + + if (count == sizeof(struct JS_DATA_TYPE)) { + + struct JS_DATA_TYPE data; + + data.buttons = (joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0 | + (joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0; + data.x = ((js_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x; + data.y = ((js_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y; + + if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) + return -EFAULT; + + list->startup = 0; + list->tail = list->head; + + return sizeof(struct JS_DATA_TYPE); + } + + if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) { + + add_wait_queue(&list->joydev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (list->head == list->tail) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->joydev->wait, &wait); + } + + if (retval) + return retval; + + while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { + + struct js_event event; + + event.time = jiffies * (1000/HZ); + + if (list->startup < joydev->nkey) { + event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; + event.value = !!test_bit(joydev->keypam[list->startup], input->key); + event.number = list->startup; + } else { + event.type = JS_EVENT_AXIS | JS_EVENT_INIT; + event.value = js_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]], + &joydev->corr[list->startup - joydev->nkey]); + event.number = list->startup - joydev->nkey; + } + + if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) + return -EFAULT; + + list->startup++; + retval += sizeof(struct js_event); + } + + while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { + + if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) + return -EFAULT; + + list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); + retval += sizeof(struct js_event); + } + + return retval; +} + +static unsigned int joydev_poll(struct file *file, poll_table *wait) +{ + struct joydev_list *list = file->private_data; + poll_wait(file, &list->joydev->wait, wait); + if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) + return POLLIN | POLLRDNORM; + return 0; +} + +static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct joydev_list *list = file->private_data; + struct joydev *joydev = list->joydev; + + switch (cmd) { + + case JS_SET_CAL: + return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg, + sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + case JS_GET_CAL: + return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR, + sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0; + case JS_SET_TIMEOUT: + return get_user(joydev->glue.JS_TIMEOUT, (int *) arg); + case JS_GET_TIMEOUT: + return put_user(joydev->glue.JS_TIMEOUT, (int *) arg); + case JS_SET_TIMELIMIT: + return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg); + case JS_GET_TIMELIMIT: + return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg); + case JS_SET_ALL: + return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg, + sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; + case JS_GET_ALL: + return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue, + sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0; + + case JSIOCGVERSION: + return put_user(JS_VERSION, (__u32 *) arg); + case JSIOCGAXES: + return put_user(joydev->nabs, (__u8 *) arg); + case JSIOCGBUTTONS: + return put_user(joydev->nkey, (__u8 *) arg); + case JSIOCSCORR: + return copy_from_user(joydev->corr, (struct js_corr *) arg, + sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + case JSIOCGCORR: + return copy_to_user((struct js_corr *) arg, joydev->corr, + sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0; + default: + if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { + int len = strlen(joydev->name) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + if (copy_to_user((char *) arg, joydev->name, len)) return -EFAULT; + return len; + } + } + return -EINVAL; +} + +static struct file_operations joydev_fops = { + read: joydev_read, + write: joydev_write, + poll: joydev_poll, + open: joydev_open, + release: joydev_release, + ioctl: joydev_ioctl, + fasync: joydev_fasync, +}; + +static int joydev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct joydev *joydev; + int i, j; + + if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && + test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) && + (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) + || test_bit(BTN_1, dev->keybit)))) return -1; + + if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) + return -1; + + memset(joydev, 0, sizeof(struct joydev)); + + init_waitqueue_head(&joydev->wait); + + if (joydev_minors == -1) { + printk("Can't register new joystick - 32 devices already taken.\n"); + return -1; + } + + sprintf(joydev->name, "joydev%d", joydev->minor); + + joydev->handle.dev = dev; + joydev->handle.handler = handler; + joydev->handle.private = joydev; + + joydev->used = 1; + + for (i = 0; i < ABS_MAX; i++) + if (test_bit(i, dev->absbit)) { + joydev->absmap[i] = joydev->nabs; + joydev->abspam[joydev->nabs] = i; + joydev->nabs++; + } + + for (i = 0; i < KEY_MAX - BTN_0; i++) + if (test_bit(i + BTN_0, dev->keybit)) { + joydev->keymap[i] = joydev->nkey; + joydev->keypam[joydev->nkey] = i + BTN_0; + joydev->nkey++; + } + + joydev->minor = ffz(joydev_minors); + set_bit(joydev->minor, &joydev_minors); + joydev_base[joydev->minor] = joydev; + + for (i = 0; i < joydev->nabs; i++) { + j = joydev->abspam[i]; + joydev->corr[i].type = JS_CORR_BROKEN; + joydev->corr[i].prec = dev->absfuzz[j]; + joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; + joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; + joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); + joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]); + } + + input_open_device(&joydev->handle); + + printk("%s: Joystick device for input%d on /dev/js%d\n", joydev->name, dev->number, joydev->minor); + + return 0; +} + +static void joydev_disconnect(struct input_handle *handle) +{ + struct joydev *joydev = handle->private; + + input_close_device(handle); + + if (!--joydev->used) { + clear_bit(joydev->minor, &joydev_minors); + kfree(joydev); + } +} + +static struct input_handler joydev_handler = { + event: js_event, + connect: joydev_connect, + disconnect: joydev_disconnect, +}; + +#ifdef MODULE +void cleanup_module(void) +{ + input_unregister_handler(&joydev_handler); + if (unregister_chrdev(JOYSTICK_MAJOR, "js")) + printk(KERN_ERR "js: can't unregister device\n"); +} + +int init_module(void) +#else +int __init joydev_init(void) +#endif +{ + if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) { + printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR); + return -EBUSY; + } + input_register_handler(&joydev_handler); + + return 0; +} diff -u --recursive --new-file v2.3.35/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.3.35/linux/drivers/usb/keybdev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/keybdev.c Sun Jan 2 12:12:59 2000 @@ -0,0 +1,139 @@ +/* + * keybdev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Input driver to keyboard driver binding. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_X86 + +static unsigned char keybdev_x86_e0s[] = + { 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48, + 0x49, 0x4b, 0x4d, 0x4f, 0x50, 0x51, 0x52, 0x53 }; + +#elif CONFIG_MAC_KEYBOARD + +static unsigned char keybdev_mac_codes[256] = + { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, + 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, + 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, + 11, 45, 46, 43, 47, 44,123, 67, 55, 49, 57,122,120, 99,118, 96, + 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, + 84, 85, 82, 65, 0, 0, 0,103,111, 0, 0, 0, 0, 0, 0, 0, + 76,125, 75, 0,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, + 0, 0, 0, 0,127, 81, 0,113 }; + +#endif + +void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down) +{ + if (type != EV_KEY || code > 255) return; + +#ifdef CONFIG_X86 + + if (code >= 125) { + handle_scancode(0xe0, 1); + handle_scancode(code - 34, down); + } else if (code == 119) { + handle_scancode(0xe1, 1); + handle_scancode(0x1d, down); + handle_scancode(0x45, down); + } else if (code >= 96) { + handle_scancode(0xe0, 1); + handle_scancode(keybdev_x86_e0s[code - 96], down); + if (code == 99) { + handle_scancode(0xe0, 1); + handle_scancode(0x37, down); + } + } else handle_scancode(code, down); + +#elif CONFIG_MAC_KEYBOARD + + if (keycode < 128) + handle_scancode(keybdev_mac_codes[code], down); + +#else +#error "Cannot generate rawmode keyboard for your architecture yet." +#endif + +} + +static int keybdev_connect(struct input_handler *handler, struct input_dev *dev) +{ + struct input_handle *handle; + + if (!test_bit(EV_KEY, dev->evbit) || !test_bit(KEY_A, dev->keybit) || !test_bit(KEY_Z, dev->keybit)) + return -1; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return -1; + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + + input_open_device(handle); + + printk("keybdev.c: Adding keyboard: input%d\n", dev->number); + + return 0; +} + +static void keybdev_disconnect(struct input_handle *handle) +{ + printk("keybdev.c: Removing keyboard: input%d\n", handle->dev->number); + + input_close_device(handle); + + kfree(handle); +} + +struct input_handler keybdev_handler = { + event: keybdev_event, + connect: keybdev_connect, + disconnect: keybdev_disconnect, +}; + +#ifdef MODULE +void cleanup_module(void) +{ + input_unregister_handler(&keybdev_handler); +} +int init_module(void) +#else +int __init keybdev_init(void) +#endif +{ + input_register_handler(&keybdev_handler); + return 0; +} diff -u --recursive --new-file v2.3.35/linux/drivers/usb/keyboard.c linux/drivers/usb/keyboard.c --- v2.3.35/linux/drivers/usb/keyboard.c Mon Dec 20 18:48:22 1999 +++ linux/drivers/usb/keyboard.c Wed Dec 31 16:00:00 1969 @@ -1,295 +0,0 @@ -/* - Fixes: - 1999/09/04 - Arnaldo Carvalho de Melo - Handle states in usb_kbd_irq - 1999/09/06 - Arnaldo Carvalho de Melo - rmmod usb-keyboard doesn't crash the system anymore: the irq - handlers are correctly released with usb_release_irq -*/ -#include -#include -#include -#include -#include -#include -#include - -#include -#include "usb.h" - -#define PCKBD_PRESSED 0x00 -#define PCKBD_RELEASED 0x80 -#define PCKBD_NEEDS_E0 0x80 - -#define USBKBD_MODIFIER_BASE 224 -#define USBKBD_KEYCODE_OFFSET 2 -#define USBKBD_KEYCODE_COUNT 6 - -#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3) -#define USBKBD_FIND_KEYCODE(down, key, count) \ - ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count))) - -#define USBKBD_REPEAT_DELAY (HZ / 4) -#define USBKBD_REPEAT_RATE (HZ / 20) - -struct usb_keyboard { - struct usb_device *dev; - unsigned long down[2]; - unsigned char repeat_key; - struct timer_list repeat_timer; - struct list_head list; - unsigned int irqpipe; - void *irq_handler; /* host controller's IRQ transfer handle */ -}; - -extern unsigned char usb_kbd_map[]; - -static void *usb_kbd_probe(struct usb_device *dev, unsigned int i); -static void usb_kbd_disconnect(struct usb_device *dev, void *ptr); -static void usb_kbd_repeat(unsigned long dummy); - -static LIST_HEAD(usb_kbd_list); - -static struct usb_driver usb_kbd_driver = { - "keyboard", - usb_kbd_probe, - usb_kbd_disconnect, - {NULL, NULL} -}; - - -static void usb_kbd_handle_key(unsigned char key, int down) -{ - int scancode = (int) usb_kbd_map[key]; - if (scancode) { -#ifndef CONFIG_MAC_KEYBOARD - if (scancode & PCKBD_NEEDS_E0) { - handle_scancode(0xe0, 1); - } -#endif /* CONFIG_MAC_KEYBOARD */ - handle_scancode((scancode & ~PCKBD_NEEDS_E0), down); - } -} - -static void usb_kbd_repeat(unsigned long dev_id) -{ - struct usb_keyboard *kbd = (struct usb_keyboard *) dev_id; - - unsigned long flags; - save_flags(flags); - cli(); - - if (kbd->repeat_key) { - usb_kbd_handle_key(kbd->repeat_key, 1); - - /* reset repeat timer */ - kbd->repeat_timer.function = usb_kbd_repeat; - kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE; - kbd->repeat_timer.data = (unsigned long) kbd; - kbd->repeat_timer.prev = NULL; - kbd->repeat_timer.next = NULL; - add_timer(&kbd->repeat_timer); - } - - restore_flags(flags); -} - -static int usb_kbd_irq(int state, void *buffer, int len, void *dev_id) -{ - struct usb_keyboard *kbd = (struct usb_keyboard *) dev_id; - unsigned long *down = (unsigned long *) buffer; - - /* - * USB_ST_NOERROR is the normal case. - * USB_ST_REMOVED occurs if keyboard disconnected - * On other states, ignore - */ - - switch (state) { - case USB_ST_REMOVED: - case USB_ST_INTERNALERROR: - printk(KERN_DEBUG "%s(%d): Suspending\n", __FILE__, - __LINE__); - return 0; /* disable */ - case USB_ST_NOERROR: - break; - default: - return 1; /* ignore */ - } - - if (kbd->down[0] != down[0] || kbd->down[1] != down[1]) { - unsigned char *olddown, *newdown; - unsigned char modsdelta, key; - int i; - - /* handle modifier change */ - modsdelta = - (*(unsigned char *) down ^ *(unsigned char *) kbd-> - down); - if (modsdelta) { - for (i = 0; i < 8; i++) { - if (modsdelta & 0x01) { - int pressed = - (*(unsigned char *) down >> i) - & 0x01; - usb_kbd_handle_key(i + - USBKBD_MODIFIER_BASE, - pressed); - } - modsdelta >>= 1; - } - } - - olddown = - (unsigned char *) kbd->down + USBKBD_KEYCODE_OFFSET; - newdown = (unsigned char *) down + USBKBD_KEYCODE_OFFSET; - - /* handle released keys */ - for (i = 0; i < USBKBD_KEYCODE_COUNT; i++) { - key = olddown[i]; - if (USBKBD_VALID_KEYCODE(key) - && !USBKBD_FIND_KEYCODE(newdown, key, - USBKBD_KEYCODE_COUNT)) - { - usb_kbd_handle_key(key, 0); - } - } - - /* handle pressed keys */ - kbd->repeat_key = 0; - for (i = 0; i < USBKBD_KEYCODE_COUNT; i++) { - key = newdown[i]; - if (USBKBD_VALID_KEYCODE(key) - && !USBKBD_FIND_KEYCODE(olddown, key, - USBKBD_KEYCODE_COUNT)) - { - usb_kbd_handle_key(key, 1); - kbd->repeat_key = key; - } - } - - /* set repeat timer if any keys were pressed */ - if (kbd->repeat_key) { - del_timer(&kbd->repeat_timer); - kbd->repeat_timer.function = usb_kbd_repeat; - kbd->repeat_timer.expires = - jiffies + USBKBD_REPEAT_DELAY; - kbd->repeat_timer.data = (unsigned long) kbd; - kbd->repeat_timer.prev = NULL; - kbd->repeat_timer.next = NULL; - add_timer(&kbd->repeat_timer); - } - - kbd->down[0] = down[0]; - kbd->down[1] = down[1]; - } - - return 1; -} - -static void *usb_kbd_probe(struct usb_device *dev, unsigned int i) -{ - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_keyboard *kbd; - int ret; - - interface = &dev->actconfig->interface[i].altsetting[0]; - endpoint = &interface->endpoint[0]; - - if (interface->bInterfaceClass != 3 - || interface->bInterfaceSubClass != 1 - || interface->bInterfaceProtocol != 1) { - return NULL; - } - - printk(KERN_INFO "USB HID boot protocol keyboard detected.\n"); - - kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL); - if (kbd) { - memset(kbd, 0, sizeof(*kbd)); - kbd->dev = dev; - - usb_set_protocol(dev, 0); - usb_set_idle(dev, 0, 0); - - kbd->irqpipe = - usb_rcvintpipe(dev, endpoint->bEndpointAddress); - ret = - usb_request_irq(dev, kbd->irqpipe, usb_kbd_irq, - endpoint->bInterval, kbd, - &kbd->irq_handler); - if (ret) { - printk(KERN_INFO - "usb-keyboard failed usb_request_irq (0x%x)\n", - ret); - goto probe_err; - } - - list_add(&kbd->list, &usb_kbd_list); - - return kbd; - } - -probe_err: - if (kbd) - kfree(kbd); - return NULL; -} - -static void usb_kbd_disconnect(struct usb_device *dev, void *ptr) -{ - struct usb_keyboard *kbd = (struct usb_keyboard *) ptr; - if (kbd) { - usb_release_irq(dev, kbd->irq_handler, kbd->irqpipe); - list_del(&kbd->list); - del_timer(&kbd->repeat_timer); - kfree(kbd); - } - - printk(KERN_INFO "USB HID boot protocol keyboard removed.\n"); -} - -int usb_kbd_init(void) -{ - return usb_register(&usb_kbd_driver); -} - -void usb_kbd_cleanup(void) -{ - struct list_head *cur, *head = &usb_kbd_list; - - cur = head->next; - - while (cur != head) { - struct usb_keyboard *kbd = - list_entry(cur, struct usb_keyboard, list); - - cur = cur->next; - - list_del(&kbd->list); - INIT_LIST_HEAD(&kbd->list); - - if (kbd->irq_handler) { - usb_release_irq(kbd->dev, kbd->irq_handler, - kbd->irqpipe); - /* never keep a reference to a released IRQ! */ - kbd->irq_handler = NULL; - } - } - - usb_deregister(&usb_kbd_driver); -} - -#ifdef MODULE -int init_module(void) -{ - return usb_kbd_init(); -} - -void cleanup_module(void) -{ - usb_kbd_cleanup(); -} - -#endif diff -u --recursive --new-file v2.3.35/linux/drivers/usb/keymap-mac.c linux/drivers/usb/keymap-mac.c --- v2.3.35/linux/drivers/usb/keymap-mac.c Tue Jun 8 10:52:26 1999 +++ linux/drivers/usb/keymap-mac.c Wed Dec 31 16:00:00 1969 @@ -1,50 +0,0 @@ -unsigned char usb_kbd_map[256] = -{ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x0b, 0x08, 0x02, - 0x0e, 0x03, 0x05, 0x04, 0x22, 0x26, 0x28, 0x25, - - 0x2e, 0x2d, 0x1f, 0x23, 0x0c, 0x0f, 0x01, 0x11, - 0x20, 0x09, 0x0d, 0x07, 0x10, 0x06, 0x12, 0x13, - - 0x14, 0x15, 0x17, 0x16, 0x1a, 0x1c, 0x19, 0x1d, - 0x24, 0x35, 0x33, 0x30, 0x31, 0x1b, 0x18, 0x21, - - 0x1e, 0x2a, 0x00, 0x29, 0x27, 0x32, 0x2b, 0x2f, - 0x2c, 0x39, 0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, - - 0x62, 0x64, 0x65, 0x6d, 0x67, 0x6f, 0x69, 0x6b, - 0x71, 0x72, 0x73, 0x74, 0x75, 0x77, 0x79, 0x3c, - - 0x3b, 0x3d, 0x3e, 0x47, 0x4b, 0x43, 0x4e, 0x45, - 0x4c, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - - 0x5b, 0x5c, 0x52, 0x41, 0x00, 0x00, 0x00, 0x00, - 0x69, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x38, 0x3a, 0x37, 0x7d, 0x7b, 0x7c, 0x37, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff -u --recursive --new-file v2.3.35/linux/drivers/usb/keymap.c linux/drivers/usb/keymap.c --- v2.3.35/linux/drivers/usb/keymap.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/keymap.c Wed Dec 31 16:00:00 1969 @@ -1,50 +0,0 @@ -unsigned char usb_kbd_map[256] = -{ - 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x2e, 0x20, - 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, - - 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, - 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, - - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, - - 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, - 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, - - 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, - 0x00, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, - - 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, - 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, - - 0x48, 0x49, 0x52, 0x53, 0x56, 0x6d, 0x00, 0x00, - 0xbd, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff -u --recursive --new-file v2.3.35/linux/drivers/usb/maps/fixup.map linux/drivers/usb/maps/fixup.map --- v2.3.35/linux/drivers/usb/maps/fixup.map Sat May 22 13:06:37 1999 +++ linux/drivers/usb/maps/fixup.map Wed Dec 31 16:00:00 1969 @@ -1,30 +0,0 @@ -# misc fixes -keycode 0 = Pause -keycode 29 = Control -keycode 42 = Shift -keycode 54 = Shift_R -keycode 109 = Application - -# E0 keys (or'ed with 0x80) -keycode 156 = KP_Enter -keycode 157 = Control_R -keycode 181 = KP_Divide -keycode 183 = Print_Screen -keycode 184 = Alt_R -keycode 189 = F13 -keycode 190 = F14 -keycode 193 = F17 -keycode 198 = Break -keycode 199 = Home -keycode 200 = Up -keycode 201 = Prior -keycode 203 = Left -keycode 205 = Right -keycode 207 = End -keycode 208 = Down -keycode 209 = Next -keycode 210 = Insert -keycode 211 = Remove -keycode 219 = Window -keycode 220 = Window_R -keycode 221 = Menu diff -u --recursive --new-file v2.3.35/linux/drivers/usb/maps/mac.map linux/drivers/usb/maps/mac.map --- v2.3.35/linux/drivers/usb/maps/mac.map Tue Jun 8 10:52:26 1999 +++ linux/drivers/usb/maps/mac.map Wed Dec 31 16:00:00 1969 @@ -1,350 +0,0 @@ -# Kernel keymap for Macintoshes. This uses 7 modifier combinations. -keymaps 0-2,4-5,8,12 -# -# Fixups: -keycode 0x69 = Print_Screen -keycode 0x6b = F14 -keycode 0x37 = Window_R -# -#keycode 0x00 = a -# hack! -keycode 0x80 = a - altgr keycode 0x00 = Hex_A -keycode 0x01 = s -keycode 0x02 = d - altgr keycode 0x02 = Hex_D -keycode 0x03 = f - altgr keycode 0x03 = Hex_F -keycode 0x04 = h -keycode 0x05 = g -keycode 0x06 = z -keycode 0x07 = x -keycode 0x08 = c - altgr keycode 0x08 = Hex_C -keycode 0x09 = v -keycode 0x0a = -keycode 0x0b = b - altgr keycode 0x0b = Hex_B -keycode 0x0c = q -keycode 0x0d = w -keycode 0x0e = e - altgr keycode 0x0e = Hex_E -keycode 0x0f = r -keycode 0x10 = y -keycode 0x11 = t -keycode 0x12 = one exclam - alt keycode 0x12 = Meta_one -keycode 0x13 = two at at - control keycode 0x13 = nul - shift control keycode 0x13 = nul - alt keycode 0x13 = Meta_two -keycode 0x14 = three numbersign - control keycode 0x14 = Escape - alt keycode 0x14 = Meta_three -keycode 0x15 = four dollar dollar - control keycode 0x15 = Control_backslash - alt keycode 0x15 = Meta_four -keycode 0x16 = six asciicircum - control keycode 0x16 = Control_asciicircum - alt keycode 0x16 = Meta_six -keycode 0x17 = five percent - control keycode 0x17 = Control_bracketright - alt keycode 0x17 = Meta_five -keycode 0x18 = equal plus - alt keycode 0x18 = Meta_equal -keycode 0x19 = nine parenleft bracketright - alt keycode 0x19 = Meta_nine -keycode 0x1a = seven ampersand braceleft - control keycode 0x1a = Control_underscore - alt keycode 0x1a = Meta_seven -keycode 0x1b = minus underscore backslash - control keycode 0x1b = Control_underscore - shift control keycode 0x1b = Control_underscore - alt keycode 0x1b = Meta_minus -keycode 0x1c = eight asterisk bracketleft - control keycode 0x1c = Delete - alt keycode 0x1c = Meta_eight -keycode 0x1d = zero parenright braceright - alt keycode 0x1d = Meta_zero -keycode 0x1e = bracketright braceright asciitilde - control keycode 0x1e = Control_bracketright - alt keycode 0x1e = Meta_bracketright -keycode 0x1f = o -keycode 0x20 = u -keycode 0x21 = bracketleft braceleft - control keycode 0x21 = Escape - alt keycode 0x21 = Meta_bracketleft -keycode 0x22 = i -keycode 0x23 = p -keycode 0x24 = Return - alt keycode 0x24 = Meta_Control_m -keycode 0x25 = l -keycode 0x26 = j -keycode 0x27 = apostrophe quotedbl - control keycode 0x27 = Control_g - alt keycode 0x27 = Meta_apostrophe -keycode 0x28 = k -keycode 0x29 = semicolon colon - alt keycode 0x29 = Meta_semicolon -keycode 0x2a = backslash bar - control keycode 0x2a = Control_backslash - alt keycode 0x2a = Meta_backslash -keycode 0x2b = comma less - alt keycode 0x2b = Meta_comma -keycode 0x2c = slash question - control keycode 0x2c = Delete - alt keycode 0x2c = Meta_slash -keycode 0x2d = n -keycode 0x2e = m -keycode 0x2f = period greater - control keycode 0x2f = Compose - alt keycode 0x2f = Meta_period -keycode 0x30 = Tab Tab - alt keycode 0x30 = Meta_Tab -keycode 0x31 = space space - control keycode 0x31 = nul - alt keycode 0x31 = Meta_space -keycode 0x32 = grave asciitilde - control keycode 0x32 = nul - alt keycode 0x32 = Meta_grave -keycode 0x33 = Delete Delete - control keycode 0x33 = BackSpace - alt keycode 0x33 = Meta_Delete -keycode 0x34 = -keycode 0x35 = Escape Escape - alt keycode 0x35 = Meta_Escape -keycode 0x36 = Control -keycode 0x37 = Window -keycode 0x38 = Shift -keycode 0x39 = Caps_Lock -keycode 0x3a = Alt -keycode 0x3b = Left - alt keycode 0x3b = Decr_Console -keycode 0x3c = Right - alt keycode 0x3c = Incr_Console -keycode 0x3d = Down -keycode 0x3e = Up -keycode 0x3f = -keycode 0x40 = -keycode 0x41 = KP_Period -keycode 0x42 = -keycode 0x43 = KP_Multiply -keycode 0x44 = -keycode 0x45 = KP_Add -keycode 0x46 = -keycode 0x47 = Num_Lock -# shift keycode 0x47 = Bare_Num_Lock -keycode 0x48 = -keycode 0x49 = -keycode 0x4a = -keycode 0x4b = KP_Divide -keycode 0x4c = KP_Enter -keycode 0x4d = -keycode 0x4e = KP_Subtract -keycode 0x4f = -keycode 0x50 = -keycode 0x51 = -#keycode 0x51 = KP_Equals -keycode 0x52 = KP_0 - alt keycode 0x52 = Ascii_0 - altgr keycode 0x52 = Hex_0 -keycode 0x53 = KP_1 - alt keycode 0x53 = Ascii_1 - altgr keycode 0x53 = Hex_1 -keycode 0x54 = KP_2 - alt keycode 0x54 = Ascii_2 - altgr keycode 0x54 = Hex_2 -keycode 0x55 = KP_3 - alt keycode 0x55 = Ascii_3 - altgr keycode 0x55 = Hex_3 -keycode 0x56 = KP_4 - alt keycode 0x56 = Ascii_4 - altgr keycode 0x56 = Hex_4 -keycode 0x57 = KP_5 - alt keycode 0x57 = Ascii_5 - altgr keycode 0x57 = Hex_5 -keycode 0x58 = KP_6 - alt keycode 0x58 = Ascii_6 - altgr keycode 0x58 = Hex_6 -keycode 0x59 = KP_7 - alt keycode 0x59 = Ascii_7 - altgr keycode 0x59 = Hex_7 -keycode 0x5b = KP_8 - alt keycode 0x5b = Ascii_8 - altgr keycode 0x5b = Hex_8 -keycode 0x5c = KP_9 - alt keycode 0x5c = Ascii_9 - altgr keycode 0x5c = Hex_9 -keycode 0x5d = -keycode 0x5e = -keycode 0x5f = -keycode 0x60 = F5 F15 Console_17 - control keycode 0x60 = F5 - alt keycode 0x60 = Console_5 - control alt keycode 0x60 = Console_5 -keycode 0x61 = F6 F16 Console_18 - control keycode 0x61 = F6 - alt keycode 0x61 = Console_6 - control alt keycode 0x61 = Console_6 -keycode 0x62 = F7 F17 Console_19 - control keycode 0x62 = F7 - alt keycode 0x62 = Console_7 - control alt keycode 0x62 = Console_7 -keycode 0x63 = F3 F13 Console_15 - control keycode 0x63 = F3 - alt keycode 0x63 = Console_3 - control alt keycode 0x63 = Console_3 -keycode 0x64 = F8 F18 Console_20 - control keycode 0x64 = F8 - alt keycode 0x64 = Console_8 - control alt keycode 0x64 = Console_8 -keycode 0x65 = F9 F19 Console_21 - control keycode 0x65 = F9 - alt keycode 0x65 = Console_9 - control alt keycode 0x65 = Console_9 -keycode 0x66 = -keycode 0x67 = F11 F11 Console_23 - control keycode 0x67 = F11 - alt keycode 0x67 = Console_11 - control alt keycode 0x67 = Console_11 -keycode 0x68 = -keycode 0x69 = F13 -keycode 0x6a = -keycode 0x6b = Scroll_Lock Show_Memory Show_Registers - control keycode 0x6b = Show_State - alt keycode 0x6b = Scroll_Lock -keycode 0x6c = -keycode 0x6d = F10 F20 Console_22 - control keycode 0x6d = F10 - alt keycode 0x6d = Console_10 - control alt keycode 0x6d = Console_10 -keycode 0x6e = -keycode 0x6f = F12 F12 Console_24 - control keycode 0x6f = F12 - alt keycode 0x6f = Console_12 - control alt keycode 0x6f = Console_12 -keycode 0x70 = -keycode 0x71 = Pause -keycode 0x72 = Insert -keycode 0x73 = Home -keycode 0x74 = Prior - shift keycode 0x74 = Scroll_Backward -keycode 0x75 = Remove -keycode 0x76 = F4 F14 Console_16 - control keycode 0x76 = F4 - alt keycode 0x76 = Console_4 - control alt keycode 0x76 = Console_4 -keycode 0x77 = End -keycode 0x78 = F2 F12 Console_14 - control keycode 0x78 = F2 - alt keycode 0x78 = Console_2 - control alt keycode 0x78 = Console_2 -keycode 0x79 = Next - shift keycode 0x79 = Scroll_Forward -keycode 0x7a = F1 F11 Console_13 - control keycode 0x7a = F1 - alt keycode 0x7a = Console_1 - control alt keycode 0x7a = Console_1 -keycode 0x7b = Shift_R -keycode 0x7c = Alt_R -keycode 0x7d = Control_R -keycode 0x7e = -keycode 0x7f = -#keycode 0x7f = Power - control shift keycode 0x7f = Boot -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff -u --recursive --new-file v2.3.35/linux/drivers/usb/maps/serial.map linux/drivers/usb/maps/serial.map --- v2.3.35/linux/drivers/usb/maps/serial.map Mon Apr 19 11:47:54 1999 +++ linux/drivers/usb/maps/serial.map Wed Dec 31 16:00:00 1969 @@ -1,370 +0,0 @@ -keymaps 0-2,4-6,8-9,12 -keycode 1 = Escape - alt keycode 1 = Meta_Escape - shift alt keycode 1 = Meta_Escape - control alt keycode 1 = Meta_Escape -keycode 2 = one exclam - alt keycode 2 = Meta_one - shift alt keycode 2 = Meta_exclam -keycode 3 = two at at nul nul - alt keycode 3 = Meta_two - shift alt keycode 3 = Meta_at - control alt keycode 3 = Meta_nul -keycode 4 = three numbersign - control keycode 4 = Escape - alt keycode 4 = Meta_three - shift alt keycode 4 = Meta_numbersign -keycode 5 = four dollar dollar Control_backslash - alt keycode 5 = Meta_four - shift alt keycode 5 = Meta_dollar - control alt keycode 5 = Meta_Control_backslash -keycode 6 = five percent - control keycode 6 = Control_bracketright - alt keycode 6 = Meta_five - shift alt keycode 6 = Meta_percent -keycode 7 = six asciicircum - control keycode 7 = Control_asciicircum - alt keycode 7 = Meta_six - shift alt keycode 7 = Meta_asciicircum -keycode 8 = seven ampersand braceleft Control_underscore - alt keycode 8 = Meta_seven - shift alt keycode 8 = Meta_ampersand - control alt keycode 8 = Meta_Control_underscore -keycode 9 = eight asterisk bracketleft Delete - alt keycode 9 = Meta_eight - shift alt keycode 9 = Meta_asterisk - control alt keycode 9 = Meta_Delete -keycode 10 = nine parenleft bracketright - alt keycode 10 = Meta_nine - shift alt keycode 10 = Meta_parenleft -keycode 11 = zero parenright braceright - alt keycode 11 = Meta_zero - shift alt keycode 11 = Meta_parenright -keycode 12 = minus underscore backslash Control_underscore Control_underscore - alt keycode 12 = Meta_minus - shift alt keycode 12 = Meta_underscore - control alt keycode 12 = Meta_Control_underscore -keycode 13 = equal plus - alt keycode 13 = Meta_equal - shift alt keycode 13 = Meta_plus -keycode 14 = Delete - alt keycode 14 = Meta_Delete - shift alt keycode 14 = Meta_Delete - control alt keycode 14 = Meta_Delete -keycode 15 = Tab - alt keycode 15 = Meta_Tab - shift alt keycode 15 = Meta_Tab - control alt keycode 15 = Meta_Tab -keycode 16 = q -keycode 17 = w -keycode 18 = e -keycode 19 = r -keycode 20 = t -keycode 21 = y -keycode 22 = u -keycode 23 = i -keycode 24 = o -keycode 25 = p -keycode 26 = bracketleft braceleft - control keycode 26 = Escape - alt keycode 26 = Meta_bracketleft - shift alt keycode 26 = Meta_braceleft -keycode 27 = bracketright braceright asciitilde Control_bracketright - alt keycode 27 = Meta_bracketright - shift alt keycode 27 = Meta_braceright - control alt keycode 27 = Meta_Control_bracketright -keycode 28 = Return - alt keycode 28 = Meta_Control_m -keycode 29 = Control -keycode 30 = a -keycode 31 = s -keycode 32 = d -keycode 33 = f -keycode 34 = g -keycode 35 = h -keycode 36 = j -keycode 37 = k -keycode 38 = l -keycode 39 = semicolon colon - alt keycode 39 = Meta_semicolon - shift alt keycode 39 = Meta_colon -keycode 40 = apostrophe quotedbl - control keycode 40 = Control_g - alt keycode 40 = Meta_apostrophe - shift alt keycode 40 = Meta_quotedbl -keycode 41 = grave asciitilde - control keycode 41 = nul - alt keycode 41 = Meta_grave - shift alt keycode 41 = Meta_asciitilde -keycode 42 = Shift -keycode 43 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash - shift alt keycode 43 = Meta_bar -keycode 44 = z -keycode 45 = x -keycode 46 = c -keycode 47 = v -keycode 48 = b -keycode 49 = n -keycode 50 = m -keycode 51 = comma less - alt keycode 51 = Meta_comma - shift alt keycode 51 = Meta_less -keycode 52 = period greater - alt keycode 52 = Meta_period - shift alt keycode 52 = Meta_greater -keycode 53 = slash question - control keycode 53 = Delete - alt keycode 53 = Meta_slash - shift alt keycode 53 = Meta_question -keycode 54 = Shift -keycode 55 = KP_Multiply - altgr keycode 55 = Hex_C -keycode 56 = Alt -keycode 57 = space - control keycode 57 = nul - alt keycode 57 = Meta_space - shift alt keycode 57 = Meta_space - control alt keycode 57 = Meta_nul -keycode 58 = Caps_Lock -keycode 59 = F1 F13 Console_13 F25 - alt keycode 59 = Console_1 - control alt keycode 59 = Console_1 -keycode 60 = F2 F14 Console_14 F26 - alt keycode 60 = Console_2 - control alt keycode 60 = Console_2 -keycode 61 = F3 F15 Console_15 F27 - alt keycode 61 = Console_3 - control alt keycode 61 = Console_3 -keycode 62 = F4 F16 Console_16 F28 - alt keycode 62 = Console_4 - control alt keycode 62 = Console_4 -keycode 63 = F5 F17 Console_17 F29 - alt keycode 63 = Console_5 - control alt keycode 63 = Console_5 -keycode 64 = F6 F18 Console_18 F30 - alt keycode 64 = Console_6 - control alt keycode 64 = Console_6 -keycode 65 = F7 F19 Console_19 F31 - alt keycode 65 = Console_7 - control alt keycode 65 = Console_7 -keycode 66 = F8 F20 Console_20 F32 - alt keycode 66 = Console_8 - control alt keycode 66 = Console_8 -keycode 67 = F9 F21 Console_21 F33 - alt keycode 67 = Console_9 - control alt keycode 67 = Console_9 -keycode 68 = F10 F22 Console_22 F34 - alt keycode 68 = Console_10 - control alt keycode 68 = Console_10 -keycode 69 = Num_Lock - altgr keycode 69 = Hex_E -keycode 70 = Scroll_Lock Show_Memory Show_Registers Show_State - alt keycode 70 = Scroll_Lock -keycode 71 = KP_7 - altgr keycode 71 = Hex_7 - alt keycode 71 = Ascii_7 -keycode 72 = KP_8 - altgr keycode 72 = Hex_8 - alt keycode 72 = Ascii_8 -keycode 73 = KP_9 - altgr keycode 73 = Hex_9 - alt keycode 73 = Ascii_9 -keycode 74 = KP_Subtract -keycode 75 = KP_4 - altgr keycode 75 = Hex_4 - alt keycode 75 = Ascii_4 -keycode 76 = KP_5 - altgr keycode 76 = Hex_5 - alt keycode 76 = Ascii_5 -keycode 77 = KP_6 - altgr keycode 77 = Hex_6 - alt keycode 77 = Ascii_6 -keycode 78 = KP_Add -keycode 79 = KP_1 - altgr keycode 79 = Hex_1 - alt keycode 79 = Ascii_1 -keycode 80 = KP_2 - altgr keycode 80 = Hex_2 - alt keycode 80 = Ascii_2 -keycode 81 = KP_3 - altgr keycode 81 = Hex_3 - alt keycode 81 = Ascii_3 -keycode 82 = KP_0 - altgr keycode 82 = Hex_0 - alt keycode 82 = Ascii_0 -keycode 83 = KP_Period - altgr control keycode 83 = Boot - control alt keycode 83 = Boot -keycode 84 = Last_Console -keycode 85 = -keycode 86 = less greater bar - alt keycode 86 = Meta_less - shift alt keycode 86 = Meta_greater -keycode 87 = F11 F23 Console_23 F35 - alt keycode 87 = Console_11 - control alt keycode 87 = Console_11 -keycode 88 = F12 F24 Console_24 F36 - alt keycode 88 = Console_12 - control alt keycode 88 = Console_12 -keycode 89 = -keycode 90 = -keycode 91 = -keycode 92 = -keycode 93 = -keycode 94 = -keycode 95 = -keycode 96 = KP_Enter -keycode 97 = Control -keycode 98 = KP_Divide - altgr keycode 98 = Hex_B -keycode 99 = Control_backslash - alt keycode 99 = Meta_Control_backslash - shift alt keycode 99 = Meta_Control_backslash - control alt keycode 99 = Meta_Control_backslash -keycode 100 = AltGr -keycode 101 = Break -keycode 102 = Find -keycode 103 = Up - alt keycode 103 = KeyboardSignal -keycode 104 = Prior - shift keycode 104 = Scroll_Backward -keycode 105 = Left - alt keycode 105 = Decr_Console -keycode 106 = Right - alt keycode 106 = Incr_Console -keycode 107 = Select -keycode 108 = Down -keycode 109 = Next - shift keycode 109 = Scroll_Forward -keycode 110 = Insert -keycode 111 = Remove - altgr control keycode 111 = Boot - control alt keycode 111 = Boot -keycode 112 = Macro - altgr control keycode 112 = VoidSymbol - shift alt keycode 112 = VoidSymbol -keycode 113 = F13 - altgr control keycode 113 = VoidSymbol - shift alt keycode 113 = VoidSymbol -keycode 114 = F14 - altgr control keycode 114 = VoidSymbol - shift alt keycode 114 = VoidSymbol -keycode 115 = Help - altgr control keycode 115 = VoidSymbol - shift alt keycode 115 = VoidSymbol -keycode 116 = Do - altgr control keycode 116 = VoidSymbol - shift alt keycode 116 = VoidSymbol -keycode 117 = F17 - altgr control keycode 117 = VoidSymbol - shift alt keycode 117 = VoidSymbol -keycode 118 = KP_MinPlus - altgr control keycode 118 = VoidSymbol - shift alt keycode 118 = VoidSymbol -keycode 119 = Pause -keycode 120 = -keycode 121 = -keycode 122 = -keycode 123 = -keycode 124 = -keycode 125 = -keycode 126 = -keycode 127 = -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff -u --recursive --new-file v2.3.35/linux/drivers/usb/maps/usb.map linux/drivers/usb/maps/usb.map --- v2.3.35/linux/drivers/usb/maps/usb.map Sat Oct 9 11:47:50 1999 +++ linux/drivers/usb/maps/usb.map Wed Dec 31 16:00:00 1969 @@ -1,233 +0,0 @@ -# USB kernel keymap. -keymaps 0-2,4-5,8,12 - -keycode 4 = a - altgr keycode 30 = Hex_A -keycode 5 = b - altgr keycode 48 = Hex_B -keycode 6 = c - altgr keycode 46 = Hex_C -keycode 7 = d - altgr keycode 32 = Hex_D -keycode 8 = e - altgr keycode 18 = Hex_E -keycode 9 = f - altgr keycode 33 = Hex_F -keycode 10 = g -keycode 11 = h -keycode 12 = i -keycode 13 = j -keycode 14 = k -keycode 15 = l -keycode 16 = m -keycode 17 = n -keycode 18 = o -keycode 19 = p -keycode 20 = q -keycode 21 = r -keycode 22 = s -keycode 23 = t -keycode 24 = u -keycode 25 = v -keycode 26 = w -keycode 27 = x -keycode 28 = y -keycode 29 = z -keycode 30 = one exclam - alt keycode 2 = Meta_one -keycode 31 = two at - control keycode 3 = nul - shift control keycode 3 = nul - alt keycode 3 = Meta_two -keycode 32 = three numbersign - control keycode 4 = Escape - alt keycode 4 = Meta_three -keycode 33 = four dollar - control keycode 5 = Control_backslash - alt keycode 5 = Meta_four -keycode 34 = five percent - control keycode 6 = Control_bracketright - alt keycode 6 = Meta_five -keycode 35 = six asciicircum - control keycode 7 = Control_asciicircum - alt keycode 7 = Meta_six -keycode 36 = seven ampersand - control keycode 8 = Control_underscore - alt keycode 8 = Meta_seven -keycode 37 = eight asterisk - control keycode 9 = Delete - alt keycode 9 = Meta_eight -keycode 38 = nine parenleft - alt keycode 10 = Meta_nine -keycode 39 = zero parenright - alt keycode 11 = Meta_zero -keycode 40 = Return - alt keycode 28 = Meta_Control_m -keycode 41 = Escape Escape - alt keycode 1 = Meta_Escape -keycode 42 = Delete Delete - control keycode 14 = BackSpace - alt keycode 14 = Meta_Delete -keycode 43 = Tab Tab - alt keycode 15 = Meta_Tab -keycode 44 = space space - control keycode 57 = nul - alt keycode 57 = Meta_space -keycode 45 = minus underscore backslash - control keycode 12 = Control_underscore - shift control keycode 12 = Control_underscore - alt keycode 12 = Meta_minus -keycode 46 = equal plus - alt keycode 13 = Meta_equal -keycode 47 = bracketleft braceleft - control keycode 26 = Escape - alt keycode 26 = Meta_bracketleft -keycode 48 = bracketright braceright asciitilde - control keycode 27 = Control_bracketright - alt keycode 27 = Meta_bracketright -keycode 49 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 50 = -keycode 51 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 52 = apostrophe quotedbl - control keycode 40 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 53 = grave asciitilde - control keycode 41 = nul - alt keycode 41 = Meta_grave -keycode 54 = comma less - alt keycode 51 = Meta_comma -keycode 55 = period greater - control keycode 52 = Compose - alt keycode 52 = Meta_period -keycode 56 = slash question - control keycode 53 = Delete - alt keycode 53 = Meta_slash -keycode 57 = Caps_Lock -keycode 58 = F1 F11 Console_13 - control keycode 59 = F1 - alt keycode 59 = Console_1 - control alt keycode 59 = Console_1 -keycode 59 = F2 F12 Console_14 - control keycode 60 = F2 - alt keycode 60 = Console_2 - control alt keycode 60 = Console_2 -keycode 60 = F3 F13 Console_15 - control keycode 61 = F3 - alt keycode 61 = Console_3 - control alt keycode 61 = Console_3 -keycode 61 = F4 F14 Console_16 - control keycode 62 = F4 - alt keycode 62 = Console_4 - control alt keycode 62 = Console_4 -keycode 62 = F5 F15 Console_17 - control keycode 63 = F5 - alt keycode 63 = Console_5 - control alt keycode 63 = Console_5 -keycode 63 = F6 F16 Console_18 - control keycode 64 = F6 - alt keycode 64 = Console_6 - control alt keycode 64 = Console_6 -keycode 64 = F7 F17 Console_19 - control keycode 65 = F7 - alt keycode 65 = Console_7 - control alt keycode 65 = Console_7 -keycode 65 = F8 F18 Console_20 - control keycode 66 = F8 - alt keycode 66 = Console_8 - control alt keycode 66 = Console_8 -keycode 66 = F9 F19 Console_21 - control keycode 67 = F9 - alt keycode 67 = Console_9 - control alt keycode 67 = Console_9 -keycode 67 = F10 F20 Console_22 - control keycode 68 = F10 - alt keycode 68 = Console_10 - control alt keycode 68 = Console_10 -keycode 68 = F11 F11 Console_23 - control keycode 87 = F11 - alt keycode 87 = Console_11 - control alt keycode 87 = Console_11 -keycode 69 = F12 F12 Console_24 - control keycode 88 = F12 - alt keycode 88 = Console_12 - control alt keycode 88 = Console_12 -keycode 70 = Print_Screen -keycode 71 = Scroll_Lock Show_Memory Show_Registers - control keycode 70 = Show_State - alt keycode 70 = Scroll_Lock -keycode 72 = Pause -keycode 73 = Insert -keycode 74 = Home -keycode 75 = Prior - shift keycode 104 = Scroll_Backward -keycode 76 = Remove -# altgr control keycode 111 = Boot - control alt keycode 111 = Boot -keycode 77 = End -keycode 78 = Next - shift keycode 109 = Scroll_Forward -keycode 79 = Right - alt keycode 106 = Incr_Console -keycode 80 = Left - alt keycode 105 = Decr_Console -keycode 81 = Down -keycode 82 = Up -keycode 83 = Num_Lock - shift keycode 69 = Bare_Num_Lock -keycode 84 = KP_Divide -keycode 85 = KP_Multiply -keycode 86 = KP_Subtract -keycode 87 = KP_Add -keycode 88 = KP_Enter -keycode 89 = KP_1 - alt keycode 79 = Ascii_1 - altgr keycode 79 = Hex_1 -keycode 90 = KP_2 - alt keycode 80 = Ascii_2 - altgr keycode 80 = Hex_2 -keycode 91 = KP_3 - alt keycode 81 = Ascii_3 - altgr keycode 81 = Hex_3 -keycode 92 = KP_4 - alt keycode 75 = Ascii_4 - altgr keycode 75 = Hex_4 -keycode 93 = KP_5 - alt keycode 76 = Ascii_5 - altgr keycode 76 = Hex_5 -keycode 94 = KP_6 - alt keycode 77 = Ascii_6 - altgr keycode 77 = Hex_6 -keycode 95 = KP_7 - alt keycode 71 = Ascii_7 - altgr keycode 71 = Hex_7 -keycode 96 = KP_8 - alt keycode 72 = Ascii_8 - altgr keycode 72 = Hex_8 -keycode 97 = KP_9 - alt keycode 73 = Ascii_9 - altgr keycode 73 = Hex_9 -keycode 98 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 99 = KP_Period -# altgr control keycode 83 = Boot - control alt keycode 83 = Boot -keycode 100 = -keycode 101 = Application -keycode 102 = -keycode 103 = -keycode 104 = F13 -keycode 105 = F14 - -# modifiers -keycode 224 = Control -keycode 225 = Shift -keycode 226 = Alt -keycode 227 = Window -keycode 228 = Control_R -keycode 229 = Shift_R -keycode 230 = Alt_R -keycode 231 = Window_R diff -u --recursive --new-file v2.3.35/linux/drivers/usb/mkmap linux/drivers/usb/mkmap --- v2.3.35/linux/drivers/usb/mkmap Mon Apr 19 11:53:27 1999 +++ linux/drivers/usb/mkmap Wed Dec 31 16:00:00 1969 @@ -1,83 +0,0 @@ -#!/usr/bin/perl - -($ME = $0) =~ s|.*/||; - -$file = "maps/serial.map"; -$line = 1; -open(PC, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*(\S+)/) - { - my($idx) = int($1); - my($sym) = $2; - if(defined($map{uc($sym)})) - { - # print STDERR "$file:$line: warning: `$sym' redefined\n"; - } - $map{uc($sym)} = $idx; - } - $line++; -} -close(PC); - -$file = "maps/fixup.map"; -$line = 1; -open(FIXUP, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*/) - { - my($idx) = int($1); - for $sym (split(/\s+/, $')) - { - $map{uc($sym)} = $idx; - } - } - $line++; -} -close(FIXUP); - -$file = "maps/usb.map"; -$line = 1; -open(USB, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*/) - { - my($idx) = int($1); - for $sym (split(/\s+/, $')) - { - my($val) = $map{uc($sym)}; - $map[$idx] = $val; - if(!defined($val)) - { - print STDERR "$file:$line: warning: `$sym' undefined\n"; - } - else - { - last; - } - } - } - $line++; -} -close(USB); - -print "unsigned char usb_kbd_map[256] = \n{\n"; -for($x = 0; $x < 32; $x++) -{ - if($x && !($x % 2)) - { - print "\n"; - } - print " "; - for($y = 0; $y < 8; $y++) - { - my($idx) = $x * 8 + $y; - print sprintf(" 0x%02x,", - int(defined($map[$idx]) ? $map[$idx]:0)); - } - print "\n"; -} -print "};\n"; diff -u --recursive --new-file v2.3.35/linux/drivers/usb/mkmap.adb linux/drivers/usb/mkmap.adb --- v2.3.35/linux/drivers/usb/mkmap.adb Tue Jun 8 10:52:26 1999 +++ linux/drivers/usb/mkmap.adb Wed Dec 31 16:00:00 1969 @@ -1,88 +0,0 @@ -#!/usr/bin/perl - -($ME = $0) =~ s|.*/||; - -$file = "maps/mac.map"; -$line = 1; -open(PC, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+|0x[0-9a-fA-F]+)\s*=\s*(\S+)/) - { - my($idx) = $1; - my($sym) = $2; - if ($idx =~ "0x.*") { - $idx = hex($idx); - } else { - $idx = int($idx); - } - if(defined($map{uc($sym)})) - { - # print STDERR "$file:$line: warning: `$sym' redefined\n"; - } - $map{uc($sym)} = $idx; - } - $line++; -} -close(PC); - -# $file = "maps/fixup.map"; -# $line = 1; -# open(FIXUP, $file) || die("$!"); -# while() -# { -# if(/^\s*keycode\s+(\d+)\s*=\s*/) -# { -# my($idx) = int($1); -# for $sym (split(/\s+/, $')) -# { -# $map{uc($sym)} = $idx; -# } -# } -# $line++; -# } -# close(FIXUP); - -$file = "maps/usb.map"; -$line = 1; -open(USB, $file) || die("$!"); -while() -{ - if(/^\s*keycode\s+(\d+)\s*=\s*/) - { - my($idx) = int($1); - for $sym (split(/\s+/, $')) - { - my($val) = $map{uc($sym)}; - $map[$idx] = $val; - if(!defined($val)) - { - print STDERR "$file:$line: warning: `$sym' undefined\n"; - } - else - { - last; - } - } - } - $line++; -} -close(USB); - -print "unsigned char usb_kbd_map[256] = \n{\n"; -for($x = 0; $x < 32; $x++) -{ - if($x && !($x % 2)) - { - print "\n"; - } - print " "; - for($y = 0; $y < 8; $y++) - { - my($idx) = $x * 8 + $y; - print sprintf(" 0x%02x,", - int(defined($map[$idx]) ? $map[$idx]:0)); - } - print "\n"; -} -print "};\n"; diff -u --recursive --new-file v2.3.35/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c --- v2.3.35/linux/drivers/usb/mouse.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/mouse.c Wed Dec 31 16:00:00 1969 @@ -1,498 +0,0 @@ -/* - * USB HID boot protocol mouse support based on MS BusMouse driver, psaux - * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus. - * - * Brad Keryan 4/3/1999 - * - * version 0.? Georg Acher 1999/10/30 - * URBification for UHCI-Acher/Fliegl/Sailer - * - * version 0.30? Paul Ashton 1999/08/19 - Fixed behaviour on mouse - * disconnect and suspend/resume. Added module parameter "force=1" - * to allow opening of the mouse driver before mouse has been plugged - * in (enables consistent XF86Config settings). Fixed module use count. - * Documented missing blocking/non-blocking read handling (not fixed). - * - * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it - * correctly. Events are added together, not queued, to keep the rodent sober. - * - * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events. - * This is wrong: when an application (like X or gpm) reads the mouse device, - * it wants to find out the mouse's current position, not its recent history. - * The button thing turned out to be UHCI not flipping data toggle, so half the - * packets were thrown out. - * - * version 0.01: Switched over to busmouse protocol, and changed the minor - * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now, - * but it still doesn't generate button events unless you move the mouse. - * - * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I - * know that's not very nice). Moving in the X and Y axes works. Buttons don't - * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease - * combos when you hold down a button and drag the mouse around. Probably has - * some additional bugs on an SMP machine. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include - -#include "usb.h" - -#define MODSTR "mouse.c: " - - -struct mouse_state { - unsigned char buttons; /* current button state */ - long dx; /* dx, dy, dz are change since last read */ - long dy; - long dz; - int present; /* this mouse is plugged in */ - int active; /* someone is has this mouse's device open */ - int ready; /* the mouse has changed state since the last read */ - int suspended; /* mouse disconnected */ - wait_queue_head_t wait; /* for polling */ - struct fasync_struct *fasync; - /* later, add a list here to support multiple mice */ - /* but we will also need a list of file pointers to identify it */ - - /* FIXME: move these to a per-mouse structure */ - struct usb_device *dev; /* host controller this mouse is on */ - void* irq_handle; /* host controller's IRQ transfer handle */ - char* buffer; - urb_t* urb; - __u8 bEndpointAddress; /* these are from the endpoint descriptor */ - __u8 bInterval; /* ... used when calling usb_request_irq */ -}; - -static struct mouse_state static_mouse_state; - -spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED; - -static int force=0; /* allow the USB mouse to be opened even if not there (yet) */ -MODULE_PARM(force,"i"); -int xxx=0; - -//static int mouse_irq(int state, void *__buffer, int len, void *dev_id) -static void mouse_irq(urb_t *urb) -{ - signed char *data = urb->transfer_buffer; - int state=urb->status; - int len=urb->actual_length; - /* finding the mouse is easy when there's only one */ - struct mouse_state *mouse = urb->context; - - if (state) - printk(KERN_DEBUG "%s(%d):state %d, bp %p, len %d\n", - __FILE__, __LINE__, state, data, len); - //printk("mouseirq: %i\n",xxx++); - /* - * USB_ST_NOERROR is the normal case. - * USB_ST_REMOVED occurs if mouse disconnected or suspend/resume - * USB_ST_INTERNALERROR occurs if system suspended then mouse removed - * followed by resume. On UHCI could then occur every second - * In both cases, suspend the mouse - * On other states, ignore - */ - switch (state) { - case USB_ST_REMOVED: - case USB_ST_INTERNALERROR: - printk(KERN_DEBUG "%s(%d): Suspending\n", - __FILE__, __LINE__); - mouse->suspended = 1; - // FIXME stop interrupt! - return; - case USB_ST_NOERROR: break; - default: - return; /* ignore */ - } - - /* if a mouse moves with no one listening, do we care? no */ - if(!mouse->active) - return; - - /* if the USB mouse sends an interrupt, then something noteworthy - must have happened */ - - mouse->buttons = data[0] & 0x0f; - mouse->dx += data[1]; /* data[] is signed, so this works */ - mouse->dy -= data[2]; /* y-axis is reversed */ - mouse->dz -= data[3]; - mouse->ready = 1; - - add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + - (mouse->dy << 8) + mouse->dx); - - wake_up_interruptible(&mouse->wait); - if (mouse->fasync) -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,20) - kill_fasync(mouse->fasync, SIGIO, POLL_IN); -#else - kill_fasync(mouse->fasync, SIGIO); -#endif - return; -} - -static int fasync_mouse(int fd, struct file *filp, int on) -{ - int retval; - struct mouse_state *mouse = &static_mouse_state; - - retval = fasync_helper(fd, filp, on, &mouse->fasync); - if (retval < 0) - return retval; - return 0; -} - -static int release_mouse(struct inode * inode, struct file * file) -{ - struct mouse_state *mouse = &static_mouse_state; - - fasync_mouse(-1, file, 0); - - printk(KERN_DEBUG "%s(%d): MOD_DEC\n", __FILE__, __LINE__); - MOD_DEC_USE_COUNT; - - if (--mouse->active == 0) { - mouse->suspended = 0; - /* stop polling the mouse while its not in use */ - usb_unlink_urb(mouse->urb); - } - - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - struct mouse_state *mouse = &static_mouse_state; - int ret; - unsigned int pipe; - - printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__); - /* - * First open may fail since mouse_probe() may get called after this - * if module load is in response to the open - * mouse_probe() sets mouse->present. This open can be delayed by - * specifying force=1 in module load - * This helps if you want to insert the USB mouse after starting X - */ - if (!mouse->present) - { - if (force) /* always load the driver even if no mouse (yet) */ - { - printk(KERN_DEBUG "%s(%d): forced open\n", - __FILE__, __LINE__); - mouse->suspended = 1; - } - else - return -EINVAL; - } - - /* prevent the driver from being unloaded while its in use */ - printk(KERN_DEBUG "%s(%d): MOD_INC\n", __FILE__, __LINE__); - /* Increment use count even if already active */ - MOD_INC_USE_COUNT; - - if (mouse->active++) - return 0; - /* flush state */ - mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0; - - if (!mouse->present) /* only get here if force == 1 */ - return 0; - - /* start the usb controller's polling of the mouse */ - pipe = usb_rcvintpipe(mouse->dev, mouse->bEndpointAddress); - FILL_INT_URB(mouse->urb,mouse->dev,pipe, - mouse->buffer, - usb_maxpacket(mouse->urb->dev, pipe, usb_pipeout(pipe)), - mouse_irq,mouse,mouse->bInterval); - - ret=usb_submit_urb(mouse->urb); - - // ret = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), - // mouse_irq, mouse->bInterval, - // NULL, &mouse->irq_handle); - if (ret) { - printk (KERN_WARNING "usb-mouse: usb_submit_urb(INT) failed (0x%x)\n", ret); - MOD_DEC_USE_COUNT; - return ret; - } - return 0; -} - -static ssize_t write_mouse(struct file * file, - const char * buffer, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -/* - * Look like a PS/2 mouse, please.. - * In XFree86 (3.3.5 tested) you must select Protocol "NetMousePS/2", - * then use your wheel as Button 4 and 5 via ZAxisMapping 4 5. - * The PS/2 protocol is fairly strange, but - * oh, well, it's at least common.. - */ -static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - int retval = 0; - static int state = 0; - struct mouse_state *mouse = &static_mouse_state; - - if (!mouse->present) - return 0; - - if (!mouse->ready) { - if (file->f_flags & O_NONBLOCK) return -EAGAIN; - - add_wait_queue(&mouse->wait, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (!mouse->ready && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&mouse->wait, &wait); - } - if (signal_pending(current)) return -ERESTARTSYS; - - if (!mouse->present) - return 0; - if (count) { - mouse->ready = 0; - switch (state) { - case 0: { /* buttons and sign */ - int buttons = mouse->buttons; - mouse->buttons = 0; - if (mouse->dx < 0) - buttons |= 0x10; - if (mouse->dy < 0) - buttons |= 0x20; - put_user(buttons, buffer); - buffer++; - retval++; - state = 1; - if (!--count) - break; - } - case 1: { /* dx */ - int dx = mouse->dx; - mouse->dx = 0; - put_user(dx, buffer); - buffer++; - retval++; - state = 2; - if (!--count) - break; - } - case 2: { /* dy */ - int dy = mouse->dy; - mouse->dy = 0; - put_user(dy, buffer); - buffer++; - retval++; - state = 0; - if (!--count) - break; - } - - /* - * SUBTLE: - * - * The only way to get here is to do a read() of - * more than 3 bytes: if you read a byte at a time - * you will just ever see states 0-2, for backwards - * compatibility. - * - * So you can think of this as a packet interface, - * where you have arbitrary-sized packets, and you - * only ever see the first three bytes when you read - * them in small chunks. - */ - { /* fallthrough - dz */ - int dz = mouse->dz; - mouse->dz = 0; - put_user(dz, buffer); - buffer++; - retval++; - state = 0; - } - break; - } - } - return retval; -} - -static unsigned int mouse_poll(struct file *file, poll_table * wait) -{ - struct mouse_state *mouse = &static_mouse_state; - - poll_wait(file, &mouse->wait, wait); - if (mouse->ready) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations usb_mouse_fops = { - NULL, /* mouse_seek */ - read_mouse, - write_mouse, - NULL, /* mouse_readdir */ - mouse_poll, /* mouse_poll */ - NULL, /* mouse_ioctl */ - NULL, /* mouse_mmap */ - open_mouse, - NULL, /* flush */ - release_mouse, - NULL, - fasync_mouse, -}; - - void* mouse_probe(struct usb_device *dev,unsigned int ifnum) -{ - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - struct mouse_state *mouse = &static_mouse_state; - int ret; - unsigned int pipe; - - printk("mouse probe for if %i\n",ifnum); - /* Is it a mouse interface? */ - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - if (interface->bInterfaceClass != 3) - return NULL; - if (interface->bInterfaceSubClass != 1) - return NULL; - if (interface->bInterfaceProtocol != 2) - return NULL; - - /* Multiple endpoints? What kind of mutant ninja-mouse is this? */ - if (interface->bNumEndpoints != 1) - return NULL; - - endpoint = &interface->endpoint[0]; - - /* Output endpoint? Curiousier and curiousier.. */ - if (!(endpoint->bEndpointAddress & 0x80)) - return NULL; - - /* If it's not an interrupt endpoint, we'd better punt! */ - if ((endpoint->bmAttributes & 3) != 3) - return NULL; - - printk("USB mouse found\n"); - - /* these are used to request the irq when the mouse is opened */ - mouse->dev = dev; - mouse->bEndpointAddress = endpoint->bEndpointAddress; - mouse->bInterval = endpoint->bInterval; - - mouse->present = 1; - - /* This appears to let USB mouse survive disconnection and */ - /* APM suspend/resume */ - if (mouse->suspended) - { - printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__); - /* restart the usb controller's polling of the mouse */ - - pipe = usb_rcvintpipe(mouse->dev, mouse->bEndpointAddress); - FILL_INT_URB(mouse->urb,mouse->dev,pipe, - mouse->buffer, - usb_maxpacket(mouse->urb->dev, pipe, usb_pipeout(pipe)), - mouse_irq,mouse,mouse->bInterval); - - ret=usb_submit_urb(mouse->urb); - if (ret) { - printk (KERN_WARNING "usb-mouse: usb_submit_urb(INT) failed (0x%x)\n", ret); - return NULL; - } - mouse->suspended = 0; - } - - printk("mouse probe2\n"); - return mouse; -} - -static void mouse_disconnect(struct usb_device *dev, void *priv) -{ - struct mouse_state *mouse = priv; - - /* stop the usb interrupt transfer */ - if (mouse->present) { - usb_unlink_urb(mouse->urb); - wake_up(&mouse->wait); - } - - /* this might need work */ - mouse->present = 0; - printk("Mouse disconnected\n"); -} - -static struct usb_driver mouse_driver = { - "mouse", - mouse_probe, - mouse_disconnect, - { NULL, NULL }, - &usb_mouse_fops, - 16 -}; - -int usb_mouse_init(void) -{ - struct mouse_state *mouse = &static_mouse_state; - - mouse->present = mouse->active = mouse->suspended = 0; - mouse->buffer=kmalloc(64,GFP_KERNEL); - - if (!mouse->buffer) - return -ENOMEM; - mouse->urb=usb_alloc_urb(0); - if (!mouse->urb) - printk(KERN_DEBUG MODSTR"URB allocation failed\n"); - - init_waitqueue_head(&mouse->wait); - mouse->fasync = NULL; - - if (usb_register(&mouse_driver)<0) - return -1; - - printk(KERN_INFO "USB HID boot protocol mouse driver registered.\n"); - return 0; -} - -void usb_mouse_cleanup(void) -{ - struct mouse_state *mouse = &static_mouse_state; - - /* stop the usb interrupt transfer */ - if (mouse->present) { - usb_unlink_urb(mouse->urb); - } - kfree(mouse->urb); - kfree(mouse->buffer); - /* this, too, probably needs work */ - usb_deregister(&mouse_driver); -} - -#ifdef MODULE -int init_module(void) -{ - return usb_mouse_init(); -} - -void cleanup_module(void) -{ - usb_mouse_cleanup(); -} -#endif diff -u --recursive --new-file v2.3.35/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c --- v2.3.35/linux/drivers/usb/mousedev.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/mousedev.c Sun Jan 2 12:12:59 2000 @@ -0,0 +1,457 @@ +/* + * mousedev.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Input driver to PS/2 or ImPS/2 device driver module. + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#define MOUSEDEV_MINOR_BASE 32 + +#include +#include +#include +#include +#include +#include +#include + +struct mousedev { + char name[32]; + int used; + struct input_handle handle; + struct miscdevice misc; + wait_queue_head_t wait; + struct mousedev_list *list; +}; + +struct mousedev_list { + struct fasync_struct *fasync; + struct mousedev *mousedev; + struct mousedev_list *next; + int dx, dy, dz; + unsigned char ps2[6]; + unsigned char buttons; + unsigned char ready, buffer, bufsiz; + unsigned char mode, genseq, impseq; +}; + +#define MOUSEDEV_GENIUS_LEN 5 +#define MOUSEDEV_IMPS_LEN 6 + +static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 }; +static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX +static struct mousedev mousedev_single; +#else +static unsigned long mousedev_miscbits = 0; +static struct mousedev *mousedev_base[BITS_PER_LONG]; +#endif + +static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + struct mousedev *mousedev = handle->private; + struct mousedev_list *list = mousedev->list; + int index; + + while (list) { + switch (type) { + case EV_REL: + switch (code) { + case REL_X: list->dx += value; break; + case REL_Y: list->dy -= value; break; + case REL_WHEEL: if (list->mode) list->dz += value; break; + } + break; + + case EV_KEY: + switch (code) { + case BTN_LEFT: index = 0; break; + case BTN_EXTRA: if (list->mode > 1) { index = 4; break; } + case BTN_RIGHT: index = 1; break; + case BTN_SIDE: if (list->mode > 1) { index = 3; break; } + case BTN_MIDDLE: index = 2; break; + default: index = 0; + } + switch (value) { + case 0: clear_bit(index, &list->buttons); break; + case 1: set_bit(index, &list->buttons); break; + case 2: return; + } + break; + } + + list->ready = 1; + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + list = list->next; + } + + wake_up_interruptible(&mousedev->wait); +} + +static int mousedev_fasync(int fd, struct file *file, int on) +{ + int retval; + struct mousedev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static int mousedev_release(struct inode * inode, struct file * file) +{ + struct mousedev_list *list = file->private_data; + struct mousedev_list **listptr = &list->mousedev->list; + + mousedev_fasync(-1, file, 0); + + while (*listptr && (*listptr != list)) + listptr = &((*listptr)->next); + *listptr = (*listptr)->next; + +#ifndef CONFIG_INPUT_MOUSEDEV_MIX + if (!--list->mousedev->used) { + clear_bit(list->mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits); + misc_deregister(&list->mousedev->misc); + kfree(list->mousedev); + } +#endif + + kfree(list); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int mousedev_open(struct inode * inode, struct file * file) +{ + struct mousedev_list *list; + +#ifndef CONFIG_INPUT_MOUSEDEV_MIX + int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; + if (i > BITS_PER_LONG || !test_bit(i, &mousedev_miscbits)) + return -ENODEV; +#endif + + if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) + return -ENOMEM; + + memset(list, 0, sizeof(struct mousedev_list)); + + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + list->mousedev = &mousedev_single; + list->next = mousedev_single.list; + mousedev_single.list = list; +#else + list->mousedev = mousedev_base[i]; + list->next = mousedev_base[i]->list; + mousedev_base[i]->list = list; + list->mousedev->used++; +#endif + + file->private_data = list; + + MOD_INC_USE_COUNT; + return 0; +} + +static void mousedev_packet(struct mousedev_list *list, unsigned char off) +{ + list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); + list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); + list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); + list->dx = list->dy = 0; + list->bufsiz = off + 3; + + if (list->mode > 1) + list->ps2[off] |= ((list->buttons & 0x30) << 2); + + if (list->mode) { + list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); + list->bufsiz++; + list->dz = 0; + } + list->ready = 0; + list->buffer = list->bufsiz; +} + + +static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) +{ + struct mousedev_list *list = file->private_data; + unsigned char c; + int i; + + for (i = 0; i < count; i++) { + + c = buffer[i]; + +#ifdef MOUSEDEV_DEBUG + printk(KERN_DEBUG "mousedev: received char %#x\n", c); +#endif + + if (c == mousedev_genius_seq[list->genseq]) { + if (++list->genseq == MOUSEDEV_GENIUS_LEN) { + list->genseq = 0; + list->ready = 1; + list->mode = 2; + } + } else list->genseq = 0; + + if (c == mousedev_imps_seq[list->impseq]) { + if (++list->impseq == MOUSEDEV_IMPS_LEN) { + list->impseq = 0; + list->ready = 1; + list->mode = 1; + } + } else list->impseq = 0; + + list->ps2[0] = 0xfa; + list->bufsiz = 1; + + switch (c) { + + case 0xeb: /* Poll */ + mousedev_packet(list, 1); + break; + + case 0xf2: /* Get ID */ + list->ps2[1] = (list->mode == 1) ? 3 : 0; + list->bufsiz = 2; + break; + + case 0xe9: /* Get info */ + if (list->mode == 2) { + list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55; + } else { + list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200; + } + list->bufsiz = 4; + break; + } + + list->buffer = list->bufsiz; + } + + if (list->fasync) + kill_fasync(list->fasync, SIGIO, POLL_IN); + + wake_up_interruptible(&list->mousedev->wait); + + return count; +} + +static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + struct mousedev_list *list = file->private_data; + int retval = 0; + + if (!list->ready && !list->buffer) { + + add_wait_queue(&list->mousedev->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!list->ready) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&list->mousedev->wait, &wait); + } + + if (retval) + return retval; + + if (!list->buffer) + mousedev_packet(list, 0); + + if (count > list->buffer) + count = list->buffer; + + if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count)) + return -EFAULT; + + list->buffer -= count; + + return count; +} + +static unsigned int mousedev_poll(struct file *file, poll_table *wait) +{ + struct mousedev_list *list = file->private_data; + poll_wait(file, &list->mousedev->wait, wait); + if (list->ready || list->buffer) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations mousedev_fops = { + read: mousedev_read, + write: mousedev_write, + poll: mousedev_poll, + open: mousedev_open, + release: mousedev_release, + fasync: mousedev_fasync, +}; + +static int mousedev_connect(struct input_handler *handler, struct input_dev *dev) +{ + + if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_REL, dev->evbit))) /* The device must have both rels and keys */ + return -1; + + if (!(test_bit(REL_X, dev->relbit) && test_bit(REL_Y, dev->relbit))) /* It must be a pointer device */ + return -1; + + if (!test_bit(BTN_LEFT, dev->keybit)) /* And have at least one mousebutton */ + return -1; + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + { + struct input_handle *handle; + + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + return -1; + + memset(handle, 0, sizeof(struct input_handle)); + + handle->dev = dev; + handle->handler = handler; + handle->private = &mousedev_single; + + input_open_device(handle); + + printk("mousedev.c: Adding mouse: input%d\n", dev->number); + } +#else + { + struct mousedev *mousedev; + + if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL))) + return -1; + + memset(mousedev, 0, sizeof(struct mousedev)); + + mousedev->misc.minor = ffz(mousedev_miscbits); + set_bit(mousedev->misc.minor, &mousedev_miscbits); + mousedev_base[mousedev->misc.minor] = mousedev; + + sprintf(mousedev->name, "mousedev%d", mousedev->misc.minor); + mousedev->misc.name = mousedev->name; + mousedev->misc.minor += MOUSEDEV_MINOR_BASE; + mousedev->misc.fops = &mousedev_fops; + + mousedev->handle.dev = dev; + mousedev->handle.handler = handler; + mousedev->handle.private = mousedev; + + init_waitqueue_head(&mousedev->wait); + + mousedev->used = 1; + + misc_register(&mousedev->misc); + input_open_device(&mousedev->handle); + + printk("%s: PS/2 mouse device for input%d on misc%d\n", + mousedev->name, dev->number, mousedev->misc.minor); + } +#endif + + return 0; +} + +static void mousedev_disconnect(struct input_handle *handle) +{ +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + printk("mousedev.c: Removing mouse: input%d\n", handle->dev->number); + input_close_device(handle); + kfree(handle); +#else + struct mousedev *mousedev = handle->private; + input_close_device(handle); + if (!--mousedev->used) { + clear_bit(mousedev->misc.minor - MOUSEDEV_MINOR_BASE, &mousedev_miscbits); + misc_deregister(&mousedev->misc); + kfree(mousedev); + } +#endif +} + +static struct input_handler mousedev_handler = { + event: mousedev_event, + connect: mousedev_connect, + disconnect: mousedev_disconnect, +}; + + +#ifdef MODULE +int init_module(void) +#else +int __init mousedev_init(void) +#endif +{ + input_register_handler(&mousedev_handler); + +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + memset(&mousedev_single, 0, sizeof(struct mousedev)); + + init_waitqueue_head(&mousedev_single.wait); + mousedev_single.misc.minor = MOUSEDEV_MINOR_BASE; + mousedev_single.misc.name = "mousedev"; + mousedev_single.misc.fops = &mousedev_fops; + + misc_register(&mousedev_single.misc); + + printk("mousedev: PS/2 mouse device on misc%d\n", mousedev_single.misc.minor); +#endif + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +#ifdef CONFIG_INPUT_MOUSEDEV_MIX + misc_deregister(&mousedev_single.misc); +#endif + + input_unregister_handler(&mousedev_handler); +} +#endif diff -u --recursive --new-file v2.3.35/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.3.35/linux/drivers/usb/ov511.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/ov511.c Sun Jan 2 12:13:47 2000 @@ -0,0 +1,1241 @@ +/* + * OmniVision OV511 Camera-to-USB Bridge Driver + * Copyright 1999 Mark W. McClelland + * + * Based on the Linux CPiA driver. + * + * Released under GPL v.2 license. + * + * Important keywords in comments: + * CAMERA SPECIFIC - Camera specific code; may not work with other cameras. + * DEBUG - Debugging code. + * FIXME - Something that is broken or needs improvement. + * + * Version History: + * Version 1.00 - Initial version + */ + + +#define __NO_VERSION__ + +/* Handle mangled (versioned) external symbols */ + +#include /* retrieve the CONFIG_* macros */ +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +# define MODVERSIONS /* force it on */ +#endif + +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb.h" +#include "ov511.h" + +/* Video Size 384 x 288 x 3 bytes for RGB */ +#define MAX_FRAME_SIZE (384 * 288 * 3) + +// FIXME - Force CIF to make some apps happy for the moment. Should find a +// better way to do this. +#define DEFAULT_WIDTH 384 +#define DEFAULT_HEIGHT 288 + +char kernel_version[] = UTS_RELEASE; + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +static struct usb_driver ov511_driver; + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if (pte_present(pte)) + ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1)); + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr, page; + + /* Round it off to PAGE_SIZE */ + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + mem = vmalloc(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr, page; + + if (!mem) + return; + + size += (PAGE_SIZE - 1); + size &= ~(PAGE_SIZE - 1); + + adr=(unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + vfree(mem); +} + +int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +{ + int rc; + + rc = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 2 /* REG_IO */, + USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, (__u16)reg, &value, 1, HZ); + + PDEBUG("reg write: 0x%X:0x%X\n", reg, value); + + return rc; +} + +/* returns: negative is error, pos or zero is data */ +int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg) +{ + int rc; + unsigned char buffer[1]; + + rc = usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + 2 /* REG_IO */, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE, + 0, (__u16)reg, buffer, 1, HZ); + + PDEBUG("reg read: 0x%X:0x%X\n", reg, buffer[0]); + + if(rc < 0) + return rc; + else + return buffer[0]; +} + +int usb_ov511_cam_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +{ + int rc; + + // Three byte write cycle + + // Set slave ID (This might only need to be done once) + // (CAMERA SPECIFIC (OV7610/OV7110)) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, + OV7610_I2C_WRITE_ID); + if (rc < 0) return rc; + + // Select camera register (I2C sub-address) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + if (rc < 0) return rc; + + // Write "value" to I2C data port of OV511 + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + if (rc < 0) return rc; + + // FIXME - should ensure bus is idle before continuing + + // Initiate 3-byte write cycle + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); + + return rc; +} + +/* returns: negative is error, pos or zero is data */ +int usb_ov511_cam_reg_read(struct usb_device *dev, unsigned char reg) +{ + int rc; + + // Two byte write cycle + + // Set slave ID (This might only need to be done once) + // (CAMERA SPECIFIC (OV7610/OV7110)) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, OV7610_I2C_WRITE_ID); + if (rc < 0) return rc; + + // Select camera register (I2C sub-address) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + if (rc < 0) return rc; + + // Initiate 2-byte write cycle + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); + if (rc < 0) return rc; + + // Two byte read cycle + + // Set slave ID (This might only need to be done once) + // (CAMERA SPECIFIC (OV7610/OV7110)) + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, + OV7610_I2C_READ_ID); + if (rc < 0) return rc; + + // Initiate 2-byte read cycle + rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + if (rc < 0) return rc; + + // FIXME - should check I2C bus status here before reading data! + + // Write "value" to I2C data port of OV511 + return usb_ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); +} + +int usb_ov511_reset(struct usb_device *dev, unsigned char reset_type) +{ + int rc; + + PDEBUG("Reset: type=0x%X\n", reset_type); + rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type); + if (rc < 0) + printk(KERN_ERR "ov511: reset: command failed\n"); + + rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0); + if (rc < 0) + printk(KERN_ERR "ov511: reset: command failed\n"); + + return rc; +} + +int usb_ov511_set_packet_size(struct usb_ov511 *ov511, int size) +{ + int alt, multiplier, err; + + PDEBUG("set packet size: %d\n", size); + + switch (size) { + case 992: + alt = 0; + multiplier = 31; + break; + case 993: + alt = 1; + multiplier = 32; + break; + case 768: + alt = 2; + multiplier = 24; + break; + case 769: + alt = 3; + multiplier = 25; + break; + case 512: + alt = 4; + multiplier = 16; + break; + case 513: + alt = 5; + multiplier = 17; + break; + case 257: + alt = 6; + multiplier = 9; + break; + case 0: + alt = 7; + multiplier = 1; // FIXME - is this correct? + break; + default: + printk(KERN_ERR "ov511_set_packet_size: invalid size (%d)\n", + size); + return -EINVAL; + } + + err = usb_ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, + multiplier); + if (err < 0) { + printk(KERN_ERR "ov511: Set packet size: Set FIFO size ret %d\n", + err); + return -ENOMEM; + } + + if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) { + printk(KERN_ERR "ov511: Set packet size: set interface error\n"); + return -EBUSY; + } + + // FIXME - Should we only reset the FIFO? + if (usb_ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0) + return -ENOMEM; + + return 0; +} + +/* How much data is left in the scratch buf? */ +#define scratch_left(x) (ov511->scratchlen - (int)((char *)x - (char *)ov511->scratch)) + +// FIXME - Useless stub +static void ov511_parse_data(struct usb_ov511 *ov511) +{ + PDEBUG("ov511_parse_data not implemented\n"); // TEMPORARY CODE +} + +static int ov511_compress_isochronous(struct usb_ov511 *ov511, urb_t *urb) +{ + unsigned char *cdata, *data; + int i, totlen = 0; + + data = ov511->scratch + ov511->scratchlen; + for (i = 0; i < urb->number_of_packets; i++) { + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (st) { + // Macro - must be in braces! + PDEBUG("data error: [%d] len=%d, status=%d\n", + i, n, st); + } + + if ((ov511->scratchlen + n) > SCRATCH_BUF_SIZE) { + PDEBUG("scratch buf overflow!scr_len: %d, n: %d\n", ov511->scratchlen, n ); + return totlen; + } + + if (n) { + memmove(data, cdata, n); + data += n; + totlen += n; + ov511->scratchlen += n; + } + } + + return totlen; +} + +static void ov511_isoc_irq(struct urb *urb) +{ + int len; + struct usb_ov511 *ov511 = urb->context; + struct ov511_sbuf *sbuf; + int i; + + PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length); + + if (!ov511->streaming) { + PDEBUG("hmmm... not streaming, but got interrupt\n"); + return; + } + + sbuf = &ov511->sbuf[ov511->cursbuf]; +// usb_kill_isoc(sbuf->isodesc); + + /* Copy the data received into our scratch buffer */ + len = ov511_compress_isochronous(ov511, urb); + + /* If we don't have a frame we're current working on, complain */ + if (ov511->scratchlen) { + if (ov511->curframe < 0) { + // Macro - must be in braces!! + PDEBUG("received data, but no frame available\n"); + } else + ov511_parse_data(ov511); + } + + for (i = 0; i < FRAMES_PER_DESC; i++) { + sbuf->urb->iso_frame_desc[i].status = 0; + sbuf->urb->iso_frame_desc[i].actual_length = 0; + } + + /* Move to the next sbuf */ + ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF; + + /* Reschedule this block of Isochronous desc */ +// usb_run_isoc(sbuf->isodesc, ov511->sbuf[ov511->cursbuf].isodesc); + + return; +} + +static int ov511_init_isoc(struct usb_ov511 *ov511) +{ + struct usb_device *dev = ov511->dev; + urb_t *urb; + int fx, err; + + ov511->compress = 0; + ov511->curframe = -1; + ov511->cursbuf = 0; + ov511->scratchlen = 0; + + // FIXME - is this the proper size? + usb_ov511_set_packet_size(ov511, 512); + + /* We double buffer the Iso lists */ + urb = usb_alloc_urb(FRAMES_PER_DESC); + + if (!urb) { + printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); + return -ENOMEM; + } + ov511->sbuf[0].urb = urb; + urb->dev = dev; + urb->context = ov511; + urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ov511->sbuf[0].data; + urb->complete = ov511_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { + printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); + return -ENOMEM; + } + ov511->sbuf[1].urb = urb; + urb->dev = dev; + urb->context = ov511; + urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ov511->sbuf[1].data; + urb->complete = ov511_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + ov511->sbuf[1].urb->next = ov511->sbuf[0].urb; + ov511->sbuf[0].urb->next = ov511->sbuf[1].urb; + + err = usb_submit_urb(ov511->sbuf[0].urb); + if (err) + printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(0) ret %d\n", + err); + err = usb_submit_urb(ov511->sbuf[1].urb); + if (err) + printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(1) ret %d\n", + err); + + ov511->streaming = 1; + + return 0; +} + + +static void ov511_stop_isoc(struct usb_ov511 *ov511) +{ + if (!ov511->streaming) + return; + +// FIXME - Figure out how to do this with the ov511 (Does the below do it?) +// /* Turn off continuous grab */ +// if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) { +// printk(KERN_ERR "cpia_set_grab_mode error\n"); +// return /* -EBUSY */; +// } + + usb_ov511_set_packet_size(ov511, 0); + + /* Unschedule all of the iso td's */ + usb_unlink_urb(ov511->sbuf[1].urb); + usb_unlink_urb(ov511->sbuf[0].urb); + + ov511->streaming = 0; + + /* Delete them all */ + usb_free_urb(ov511->sbuf[1].urb); + usb_free_urb(ov511->sbuf[0].urb); +} + +static int ov511_new_frame(struct usb_ov511 *ov511, int framenum) +{ + struct ov511_frame *frame; + int width, height; + + /* If we're not grabbing a frame right now and the other frame is */ + /* ready to be grabbed into, then use it instead */ + if (ov511->curframe == -1) { + if (ov511->frame[(framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES].grabstate == FRAME_READY) + framenum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; + } else + return 0; + + frame = &ov511->frame[framenum]; + width = frame->width; + height = frame->height; + + frame->grabstate = FRAME_GRABBING; + frame->scanstate = STATE_SCANNING; + frame->scanlength = 0; /* accumulated in ov511_parse_data() */ + + ov511->curframe = framenum; + + /* Make sure it's not too big */ + if (width > DEFAULT_WIDTH) + width = DEFAULT_WIDTH; + width = (width / 8) * 8; /* Multiple of 8 */ + + if (height > DEFAULT_HEIGHT) + height = DEFAULT_HEIGHT; + height = (height / 4) * 4; /* Multiple of 4 */ + +// FIXME - Don't know how to implement the equivalent of this for the ov511 +// /* Set the ROI they want */ +// if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0) +// return -EBUSY; + +// if (usb_cpia_set_compression(cpia->dev, cpia->compress ? +// COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) { +// printk(KERN_ERR "cpia_set_compression error\n"); +// return -EBUSY; +// } + + /* We want a fresh frame every 30 we get */ + ov511->compress = (ov511->compress + 1) % 30; + +// /* Grab the frame */ +// if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) { +// printk(KERN_ERR "cpia_upload_frame error\n"); +// return -EBUSY; +// } + + return 0; +} + + + +/* Video 4 Linux API */ +static int ov511_open(struct video_device *dev, int flags) +{ + int err = -EBUSY; + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + + PDEBUG("ov511_open\n"); + + down(&ov511->lock); + if (ov511->user) + goto out_unlock; + + ov511->frame[0].grabstate = FRAME_UNUSED; + ov511->frame[1].grabstate = FRAME_UNUSED; + + err = -ENOMEM; + + /* Allocate memory for the frame buffers */ + ov511->fbuf = rvmalloc(2 * MAX_FRAME_SIZE); + if (!ov511->fbuf) + goto open_err_ret; + + ov511->frame[0].data = ov511->fbuf; + ov511->frame[1].data = ov511->fbuf + MAX_FRAME_SIZE; + + PDEBUG("frame [0] @ %p\n", ov511->frame[0].data); + PDEBUG("frame [1] @ %p\n", ov511->frame[1].data); + + ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ov511->sbuf[0].data) + goto open_err_on0; + ov511->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ov511->sbuf[1].data) + goto open_err_on1; + + PDEBUG("sbuf[0] @ %p\n", ov511->sbuf[0].data); + PDEBUG("sbuf[1] @ %p\n", ov511->sbuf[1].data); + + /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used + * (using read() instead). */ + ov511->frame[0].width = DEFAULT_WIDTH; + ov511->frame[0].height = DEFAULT_HEIGHT; + ov511->frame[0].bytes_read = 0; + ov511->frame[1].width = DEFAULT_WIDTH; + ov511->frame[1].height = DEFAULT_HEIGHT; + ov511->frame[1].bytes_read = 0; + + err = ov511_init_isoc(ov511); + if (err) + goto open_err_on2; + + ov511->user++; + up(&ov511->lock); + + MOD_INC_USE_COUNT; + + return 0; + +open_err_on2: + kfree (ov511->sbuf[1].data); +open_err_on1: + kfree (ov511->sbuf[0].data); +open_err_on0: + rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE); +open_err_ret: + return err; +out_unlock: + up(&ov511->lock); + return err; + +} + +static void ov511_close(struct video_device *dev) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + + PDEBUG("ov511_close\n"); + + down(&ov511->lock); + ov511->user--; + + MOD_DEC_USE_COUNT; + + ov511_stop_isoc(ov511); + + rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE); + + kfree(ov511->sbuf[1].data); + kfree(ov511->sbuf[0].data); + + up(&ov511->lock); +} + +static int ov511_init_done(struct video_device *dev) +{ + return 0; +} + +static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock) +{ + return -EINVAL; +} + +// FIXME - Needs much work!!! +static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + + PDEBUG("IOCtl: 0x%X\n", cmd); + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + + strcpy(b.name, "OV511 USB Camera"); + b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = DEFAULT_WIDTH; + b.maxheight = DEFAULT_HEIGHT; + b.minwidth = 8; + b.minheight = 4; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if (v.channel != 0) + return -EINVAL; + + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + strcpy(v.name, "Camera"); + + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSCHAN: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (v != 0) + return -EINVAL; + + return 0; + } + + case VIDIOCGPICT: + { + struct video_picture p; + + p.colour = 0x8000; /* Damn British people :) */ + p.hue = 0x8000; + p.brightness = 180 << 8; /* XXX */ + p.contrast = 192 << 8; /* XXX */ + p.whiteness = 105 << 8; /* XXX */ + p.depth = 24; + p.palette = VIDEO_PALETTE_RGB24; + + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) + return -EFAULT; + + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + + if (copy_from_user(&vw, arg, sizeof(vw))) + return -EFAULT; + if (vw.flags) + return -EINVAL; + if (vw.clipcount) + return -EINVAL; + if (vw.height != DEFAULT_HEIGHT) + return -EINVAL; + if (vw.width != DEFAULT_WIDTH) + return -EINVAL; + + ov511->compress = 0; + + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + + vw.x = 0; + vw.y = 0; + vw.width = DEFAULT_WIDTH; + vw.height = DEFAULT_HEIGHT; + vw.chromakey = 0; + vw.flags = 30; + + if (copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + + return 0; + } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + + memset(&vm, 0, sizeof(vm)); + vm.size = MAX_FRAME_SIZE * 2; + vm.frames = 2; + vm.offsets[0] = 0; + vm.offsets[1] = MAX_FRAME_SIZE; + + if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) + return -EFAULT; + + PDEBUG("MCAPTURE\n"); + PDEBUG("frame: %d, size: %dx%d, format: %d\n", + vm.frame, vm.width, vm.height, vm.format); + + if (vm.format != VIDEO_PALETTE_RGB24) + return -EINVAL; + + if ((vm.frame != 0) && (vm.frame != 1)) + return -EINVAL; + + if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) + return -EBUSY; + + /* Don't compress if the size changed */ + if ((ov511->frame[vm.frame].width != vm.width) || + (ov511->frame[vm.frame].height != vm.height)) + ov511->compress = 0; + + ov511->frame[vm.frame].width = vm.width; + ov511->frame[vm.frame].height = vm.height; + + /* Mark it as ready */ + ov511->frame[vm.frame].grabstate = FRAME_READY; + + return ov511_new_frame(ov511, vm.frame); + } + case VIDIOCSYNC: + { + int frame; + + if (copy_from_user((void *)&frame, arg, sizeof(int))) + return -EFAULT; + + PDEBUG("syncing to frame %d\n", frame); + + switch (ov511->frame[frame].grabstate) { + case FRAME_UNUSED: + return -EINVAL; + case FRAME_READY: + case FRAME_GRABBING: + case FRAME_ERROR: +redo: + do { +#if 0 + init_waitqueue_head(&ov511->frame[frame].wq); +#endif + interruptible_sleep_on(&ov511->frame[frame].wq); + if (signal_pending(current)) + return -EINTR; + } while (ov511->frame[frame].grabstate == FRAME_GRABBING); + + if (ov511->frame[frame].grabstate == FRAME_ERROR) { + int ret; + + if ((ret = ov511_new_frame(ov511, frame)) < 0) + return ret; + goto redo; + } + case FRAME_DONE: + ov511->frame[frame].grabstate = FRAME_UNUSED; + break; + } + + ov511->frame[frame].grabstate = FRAME_UNUSED; + + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer vb; + + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; /* frame buffer not supported, not used */ + + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; + + return 0; + } + case VIDIOCKEY: + return 0; + case VIDIOCCAPTURE: + return -EINVAL; + case VIDIOCSFBUF: + return -EINVAL; + case VIDIOCGTUNER: + case VIDIOCSTUNER: + return -EINVAL; + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return -EINVAL; + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + int frmx = -1; + volatile struct ov511_frame *frame; + + PDEBUG("ov511_read: %ld bytes, noblock=%d\n", count, noblock); + + if (!dev || !buf) + return -EFAULT; + + /* See if a frame is completed, then use it. */ + if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ + frmx = 0; + else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ + frmx = 1; + + if (noblock && (frmx == -1)) + return -EAGAIN; + + /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ + /* See if a frame is in process (grabbing), then use it. */ + if (frmx == -1) { + if (ov511->frame[0].grabstate == FRAME_GRABBING) + frmx = 0; + else if (ov511->frame[1].grabstate == FRAME_GRABBING) + frmx = 1; + } + + /* If no frame is active, start one. */ + if (frmx == -1) + ov511_new_frame(ov511, frmx = 0); + + frame = &ov511->frame[frmx]; + +restart: + while (frame->grabstate == FRAME_GRABBING) { + interruptible_sleep_on(&frame->wq); + if (signal_pending(current)) + return -EINTR; + } + + if (frame->grabstate == FRAME_ERROR) { + frame->bytes_read = 0; + printk(KERN_ERR "ov511_read: errored frame %d\n", ov511->curframe); + if (ov511_new_frame(ov511, frmx)) + printk(KERN_ERR "ov511_read: ov511_new_frame error\n"); + goto restart; + } + + PDEBUG("ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n", frmx, + frame->bytes_read, frame->scanlength); + + /* copy bytes to user space; we allow for partials reads */ + if ((count + frame->bytes_read) > frame->scanlength) + count = frame->scanlength - frame->bytes_read; + + if (copy_to_user(buf, frame->data + frame->bytes_read, count)) + return -EFAULT; + + frame->bytes_read += count; + PDEBUG("ov511_read: {copy} count used=%ld, new bytes_read=%ld\n", + count, frame->bytes_read); + + if (frame->bytes_read >= frame->scanlength) { /* All data has been read */ + frame->bytes_read = 0; + + /* Mark it as available to be used again. */ + ov511->frame[frmx].grabstate = FRAME_UNUSED; + if (ov511_new_frame(ov511, frmx ? 0 : 1)) + printk(KERN_ERR "ov511_read: ov511_new_frame returned error\n"); + } + + return count; +} + +static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; + unsigned long start = (unsigned long)adr; + unsigned long page, pos; + + PDEBUG("mmap: %ld (%lX) bytes\n", size, size); + + if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + return -EINVAL; + + pos = (unsigned long)ov511->fbuf; + while (size > 0) + { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + +// FIXME - needs V4L ID to be assigned +static struct video_device ov511_template = { + "OV511 USB Camera", + VID_TYPE_CAPTURE, + VID_HARDWARE_CPIA, /* FIXME */ + ov511_open, + ov511_close, + ov511_read, + ov511_write, + NULL, + ov511_ioctl, + ov511_mmap, + ov511_init_done, + NULL, + 0, + 0 +}; + +static int usb_ov511_configure(struct usb_ov511 *ov511) +{ + struct usb_device *dev = ov511->dev; + int temprc; // DEBUG CODE + + /* Set altsetting 0 */ + if (usb_set_interface(dev, ov511->iface, 0) < 0) { + printk(KERN_ERR "ov511: usb_set_interface error\n"); + return -EBUSY; + } + + memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); + + init_waitqueue_head(&ov511->frame[0].wq); + init_waitqueue_head(&ov511->frame[1].wq); + + if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) { + printk(KERN_ERR "ov511: video_register_device failed\n"); + return -EBUSY; + } + + // Disable compression + if (usb_ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) { + printk(KERN_ERR "ov511: disable compression: command failed\n"); + goto error; + } + + // Initialize system + // FIXME - This should be moved to a function + if (usb_ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) { + printk(KERN_ERR "ov511: enable system: command failed\n"); + goto error; + } + + if (usb_ov511_reset(dev, OV511_RESET_NOREGS) < 0) + goto error; + +// DEBUG - TEST CODE FOR CAMERA REG READ + temprc = usb_ov511_cam_reg_read(dev, 0x1D); + PDEBUG("Camera reg 0x1D: 0x%X\n", temprc); +// END DEBUG CODE + + ov511->compress = 0; + + return 0; + +error: + video_unregister_device(&ov511->vdev); + usb_driver_release_interface(&ov511_driver, + &dev->actconfig->interface[ov511->iface]); + + kfree(ov511); + + return -EBUSY; +} + +static void* ov511_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_ov511 *ov511; + int rc; + + PDEBUG("probing for device...\n"); + + /* We don't handle multi-config cameras */ + if (dev->descriptor.bNumConfigurations != 1) + return NULL; + + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + + /* Is it an OV511? */ + if (dev->descriptor.idVendor != 0x05a9) + return NULL; + if (dev->descriptor.idProduct != 0x0511) + return NULL; + + /* Checking vendor/product should be enough, but what the hell */ + if (interface->bInterfaceClass != 0xFF) + return NULL; + if (interface->bInterfaceSubClass != 0x00) + return NULL; + + /* We found one */ + printk(KERN_INFO "ov511: USB OV511-based camera found\n"); + + if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "ov511: couldn't kmalloc ov511 struct\n"); + return NULL; + } + + memset(ov511, 0, sizeof(*ov511)); + + ov511->dev = dev; + ov511->iface = interface->bInterfaceNumber; + + rc = usb_ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); + if (rc < 0) { + printk("ov511: Unable to read camera bridge registers\n"); + return NULL; + } else if (rc == 3) { // D-Link DSB-C300 + printk("ov511: Camera is a D-Link DSB-C300\n"); + ov511->customid = 3; + } else if (rc == 21) { // Creative Labs WebCam 3 + printk("ov511: Camera is a Creative Labs WebCam 3\n"); + ov511->customid = 21; + } else { + printk("ov511: Specific camera type (%d) not recognized\n", rc); + printk("ov511: Please contact mmcclelland@delphi.com to request\n"); + printk("ov511: support for your camera.\n"); + return NULL; + } + + // Reset in case driver was unloaded and reloaded without unplug + if (usb_ov511_reset(dev, OV511_RESET_ALL) < 0) + return NULL; + + if (!usb_ov511_configure(ov511)) { + ov511->user=0; + init_MUTEX(&ov511->lock); /* to 1 == available */ + return ov511; + } + else { + printk(KERN_ERR "ov511: Failed to configure camera\n"); + return NULL; + } + + return ov511; +} + +static void ov511_disconnect(struct usb_device *dev, void *ptr) +{ + + struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; + + video_unregister_device(&ov511->vdev); + + usb_driver_release_interface(&ov511_driver, + &ov511->dev->actconfig->interface[ov511->iface]); + + /* Free the memory */ + kfree(ov511); ov511 = NULL; +} + +static struct usb_driver ov511_driver = { + "ov511", + ov511_probe, + ov511_disconnect, + { NULL, NULL } +}; + +int usb_ov511_init(void) +{ + PDEBUG("usb_ov511_init()\n"); + + EXPORT_NO_SYMBOLS; + + return usb_register(&ov511_driver); +} + +void usb_ov511_cleanup(void) +{ + usb_deregister(&ov511_driver); +} + +#ifdef MODULE +int init_module(void) +{ + return usb_ov511_init(); +} + +void cleanup_module(void) +{ + usb_ov511_cleanup(); + + PDEBUG("Module unloaded\n"); +} +#endif + diff -u --recursive --new-file v2.3.35/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h --- v2.3.35/linux/drivers/usb/ov511.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/ov511.h Sun Jan 2 12:13:47 2000 @@ -0,0 +1,209 @@ +#ifndef __LINUX_OV511_H +#define __LINUX_OV511_H + +//#include + +#define OV511_DEBUG /* Turn on debug messages */ + +#ifdef OV511_DEBUG +# define PDEBUG(fmt, args...) printk("ov511: " fmt, ## args) +#else +# define PDEBUG(fmt, args...) /* Nothing */ +#endif + +/* Camera interface register numbers */ +#define OV511_REG_CAMERA_DELAY_MODE 0x10 +#define OV511_REG_CAMERA_EDGE_MODE 0x11 +#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM 0x12 +#define OV511_REG_CAMERA_CLAMPED_LINE_NUM 0x13 +#define OV511_REG_CAMERA_PIXEL_DIVISOR 0x14 +#define OV511_REG_CAMERA_LINE_DIVISOR 0x15 +#define OV511_REG_CAMERA_DATA_INPUT_SELECT 0x16 +#define OV511_REG_CAMERA_RESERVED_LINE_MODE 0x17 +#define OV511_REG_CAMERA_BITMASK 0x18 + +/* Snapshot mode camera interface register numbers */ +#define OV511_REG_SNAP_CAPTURED_FRAME 0x19 +#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM 0x1A +#define OV511_REG_SNAP_CLAMPED_LINE_NUM 0x1B +#define OV511_REG_SNAP_PIXEL_DIVISOR 0x1C +#define OV511_REG_SNAP_LINE_DIVISOR 0x1D +#define OV511_REG_SNAP_DATA_INPUT_SELECT 0x1E +#define OV511_REG_SNAP_BITMASK 0x1F + +/* DRAM register numbers */ +#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL 0x20 +#define OV511_REG_DRAM_READ_CYCLE_PREDICT 0x21 +#define OV511_REG_DRAM_MANUAL_READ_CYCLE 0x22 +#define OV511_REG_DRAM_REFRESH_COUNTER 0x23 + +/* ISO FIFO register numbers */ +#define OV511_REG_FIFO_PACKET_SIZE 0x30 +#define OV511_REG_FIFO_BITMASK 0x31 + +/* PIO register numbers */ +#define OV511_REG_PIO_BITMASK 0x38 +#define OV511_REG_PIO_DATA_PORT 0x39 +#define OV511_REG_PIO_BIST 0x3E + +/* I2C register numbers */ +#define OV511_REG_I2C_CONTROL 0x40 +#define OV511_REG_I2C_SLAVE_ID_WRITE 0x41 +#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE 0x42 +#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE 0x43 +#define OV511_REG_I2C_SLAVE_ID_READ 0x44 +#define OV511_REG_I2C_DATA_PORT 0x45 +#define OV511_REG_I2C_CLOCK_PRESCALER 0x46 +#define OV511_REG_I2C_TIME_OUT_COUNTER 0x47 + +/* I2C snapshot register numbers */ +#define OV511_REG_I2C_SNAP_SUB_ADDRESS 0x48 +#define OV511_REG_I2C_SNAP_DATA_PORT 0x49 + +/* System control register numbers */ +#define OV511_REG_SYSTEM_RESET 0x50 +#define OV511_RESET_UDC 0x01 +#define OV511_RESET_I2O 0x02 +#define OV511_RESET_FIFO 0x04 +#define OV511_RESET_OMNICE 0x08 +#define OV511_RESET_DRAM_INTF 0x10 +#define OV511_RESET_CAMERA_INTF 0x20 +#define OV511_RESET_OV511 0x40 +#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ +#define OV511_RESET_ALL 0x7F +#define OV511_REG_SYSTEM_CLOCK_DIVISOR 0x51 +#define OV511_REG_SYSTEM_SNAPSHOT 0x52 +#define OV511_REG_SYSTEM_INIT 0x53 +#define OV511_REG_SYSTEM_USER_DEFINED 0x5E +#define OV511_REG_SYSTEM_CUSTOM_ID 0x5F + +/* OmniCE register numbers */ +#define OV511_OMNICE_PREDICATION_HORIZ_Y 0x70 +#define OV511_OMNICE_PREDICATION_HORIZ_UV 0x71 +#define OV511_OMNICE_PREDICATION_VERT_Y 0x72 +#define OV511_OMNICE_PREDICATION_VERT_UV 0x73 +#define OV511_OMNICE_QUANTIZATION_HORIZ_Y 0x74 +#define OV511_OMNICE_QUANTIZATION_HORIZ_UV 0x75 +#define OV511_OMNICE_QUANTIZATION_VERT_Y 0x76 +#define OV511_OMNICE_QUANTIZATION_VERT_UV 0x77 +#define OV511_OMNICE_ENABLE 0x78 +#define OV511_OMNICE_LUT_ENABLE 0x79 +#define OV511_OMNICE_Y_LUT_BEGIN 0x80 +#define OV511_OMNICE_Y_LUT_END 0x9F +#define OV511_OMNICE_UV_LUT_BEGIN 0xA0 +#define OV511_OMNICE_UV_LUT_END 0xBF + +/* Alternate numbers for various max packet sizes */ +#define OV511_ALTERNATE_SIZE_992 0 +#define OV511_ALTERNATE_SIZE_993 1 +#define OV511_ALTERNATE_SIZE_768 2 +#define OV511_ALTERNATE_SIZE_769 3 +#define OV511_ALTERNATE_SIZE_512 4 +#define OV511_ALTERNATE_SIZE_513 5 +#define OV511_ALTERNATE_SIZE_257 6 +#define OV511_ALTERNATE_SIZE_0 7 + + +#define STREAM_BUF_SIZE (PAGE_SIZE * 4) + +#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) + +#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ +#define FRAME_SIZE_PER_DESC 960 /* FIXME - Shouldn't be hardcoded */ + +// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)? +#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */ + +// CAMERA SPECIFIC +// FIXME - these can vary between specific models +#define OV7610_I2C_WRITE_ID 0x42 +#define OV7610_I2C_READ_ID 0x43 + +/* Prototypes */ +int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg); +int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value); + + +enum { + STATE_SCANNING, /* Scanning for start */ + STATE_HEADER, /* Parsing header */ + STATE_LINES, /* Parsing lines */ +}; + +struct ov511_frame_header { + // FIXME - nothing here yet +}; + +struct usb_device; + +struct ov511_sbuf { + char *data; + urb_t *urb; +}; + +enum { + FRAME_UNUSED, /* Unused (no MCAPTURE) */ + FRAME_READY, /* Ready to start grabbing */ + FRAME_GRABBING, /* In the process of being grabbed into */ + FRAME_DONE, /* Finished grabbing, but not been synced yet */ + FRAME_ERROR, /* Something bad happened while processing */ +}; + +struct ov511_frame { + char *data; /* Frame buffer */ + + struct ov511_frame_header header; /* Header from stream */ + + int width; /* Width application is expecting */ + int height; /* Height */ + + int hdrwidth; /* Width the frame actually is */ + int hdrheight; /* Height */ + + volatile int grabstate; /* State of grabbing */ + int scanstate; /* State of scanning */ + + int curline; /* Line of frame we're working on */ + + long scanlength; /* uncompressed, raw data length of frame */ + long bytes_read; /* amount of scanlength that has been read from *data */ + + wait_queue_head_t wq; /* Processes waiting */ +}; + +#define OV511_NUMFRAMES 2 +#define OV511_NUMSBUF 2 + +struct usb_ov511 { + struct video_device vdev; + + /* Device structure */ + struct usb_device *dev; + + unsigned char customid; /* Type of camera */ + + unsigned char iface; + + struct semaphore lock; + int user; /* user count for exclusive use */ + + int streaming; /* Are we streaming Isochronous? */ + int grabbing; /* Are we grabbing? */ + + int compress; /* Should the next frame be compressed? */ + + char *fbuf; /* Videodev buffer area */ + + int curframe; /* Current receiving sbuf */ + struct ov511_frame frame[OV511_NUMFRAMES]; + + int cursbuf; /* Current receiving sbuf */ + struct ov511_sbuf sbuf[OV511_NUMSBUF]; + + /* Scratch space from the Isochronous pipe */ + unsigned char scratch[SCRATCH_BUF_SIZE]; + int scratchlen; +}; + +#endif + diff -u --recursive --new-file v2.3.35/linux/drivers/usb/procusb linux/drivers/usb/procusb --- v2.3.35/linux/drivers/usb/procusb Tue Jul 27 16:05:50 1999 +++ linux/drivers/usb/procusb Wed Dec 31 16:00:00 1969 @@ -1,41 +0,0 @@ -#!/usr/bin/perl - -# Reads /proc/bus/usb/devices and selectively lists and/or -# interprets it. - -$DEVFILENAME = "/proc/bus/usb/devices"; -$PROGNAME = $0; - -$TAGS = $ARGV[0]; # save user TAGS -if (length ($TAGS) == 0) -{ - print "usage: $PROGNAME tags\n"; - print " where 'tags' can be any number of 'TDPCIE' or 'A(LL)'\n"; - exit 1; -} - -$ALL = ($TAGS =~ /all/i) || ($TAGS =~ /a/i); - -# TBD: Check that $TAGS is valid. -if (! $ALL) -{ -} - -if (! open (DEVNUM, "<$DEVFILENAME")) -{ - print "$PROGNAME: cannot open '$DEVFILENAME'\n"; - exit 1; -} - -while ($line = ) # read a text line from DEVNUM -{ - if (($ALL) || ($line =~ /^[$TAGS]:/i)) # any of TAGS at beg. of line? - { - print "$line"; # still has newline char on it - # TBD: add more/paging functionality. - } -} # end while DEVNUM - -close (DEVNUM); - -# END. diff -u --recursive --new-file v2.3.35/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.35/linux/drivers/usb/uhci.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/uhci.c Tue Jan 4 09:41:45 2000 @@ -15,11 +15,6 @@ * $Id: uhci.c,v 1.149 1999/12/26 20:57:14 acher Exp $ */ - -#ifndef EXPORT_SYMTAB -#define EXPORT_SYMTAB -#endif - #include #include #include @@ -1807,7 +1802,6 @@ else { desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD } - err: } return ret; diff -u --recursive --new-file v2.3.35/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.3.35/linux/drivers/usb/usb-core.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/usb-core.c Tue Jan 4 11:17:50 2000 @@ -9,78 +9,57 @@ * library, while this file handles starting drivers, etc. * */ + #include #include #include -#include "inits.h" #include "usb.h" -#ifndef CONFIG_USB_MODULE -# ifdef CONFIG_USB_UHCI - int uhci_init(void); -# endif -# ifdef CONFIG_USB_OHCI_HCD - int ohci_hcd_init(void); -# endif -#endif +/* + * USB core + */ -int usb_init(void) -{ - usb_major_init(); -#ifdef CONFIG_USB_PROC - proc_usb_init(); -#endif - usb_hub_init(); +int usb_hub_init(void); +void usb_hub_cleanup(void); +int usb_major_init(void); +void usb_major_cleanup(void); +int proc_usb_init(void); +void proc_usb_cleanup(void); -#ifndef CONFIG_USB_MODULE -# ifdef CONFIG_USB_UHCI - uhci_init(); -# endif -# ifdef CONFIG_USB_OHCI_HCD - ohci_hcd_init(); -# endif -# ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -# endif -# ifdef CONFIG_USB_SCANNER - usb_scanner_init(); -# endif -# ifdef CONFIG_USB_KBD - usb_kbd_init(); -# endif -# ifdef CONFIG_USB_AUDIO - usb_audio_init(); -# endif -# ifdef CONFIG_USB_ACM - usb_acm_init(); -# endif -# ifdef CONFIG_USB_PRINTER - usb_printer_init(); -# endif -# ifdef CONFIG_USB_SERIAL - usb_serial_init(); -# endif -# ifdef CONFIG_USB_CPIA - usb_cpia_init(); -# endif -# ifdef CONFIG_USB_DC2XX - usb_dc2xx_init(); -# endif -# ifdef CONFIG_USB_SCSI - usb_scsi_init(); -# endif -# ifdef CONFIG_USB_DABUSB - dabusb_init(); -# endif -#endif - return 0; -} +/* + * USB device drivers + */ + +int usb_acm_init(void); +int usb_audio_init(void); +int usb_cpia_init(void); +int usb_ov511_init(void); +int usb_dc2xx_init(void); +int usb_scanner_init(void); +int usb_printer_init(void); +int usb_scsi_init(void); +int usb_serial_init(void); +int dabusb_init(void); +int hid_init(void); +int input_init(void); +int usb_mouse_init(void); +int usb_kbd_init(void); /* - * Clean up when unloading the module + * HCI drivers */ -void cleanup_drivers(void) + +int uhci_init(void); +int ohci_hcd_init(void); + +#ifdef MODULE + +/* + * Cleanup + */ + +void cleanup_module(void) { usb_major_cleanup(); #ifdef CONFIG_USB_PROC @@ -88,39 +67,72 @@ #endif usb_hub_cleanup(); -#ifndef MODULE -# ifdef CONFIG_USB_MOUSE - usb_mouse_cleanup(); -# endif -# ifdef CONFIG_USB_SCANNER - usb_scanner_cleanup(); -# endif -# ifdef CONFIG_USB_DABUSB - dabusb_cleanup(); -# endif -# ifdef CONFIG_USB_KBD - usb_kbd_cleanup(); -# endif -# ifdef CONFIG_USB_ACM - usb_acm_cleanup(); -# endif -# ifdef CONFIG_USB_CPIA - usb_cpia_cleanup(); -# endif -# ifdef CONFIG_USB_DC2XX - usb_dc2xx_cleanup(); -# endif -#endif } -#ifdef MODULE +/* + * Init + */ + int init_module(void) +#else +int usb_init(void) +#endif { - return usb_init(); -} + usb_major_init(); +#ifdef CONFIG_USB_PROC + proc_usb_init(); +#endif + usb_hub_init(); -void cleanup_module(void) -{ - cleanup_drivers(); -} +#ifndef CONFIG_USB_MODULE +#ifdef CONFIG_USB_SCANNER + usb_scanner_init(); +#endif +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif +#ifdef CONFIG_USB_ACM + usb_acm_init(); +#endif +#ifdef CONFIG_USB_PRINTER + usb_printer_init(); #endif +#ifdef CONFIG_USB_SERIAL + usb_serial_init(); +#endif +#ifdef CONFIG_USB_CPIA + usb_cpia_init(); +#endif +#ifdef CONFIG_USB_OV511 + usb_ov511_init(); +#endif +#ifdef CONFIG_USB_DC2XX + usb_dc2xx_init(); +#endif +#ifdef CONFIG_USB_SCSI + usb_scsi_init(); +#endif +#ifdef CONFIG_USB_DABUSB + dabusb_init(); +#endif +#if defined(CONFIG_USB_HID) || defined(CONFIG_USB_MOUSE) || defined(CONFIG_USB_KBD) + input_init(); +#endif +#ifdef CONFIG_USB_HID + hid_init(); +#endif +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif +#ifdef CONFIG_USB_UHCI + uhci_init(); +#endif +#ifdef CONFIG_USB_OHCI_HCD + ohci_hcd_init(); +#endif +#endif + return 0; +} diff -u --recursive --new-file v2.3.35/linux/drivers/usb/usb-serial.c linux/drivers/usb/usb-serial.c --- v2.3.35/linux/drivers/usb/usb-serial.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/usb-serial.c Sun Jan 2 12:14:44 2000 @@ -14,6 +14,17 @@ * * See README.serial for more information on using this driver. * + * version 0.3.1 (12/30/99) gkh + * Fixed problems with urb for bulk out. + * Added initial support for multiple sets of endpoints. This enables + * the Handspring Visor to be attached successfully. Only the first + * bulk in / bulk out endpoint pair is being used right now. + * + * version 0.3.0 (12/27/99) gkh + * Added initial support for the Handspring Visor based on a patch from + * Miles Lott (milos@sneety.insync.net) + * Cleaned up the code a bunch and converted over to using urbs only. + * * version 0.2.3 (12/21/99) gkh * Added initial support for the Connect Tech WhiteHEAT converter. * Incremented the number of ports in expectation of getting the @@ -71,12 +82,13 @@ /*#define SERIAL_DEBUG 1*/ #ifdef SERIAL_DEBUG - #define debug_info(message); printk(message); + #define debug_info(format,arg...) printk(KERN_DEBUG "USB Serial: " format "\n" , ##arg) #else - #define debug_info(message); + #define debug_info(format,arg...) do {} while (0) #endif + /* Module information */ MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); MODULE_DESCRIPTION("USB Serial Driver"); @@ -96,7 +108,10 @@ #define PERACOM_VENDOR_ID 0x0565 #define PERACOM_SERIAL_CONVERTER 0x0001 #define CONNECT_TECH_VENDOR_ID 0x0710 -#define CONNECT_TECH_WHITE_HEAT_ID 0x0001 +#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 +#define CONNECT_TECH_WHITE_HEAT_ID 0x8001 +#define HANDSPRING_VENDOR_ID 0x082d +#define HANDSPRING_VISOR_ID 0x0100 #define SERIAL_MAJOR 188 /* Nice legal number now */ @@ -114,6 +129,7 @@ #define HAS 0x02 #define HAS_NOT 0x01 +#define NUM_DONT_CARE (-1) /* local function prototypes */ static int serial_open (struct tty_struct *tty, struct file * filp); @@ -134,8 +150,14 @@ char needs_interrupt_in; char needs_bulk_in; char needs_bulk_out; - // add function calls + char num_interrupt_in; + char num_bulk_in; + char num_bulk_out; + /* function call to make before accepting driver */ + void (*startup) (void); + + /* serial function calls */ int (*open)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp); int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); @@ -147,110 +169,150 @@ }; -/* function prototypes for the eTek type converters (this included Belkin and Peracom) */ +/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ +static int generic_serial_open (struct tty_struct *tty, struct file *filp); +static void generic_serial_close (struct tty_struct *tty, struct file *filp); +static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch); +static int generic_write_room (struct tty_struct *tty); +static int generic_chars_in_buffer (struct tty_struct *tty); + +/* All of the device info needed for the Generic Serial Converter */ +static struct usb_serial_device_type generic_device = { + name: "Generic", + idVendor: &vendor, /* use the user specified vendor id */ + idProduct: &product, /* use the user specified product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + open: generic_serial_open, + close: generic_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, +}; + + +/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */ static int etek_serial_open (struct tty_struct *tty, struct file *filp); static void etek_serial_close (struct tty_struct *tty, struct file *filp); -static int etek_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void etek_serial_put_char (struct tty_struct *tty, unsigned char ch); -static int etek_write_room (struct tty_struct *tty); -static int etek_chars_in_buffer (struct tty_struct *tty); /* All of the device info needed for the Belkin Serial Converter */ static __u16 belkin_vendor_id = BELKIN_VENDOR_ID; static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER; static struct usb_serial_device_type belkin_device = { - "Belkin", - &belkin_vendor_id, /* the Belkin vendor id */ - &belkin_product_id, /* the Belkin serial converter product id */ - MUST_HAVE, /* this device must have an interrupt in endpoint */ - MUST_HAVE, /* this device must have a bulk in endpoint */ - MUST_HAVE, /* this device must have a bulk out endpoint */ - etek_serial_open, - etek_serial_close, - etek_serial_write, - etek_serial_put_char, - etek_write_room, - etek_chars_in_buffer, - NULL, - NULL + name: "Belkin", + idVendor: &belkin_vendor_id, /* the Belkin vendor id */ + idProduct: &belkin_product_id, /* the Belkin serial converter product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + open: etek_serial_open, + close: etek_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, }; /* All of the device info needed for the Peracom Serial Converter */ static __u16 peracom_vendor_id = PERACOM_VENDOR_ID; static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER; static struct usb_serial_device_type peracom_device = { - "Peracom", - &peracom_vendor_id, /* the Peracom vendor id */ - &peracom_product_id, /* the Peracom serial converter product id */ - MUST_HAVE, /* this device must have an interrupt in endpoint */ - MUST_HAVE, /* this device must have a bulk in endpoint */ - MUST_HAVE, /* this device must have a bulk out endpoint */ - etek_serial_open, - etek_serial_close, - etek_serial_write, - etek_serial_put_char, - etek_write_room, - etek_chars_in_buffer, - NULL, - NULL + name: "Peracom", + idVendor: &peracom_vendor_id, /* the Peracom vendor id */ + idProduct: &peracom_product_id, /* the Peracom serial converter product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + open: etek_serial_open, + close: etek_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, }; /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); -static int whiteheat_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void whiteheat_serial_put_char (struct tty_struct *tty, unsigned char ch); -static int whiteheat_write_room (struct tty_struct *tty); -static int whiteheat_chars_in_buffer (struct tty_struct *tty); static void whiteheat_throttle (struct tty_struct *tty); static void whiteheat_unthrottle (struct tty_struct *tty); /* All of the device info needed for the Connect Tech WhiteHEAT */ static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID; +static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID; static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID; +static struct usb_serial_device_type whiteheat_fake_device = { + name: "Connect Tech - WhiteHEAT - (prerenumeration)", + idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ + idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, +}; static struct usb_serial_device_type whiteheat_device = { - "Connect Tech - WhiteHEAT", - &connecttech_vendor_id, /* the Connect Tech vendor id */ - &connecttech_whiteheat_product_id, /* the White Heat product id */ - DONT_CARE, /* don't have to have an interrupt in endpoint */ - DONT_CARE, /* don't have to have a bulk in endpoint */ - DONT_CARE, /* don't have to have a bulk out endpoint */ - whiteheat_serial_open, - whiteheat_serial_close, - whiteheat_serial_write, - whiteheat_serial_put_char, - whiteheat_write_room, - whiteheat_chars_in_buffer, - whiteheat_throttle, - whiteheat_unthrottle + name: "Connect Tech - WhiteHEAT", + idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ + idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + open: whiteheat_serial_open, + close: whiteheat_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, + throttle: whiteheat_throttle, + unthrottle: whiteheat_unthrottle }; -/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ -static int generic_serial_open (struct tty_struct *tty, struct file *filp); -static void generic_serial_close (struct tty_struct *tty, struct file *filp); -static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch); -static int generic_write_room (struct tty_struct *tty); -static int generic_chars_in_buffer (struct tty_struct *tty); - -/* All of the device info needed for the Generic Serial Converter */ -static struct usb_serial_device_type generic_device = { - "Generic", - &vendor, /* use the user specified vendor id */ - &product, /* use the user specified product id */ - DONT_CARE, /* don't have to have an interrupt in endpoint */ - DONT_CARE, /* don't have to have a bulk in endpoint */ - DONT_CARE, /* don't have to have a bulk out endpoint */ - generic_serial_open, - generic_serial_close, - generic_serial_write, - generic_serial_put_char, - generic_write_room, - generic_chars_in_buffer, - NULL, /* generic driver does not implement any flow control */ - NULL /* generic driver does not implement any flow control */ +/* function prototypes for a handspring visor */ +static int visor_serial_open (struct tty_struct *tty, struct file *filp); +static void visor_serial_close (struct tty_struct *tty, struct file *filp); +static void visor_throttle (struct tty_struct *tty); +static void visor_unthrottle (struct tty_struct *tty); + +/* All of the device info needed for the Handspring Visor */ +static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; +static __u16 handspring_product_id = HANDSPRING_VISOR_ID; +static struct usb_serial_device_type handspring_device = { + name: "Handspring Visor", + idVendor: &handspring_vendor_id, /* the Handspring vendor ID */ + idProduct: &handspring_product_id, /* the Handspring Visor product id */ + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + open: visor_serial_open, + close: visor_serial_close, + write: generic_serial_write, + put_char: generic_serial_put_char, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, + throttle: visor_throttle, + unthrottle: visor_unthrottle }; @@ -259,13 +321,16 @@ entry is NULL. */ static struct usb_serial_device_type *usb_serial_devices[] = { &generic_device, + &whiteheat_fake_device, &whiteheat_device, &belkin_device, &peracom_device, + &handspring_device, NULL }; +#define MAX_ENDPOINTS 8 struct usb_serial_state { struct usb_device * dev; @@ -277,32 +342,33 @@ char present; char active; - char has_interrupt_in; /* if this device has an interrupt in pipe or not */ + char num_interrupt_in; /* number of interrupt in endpoints we have */ char interrupt_in_inuse; /* if the interrupt in endpoint is in use */ - __u8 interrupt_in_endpoint; - __u8 interrupt_in_interval; - __u16 interrupt_in_size; /* the size of the interrupt in endpoint */ - unsigned int interrupt_in_pipe; - unsigned char * interrupt_in_buffer; - void * interrupt_in_transfer; - - char has_bulk_in; /* if thie device has a bulk in pipe or not */ - char bulk_in_inuse; /* if the bulk in endpoint is in use */ - __u8 bulk_in_endpoint; - __u8 bulk_in_interval; - __u16 bulk_in_size; /* the size of the bulk in endpoint */ - unsigned int bulk_in_pipe; - unsigned char * bulk_in_buffer; - void * bulk_in_transfer; - - char has_bulk_out; /* if this device has a bulk out pipe or not */ - char bulk_out_inuse; /* if the bulk out endpoint is in use */ - __u8 bulk_out_endpoint; - __u8 bulk_out_interval; - __u16 bulk_out_size; /* the size of the bulk out endpoint */ - unsigned int bulk_out_pipe; - unsigned char * bulk_out_buffer; - void * bulk_out_transfer; + __u8 interrupt_in_endpoint[MAX_ENDPOINTS]; + __u8 interrupt_in_interval[MAX_ENDPOINTS]; + __u16 interrupt_in_size[MAX_ENDPOINTS]; /* the size of the interrupt in endpoint */ + unsigned int interrupt_in_pipe[MAX_ENDPOINTS]; + unsigned char * interrupt_in_buffer[MAX_ENDPOINTS]; + void * interrupt_in_transfer[MAX_ENDPOINTS]; + struct urb control_urb; + + char num_bulk_in; /* number of bulk in endpoints we have */ + __u8 bulk_in_endpoint[MAX_ENDPOINTS]; + __u8 bulk_in_interval[MAX_ENDPOINTS]; + __u16 bulk_in_size[MAX_ENDPOINTS]; /* the size of the bulk in endpoint */ + unsigned int bulk_in_pipe[MAX_ENDPOINTS]; + unsigned char * bulk_in_buffer[MAX_ENDPOINTS]; + void * bulk_in_transfer[MAX_ENDPOINTS]; + struct urb read_urb; + + char num_bulk_out; /* number of bulk out endpoints we have */ + __u8 bulk_out_endpoint[MAX_ENDPOINTS]; + __u8 bulk_out_interval[MAX_ENDPOINTS]; + __u16 bulk_out_size[MAX_ENDPOINTS]; /* the size of the bulk out endpoint */ + unsigned int bulk_out_pipe[MAX_ENDPOINTS]; + unsigned char * bulk_out_buffer[MAX_ENDPOINTS]; + void * bulk_out_transfer[MAX_ENDPOINTS]; + struct urb write_urb; }; static struct usb_driver usb_serial_driver = { @@ -313,7 +379,6 @@ }; static int serial_refcount; -static struct tty_driver serial_tty_driver; static struct tty_struct * serial_tty[NUM_PORTS]; static struct termios * serial_termios[NUM_PORTS]; static struct termios * serial_termios_locked[NUM_PORTS]; @@ -321,76 +386,60 @@ -static int serial_read_irq (int state, void *buffer, int count, void *dev_id) +static void serial_read_bulk (struct urb *urb) { - struct usb_serial_state *serial = (struct usb_serial_state *)dev_id; + struct usb_serial_state *serial = (struct usb_serial_state *)urb->context; struct tty_struct *tty = serial->tty; - unsigned char* data = buffer; + unsigned char *data = urb->transfer_buffer; int i; - debug_info("USB Serial: serial_read_irq\n"); + debug_info("serial_read_irq"); + + if (urb->status) { + debug_info("nonzero read bulk status received: %d", urb->status); + return; + } #ifdef SERIAL_DEBUG - if (count) { - printk("%d %s\n", count, data); + if (urb->actual_length) { + debug_info("%d %s\n", urb->actual_length, data); } #endif - if (count) { - for (i=0;iactual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); } tty_flip_buffer_push(tty); } - /* Continue transfer */ - /* return (1); */ + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + debug_info("failed resubmitting read urb"); - /* No more transfer, let the irq schedule us again */ - serial->bulk_in_inuse = 0; - return (0); + return; } -static int serial_write_irq (int state, void *buffer, int count, void *dev_id) +static void serial_write_bulk (struct urb *urb) { - struct usb_serial_state *serial = (struct usb_serial_state *) dev_id; + struct usb_serial_state *serial = (struct usb_serial_state *) urb->context; struct tty_struct *tty = serial->tty; - debug_info("USB Serial: serial_write_irq\n"); - - if (!serial->bulk_out_inuse) { - debug_info("USB Serial: write irq for a finished pipe?\n"); - return (0); - } + debug_info("serial_write_irq"); - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; + if (urb->status) { + debug_info("nonzero write bulk status received: %d", urb->status); + return; + } if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); - return 0; -} - - -#if 0 -/* we will need this soon... removed for now to keep the compile warnings down */ -static int usb_serial_irq (int state, void *buffer, int len, void *dev_id) -{ - struct usb_serial_state *serial = (struct usb_serial_state *) dev_id; - - debug_info("USB Serial: usb_serial_irq\n"); - - /* ask for a bulk read */ -// serial->bulk_in_inuse = 1; -// serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); - - return (1); + return; } -#endif @@ -401,18 +450,18 @@ { struct usb_serial_state *serial; - debug_info("USB Serial: serial_open\n"); + debug_info("serial_open"); /* assign a serial object to the tty pointer */ serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start]; /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } @@ -432,23 +481,23 @@ static void serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_close\n"); + debug_info("serial_close"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return; } @@ -463,23 +512,23 @@ { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_write\n"); + debug_info("serial_write"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } if (!serial->present) { - debug_info("USB Serial: device not registered\n"); + debug_info("device not registered"); return (-EINVAL); } if (!serial->active) { - debug_info ("USB Serial: device not opened\n"); + debug_info ("device not opened"); return (-EINVAL); } @@ -497,23 +546,23 @@ { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: serial_put_char\n"); + debug_info("serial_put_char"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return; } @@ -530,23 +579,23 @@ { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: serial_write_room\n"); + debug_info("serial_write_room"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return (-EINVAL); } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return (-EINVAL); } @@ -563,23 +612,23 @@ { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: serial_chars_in_buffer\n"); + debug_info("serial_chars_in_buffer"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return (-ENODEV); } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return (-ENODEV); } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return (-EINVAL); } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return (-EINVAL); } @@ -596,23 +645,23 @@ { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_throttle\n"); + debug_info("serial_throttle"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return; } @@ -629,23 +678,23 @@ { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: serial_unthrottle\n"); + debug_info("serial_unthrottle"); /* do some sanity checking that we really have a device present */ if (!serial) { - debug_info("USB Serial: serial == NULL!\n"); + debug_info("serial == NULL!"); return; } if (!serial->type) { - debug_info("USB Serial: serial->type == NULL!\n"); + debug_info("serial->type == NULL!"); return; } if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return; } if (!serial->active) { - debug_info ("USB Serial: device not open\n"); + debug_info ("device not open"); return; } @@ -666,22 +715,22 @@ { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: etek_serial_open\n"); + debug_info("etek_serial_open"); if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return -EINVAL; } if (serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return -EINVAL; } serial->active = 1; /*Start reading from the device*/ - serial->bulk_in_inuse = 1; - serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ /* FIXME!!! */ @@ -693,104 +742,18 @@ static void etek_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: etek_serial_close\n"); + debug_info("etek_serial_close"); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - if (serial->bulk_out_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; - } - if (serial->bulk_in_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; - } - - /* release the irq? */ - + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); serial->active = 0; } -static int etek_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) -{ - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - int written; - - debug_info("USB Serial: etek_serial_write\n"); - - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return (0); - } - - written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count; - - if (from_user) { - copy_from_user(serial->bulk_out_buffer, buf, written); - } - else { - memcpy (serial->bulk_out_buffer, buf, written); - } - - /* send the data out the bulk port */ - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial); - - return (written); -} - - -static void etek_serial_put_char (struct tty_struct *tty, unsigned char ch) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - debug_info("USB Serial: etek_serial_put_char\n"); - - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return; - } - - /* send the single character out the bulk port */ - serial->bulk_out_buffer[0] = ch; - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial); - - return; -} - - -static int etek_write_room (struct tty_struct *tty) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - debug_info("USB Serial: etek_write_room\n"); - - if (serial->bulk_out_inuse) { - return (0); - } - - return (serial->bulk_out_size); -} - - -static int etek_chars_in_buffer (struct tty_struct *tty) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - debug_info("USB Serial: etek_chars_in_buffer\n"); - - if (serial->bulk_out_inuse) { - return (serial->bulk_out_size); - } - - return (0); -} - - /***************************************************************************** * Connect Tech's White Heat specific driver functions *****************************************************************************/ @@ -798,22 +761,22 @@ { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: whiteheat_serial_open\n"); + debug_info("whiteheat_serial_open"); if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return -EINVAL; } if (serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return -EINVAL; } serial->active = 1; /*Start reading from the device*/ - serial->bulk_in_inuse = 1; - serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ /* FIXME!!! */ @@ -825,119 +788,98 @@ static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: whiteheat_serial_close\n"); + debug_info("whiteheat_serial_close"); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - if (serial->bulk_out_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; - } - if (serial->bulk_in_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; - } - - /* release the irq? */ - + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); serial->active = 0; } -static int whiteheat_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) +static void whiteheat_throttle (struct tty_struct * tty) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - int written; + debug_info("whiteheat_throttle"); - debug_info("USB Serial: whiteheat_serial_write\n"); - - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return (0); - } - - written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count; - - if (from_user) { - copy_from_user(serial->bulk_out_buffer, buf, written); - } - else { - memcpy (serial->bulk_out_buffer, buf, written); - } - - /* send the data out the bulk port */ - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial); + /* Change the control signals */ + /* FIXME!!! */ - return (written); -} + return; +} -static void whiteheat_serial_put_char (struct tty_struct *tty, unsigned char ch) +static void whiteheat_unthrottle (struct tty_struct * tty) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - debug_info("USB Serial: whiteheat_serial_put_char\n"); + debug_info("whiteheat_unthrottle"); - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return; - } - - /* send the single character out the bulk port */ - serial->bulk_out_buffer[0] = ch; - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial); + /* Change the control signals */ + /* FIXME!!! */ return; } -static int whiteheat_write_room (struct tty_struct *tty) +/****************************************************************************** + * Handspring Visor specific driver functions + ******************************************************************************/ +static int visor_serial_open (struct tty_struct *tty, struct file *filp) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + debug_info("visor_serial_open"); - debug_info("USB Serial: whiteheat_write_room\n"); - - if (serial->bulk_out_inuse) { - return (0); + if (!serial->present) { + debug_info("no device registered"); + return -EINVAL; } - return (serial->bulk_out_size); -} - + if (serial->active) { + debug_info ("device already open"); + return -EINVAL; + } -static int whiteheat_chars_in_buffer (struct tty_struct *tty) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + serial->active = 1; - debug_info("USB Serial: whiteheat_chars_in_buffer\n"); - - if (serial->bulk_out_inuse) { - return (serial->bulk_out_size); - } + /*Start reading from the device*/ + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); return (0); } - -static void whiteheat_throttle (struct tty_struct * tty) +static void visor_serial_close(struct tty_struct *tty, struct file * filp) { - debug_info("USB Serial: whiteheat_throttle\n"); + struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + debug_info("USB: visor_serial_close"); + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); + serial->active = 0; +} + + +static void visor_throttle (struct tty_struct * tty) +{ +/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */ + + debug_info("visor_throttle"); + /* Change the control signals */ /* FIXME!!! */ return; } - -static void whiteheat_unthrottle (struct tty_struct * tty) +static void visor_unthrottle (struct tty_struct * tty) { - debug_info("USB Serial: whiteheat_unthrottle\n"); - +/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */ + + debug_info("visor_unthrottle"); + /* Change the control signals */ /* FIXME!!! */ @@ -952,24 +894,24 @@ { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: generic_serial_open\n"); + debug_info("generic_serial_open"); if (!serial->present) { - debug_info("USB Serial: no device registered\n"); + debug_info("no device registered"); return -EINVAL; } if (serial->active) { - debug_info ("USB Serial: device already open\n"); + debug_info ("device already open"); return -EINVAL; } serial->active = 1; /* if we have a bulk interrupt, start reading from it */ - if (serial->has_bulk_in) { + if (serial->num_bulk_in) { /*Start reading from the device*/ - serial->bulk_in_inuse = 1; - serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); + if (usb_submit_urb(&serial->read_urb)) + debug_info("usb_submit_urb(read bulk) failed"); } return (0); @@ -979,16 +921,14 @@ static void generic_serial_close(struct tty_struct *tty, struct file * filp) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - debug_info("USB Serial: generic_serial_close\n"); + debug_info("generic_serial_close"); /* shutdown any bulk reads that might be going on */ - if (serial->bulk_out_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; - } - if (serial->bulk_in_inuse){ - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; + if (serial->num_bulk_out) { + usb_unlink_urb (&serial->write_urb); + } + if (serial->num_bulk_in) { + usb_unlink_urb (&serial->read_urb); } serial->active = 0; @@ -998,31 +938,37 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - int written; - debug_info("USB Serial: generic_serial_write\n"); + debug_info("generic_serial_write"); + + if (count == 0) { + debug_info("write request of 0 bytes"); + return (0); + } /* only do something if we have a bulk out endpoint */ - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); + if (serial->num_bulk_out) { + if (serial->write_urb.status == -EINPROGRESS) { + debug_info ("already writing"); return (0); } - written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count; - + count = (count > serial->bulk_out_size[0]) ? serial->bulk_out_size[0] : count; + if (from_user) { - copy_from_user(serial->bulk_out_buffer, buf, written); + copy_from_user(serial->write_urb.transfer_buffer, buf, count); } else { - memcpy (serial->bulk_out_buffer, buf, written); + memcpy (serial->write_urb.transfer_buffer, buf, count); } /* send the data out the bulk port */ - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial); + serial->write_urb.transfer_buffer_length = count; - return (written); + if (usb_submit_urb(&serial->write_urb)) + debug_info("usb_submit_urb(write bulk) failed"); + + return (count); } /* no bulk out, so return 0 bytes written */ @@ -1034,19 +980,17 @@ { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: generic_serial_put_char\n"); + debug_info("generic_serial_put_char"); /* if we have a bulk out endpoint, then shove a character out it */ - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - debug_info ("USB Serial: already writing\n"); - return; - } - + if (serial->num_bulk_out) { /* send the single character out the bulk port */ - serial->bulk_out_buffer[0] = ch; - serial->bulk_out_inuse = 1; - serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial); + memcpy (serial->write_urb.transfer_buffer, &ch, 1); + serial->write_urb.transfer_buffer_length = 1; + + if (usb_submit_urb(&serial->write_urb)) + debug_info("usb_submit_urb(write bulk) failed"); + } return; @@ -1056,14 +1000,17 @@ static int generic_write_room (struct tty_struct *tty) { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + int room; - debug_info("USB Serial: generic_write_room\n"); + debug_info("generic_write_room"); - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - return (0); - } - return (serial->bulk_out_size); + if (serial->num_bulk_out) { + if (serial->write_urb.status == -EINPROGRESS) + room = 0; + else + room = serial->bulk_out_size[0]; + debug_info("generic_write_room returns %d", room); + return (room); } return (0); @@ -1074,11 +1021,11 @@ { struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - debug_info("USB Serial: generic_chars_in_buffer\n"); + debug_info("generic_chars_in_buffer"); - if (serial->has_bulk_out) { - if (serial->bulk_out_inuse) { - return (serial->bulk_out_size); + if (serial->num_bulk_out) { + if (serial->write_urb.status == -EINPROGRESS) { + return (serial->bulk_out_size[0]); } } @@ -1103,9 +1050,9 @@ struct usb_serial_state *serial = NULL; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint = NULL; - struct usb_endpoint_descriptor *bulk_in_endpoint = NULL; - struct usb_endpoint_descriptor *bulk_out_endpoint = NULL; + struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_ENDPOINTS]; + struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_ENDPOINTS]; + struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_ENDPOINTS]; struct usb_serial_device_type *type; int device_num; int serial_num; @@ -1113,20 +1060,21 @@ char interrupt_pipe; char bulk_in_pipe; char bulk_out_pipe; + int num_interrupt_in = 0; + int num_bulk_in = 0; + int num_bulk_out = 0; /* loop through our list of known serial converters, and see if this device matches */ device_num = 0; while (usb_serial_devices[device_num] != NULL) { type = usb_serial_devices[device_num]; - #ifdef SERIAL_DEBUG - printk ("USB Serial: Looking at %s Vendor id=%.4x Product id=%.4x\n", type->name, *(type->idVendor), *(type->idProduct)); - #endif + debug_info ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct)); /* look at the device descriptor */ if ((dev->descriptor.idVendor == *(type->idVendor)) && (dev->descriptor.idProduct == *(type->idProduct))) { - debug_info("USB Serial: descriptor matches...looking at the endpoints\n") + debug_info("descriptor matches...looking at the endpoints"); /* descriptor matches, let's try to find the endpoints needed */ interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT; @@ -1139,37 +1087,28 @@ if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk in endpoint */ - debug_info("USB Serial: found bulk in\n"); - if (bulk_in_pipe == HAS) { - printk("USB Serial: can't have more than one bulk in endpoint\n"); - goto probe_error; - } + debug_info("found bulk in"); bulk_in_pipe = HAS; - bulk_in_endpoint = endpoint; + bulk_in_endpoint[num_bulk_in] = endpoint; + ++num_bulk_in; } if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk out endpoint */ - debug_info("USB Serial: found bulk out\n"); - if (bulk_out_pipe == HAS) { - printk("USB Serial: can't have more than one bulk out endpoint\n"); - goto probe_error; - } + debug_info("found bulk out"); bulk_out_pipe = HAS; - bulk_out_endpoint = endpoint; + bulk_out_endpoint[num_bulk_out] = endpoint; + ++num_bulk_out; } if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03)) { /* we found a interrupt in endpoint */ - debug_info("USB Serial: found interrupt in\n"); - if (interrupt_pipe == HAS) { - printk("USB Serial: can't have more than one interrupt in endpoint\n"); - goto probe_error; - } + debug_info("found interrupt in"); interrupt_pipe = HAS; - interrupt_in_endpoint = endpoint; + interrupt_in_endpoint[num_interrupt_in] = endpoint; + ++num_interrupt_in; } } @@ -1182,7 +1121,7 @@ printk (KERN_INFO "USB Serial: %s converter detected.\n", type->name); if (0>(serial_num = Get_Free_Serial())) { - debug_info("USB Serial: Too many devices connected\n"); + debug_info("Too many devices connected"); return NULL; } @@ -1192,45 +1131,49 @@ serial->dev = dev; serial->type = type; serial->number = serial_num; + serial->num_bulk_in = num_bulk_in; + serial->num_bulk_out = num_bulk_out; + serial->num_interrupt_in = num_interrupt_in; /* set up the endpoint information */ - if (bulk_in_endpoint) { - serial->has_bulk_in = 1; - serial->bulk_in_inuse = 0; - serial->bulk_in_endpoint = bulk_in_endpoint->bEndpointAddress; - serial->bulk_in_size = bulk_in_endpoint->wMaxPacketSize; - serial->bulk_in_interval = bulk_in_endpoint->bInterval; - serial->bulk_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); - serial->bulk_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL); - if (!serial->bulk_in_buffer) { + for (i = 0; i < num_bulk_in; ++i) { + serial->bulk_in_endpoint[i] = bulk_in_endpoint[i]->bEndpointAddress; + serial->bulk_in_size[i] = bulk_in_endpoint[i]->wMaxPacketSize; + serial->bulk_in_interval[i] = bulk_in_endpoint[i]->bInterval; + serial->bulk_in_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[i]); + serial->bulk_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL); + if (!serial->bulk_in_buffer[i]) { printk("USB Serial: Couldn't allocate bulk_in_buffer\n"); goto probe_error; } } - - if (bulk_out_endpoint) { - serial->has_bulk_out = 1; - serial->bulk_out_inuse = 0; - serial->bulk_out_endpoint = bulk_out_endpoint->bEndpointAddress; - serial->bulk_out_size = bulk_out_endpoint->wMaxPacketSize; - serial->bulk_out_interval = bulk_out_endpoint->bInterval; - serial->bulk_out_pipe = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint); - serial->bulk_out_buffer = kmalloc (serial->bulk_out_size, GFP_KERNEL); - if (!serial->bulk_out_buffer) { + if (num_bulk_in) + FILL_BULK_URB(&serial->read_urb, dev, usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[0]), + serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_read_bulk, serial); + + for (i = 0; i < num_bulk_out; ++i) { + serial->bulk_out_endpoint[i] = bulk_out_endpoint[i]->bEndpointAddress; + serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize; + serial->bulk_out_interval[i] = bulk_out_endpoint[i]->bInterval; + serial->bulk_out_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint[i]); + serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL); + if (!serial->bulk_out_buffer[i]) { printk("USB Serial: Couldn't allocate bulk_out_buffer\n"); goto probe_error; } } + if (num_bulk_out) + FILL_BULK_URB(&serial->write_urb, dev, usb_sndbulkpipe (dev, serial->bulk_in_endpoint[0]), + serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_write_bulk, serial); - if (interrupt_in_endpoint) { - serial->has_interrupt_in = 1; + for (i = 0; i < num_interrupt_in; ++i) { serial->interrupt_in_inuse = 0; - serial->interrupt_in_endpoint = interrupt_in_endpoint->bEndpointAddress; - serial->interrupt_in_size = interrupt_in_endpoint->wMaxPacketSize; - serial->interrupt_in_interval = interrupt_in_endpoint->bInterval; + serial->interrupt_in_endpoint[i] = interrupt_in_endpoint[i]->bEndpointAddress; + serial->interrupt_in_size[i] = interrupt_in_endpoint[i]->wMaxPacketSize; + serial->interrupt_in_interval[i] = interrupt_in_endpoint[i]->bInterval; /* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */ - serial->interrupt_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL); - if (!serial->interrupt_in_buffer) { + serial->interrupt_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL); + if (!serial->interrupt_in_buffer[i]) { printk("USB Serial: Couldn't allocate interrupt_in_buffer\n"); goto probe_error; } @@ -1266,12 +1209,15 @@ probe_error: if (serial) { - if (serial->bulk_in_buffer) - kfree (serial->bulk_in_buffer); - if (serial->bulk_out_buffer) - kfree (serial->bulk_out_buffer); - if (serial->interrupt_in_buffer) - kfree (serial->interrupt_in_buffer); + for (i = 0; i < num_bulk_in; ++i) + if (serial->bulk_in_buffer[i]) + kfree (serial->bulk_in_buffer[i]); + for (i = 0; i < num_bulk_out; ++i) + if (serial->bulk_out_buffer[i]) + kfree (serial->bulk_out_buffer[i]); + for (i = 0; i < num_interrupt_in; ++i) + if (serial->interrupt_in_buffer[i]) + kfree (serial->interrupt_in_buffer[i]); } return NULL; } @@ -1280,30 +1226,29 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) { struct usb_serial_state *serial = (struct usb_serial_state *) ptr; + int i; if (serial) { if (!serial->present) { /* something strange is going on */ - debug_info("USB Serial: disconnect but not present?\n") + debug_info("disconnect but not present?"); return; } /* need to stop any transfers...*/ - if (serial->bulk_in_inuse) { - usb_terminate_bulk (serial->dev, serial->bulk_in_transfer); - serial->bulk_in_inuse = 0; - } - if (serial->bulk_out_inuse) { - usb_terminate_bulk (serial->dev, serial->bulk_out_transfer); - serial->bulk_out_inuse = 0; - } - // usb_release_irq (serial->dev, serial->irq_handle, serial->bulk_in_pipe); - if (serial->bulk_in_buffer) - kfree (serial->bulk_in_buffer); - if (serial->bulk_out_buffer) - kfree (serial->bulk_out_buffer); - if (serial->interrupt_in_buffer) - kfree (serial->interrupt_in_buffer); + usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->read_urb); + + /* free up any memory that we allocated */ + for (i = 0; i < serial->num_bulk_in; ++i) + if (serial->bulk_in_buffer[i]) + kfree (serial->bulk_in_buffer[i]); + for (i = 0; i < serial->num_bulk_out; ++i) + if (serial->bulk_out_buffer[i]) + kfree (serial->bulk_out_buffer[i]); + for (i = 0; i < serial->num_interrupt_in; ++i) + if (serial->interrupt_in_buffer[i]) + kfree (serial->interrupt_in_buffer[i]); serial->present = 0; serial->active = 0; @@ -1319,6 +1264,45 @@ } +static struct tty_driver serial_tty_driver = { + magic: TTY_DRIVER_MAGIC, + driver_name: "usb", + name: "ttyUSB", + major: SERIAL_MAJOR, + minor_start: 0, + num: NUM_PORTS, + type: TTY_DRIVER_TYPE_SERIAL, + subtype: SERIAL_TYPE_NORMAL, + flags: TTY_DRIVER_REAL_RAW, + refcount: &serial_refcount, + table: serial_tty, + proc_entry: NULL, + other: NULL, + termios: serial_termios, + termios_locked: serial_termios_locked, + + open: serial_open, + close: serial_close, + write: serial_write, + put_char: serial_put_char, + flush_chars: NULL, + write_room: serial_write_room, + ioctl: NULL, + set_termios: NULL, + set_ldisc: NULL, + throttle: serial_throttle, + unthrottle: serial_unthrottle, + stop: NULL, + start: NULL, + hangup: NULL, + break_ctl: NULL, + wait_until_sent: NULL, + send_xchar: NULL, + read_proc: NULL, + chars_in_buffer: serial_chars_in_buffer, + flush_buffer: NULL +}; + int usb_serial_init(void) { @@ -1330,45 +1314,8 @@ } /* register the tty driver */ - memset (&serial_tty_driver, 0, sizeof(struct tty_driver)); - serial_tty_driver.magic = TTY_DRIVER_MAGIC; - serial_tty_driver.driver_name = "usb"; - serial_tty_driver.name = "ttyUSB"; - serial_tty_driver.major = SERIAL_MAJOR; - serial_tty_driver.minor_start = 0; - serial_tty_driver.num = NUM_PORTS; - serial_tty_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_tty_driver.subtype = SERIAL_TYPE_NORMAL; serial_tty_driver.init_termios = tty_std_termios; serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_tty_driver.flags = TTY_DRIVER_REAL_RAW; - serial_tty_driver.refcount = &serial_refcount; - serial_tty_driver.table = serial_tty; - serial_tty_driver.proc_entry = NULL; - serial_tty_driver.other = NULL; - serial_tty_driver.termios = serial_termios; - serial_tty_driver.termios_locked = serial_termios_locked; - - serial_tty_driver.open = serial_open; - serial_tty_driver.close = serial_close; - serial_tty_driver.write = serial_write; - serial_tty_driver.put_char = serial_put_char; - serial_tty_driver.flush_chars = NULL; //serial_flush_chars; - serial_tty_driver.write_room = serial_write_room; - serial_tty_driver.ioctl = NULL; //serial_ioctl; - serial_tty_driver.set_termios = NULL; //serial_set_termios; - serial_tty_driver.set_ldisc = NULL; - serial_tty_driver.throttle = serial_throttle; - serial_tty_driver.unthrottle = serial_unthrottle; - serial_tty_driver.stop = NULL; //serial_stop; - serial_tty_driver.start = NULL; //serial_start; - serial_tty_driver.hangup = NULL; //serial_hangup; - serial_tty_driver.break_ctl = NULL; //serial_break; - serial_tty_driver.wait_until_sent = NULL; //serial_wait_until_sent; - serial_tty_driver.send_xchar = NULL; //serial_send_xchar; - serial_tty_driver.read_proc = NULL; //serial_read_proc; - serial_tty_driver.chars_in_buffer = serial_chars_in_buffer; - serial_tty_driver.flush_buffer = NULL; //serial_flush_buffer; if (tty_register_driver (&serial_tty_driver)) { printk( "USB Serial: failed to register tty driver\n" ); return -EPERM; diff -u --recursive --new-file v2.3.35/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.35/linux/drivers/usb/usb.c Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/usb.c Tue Jan 4 11:17:50 2000 @@ -18,10 +18,6 @@ * $Id: usb.c,v 1.39 1999/12/27 15:17:47 acher Exp $ */ -#ifndef EXPORT_SYMTAB -#define EXPORT_SYMTAB -#endif - #define USB_DEBUG 1 #include @@ -1179,6 +1175,34 @@ } /* + * __usb_get_extra_descriptor() finds a descriptor of specific type in the + * extra field of the interface and endpoint descriptor structs. + */ + +int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr) +{ + struct usb_descriptor_header *header; + + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + if (header->bDescriptorType == type) { + *ptr = header; + return 0; + } + + buffer += header->bLength; + size -= header->bLength; + } + return -1; +} + +/* * Something got disconnected. Get rid of it, and all of its children. */ void usb_disconnect(struct usb_device **pdev) @@ -1268,6 +1292,14 @@ return result; } +int usb_get_class_descriptor(struct usb_device *dev, unsigned char type, + unsigned char id, unsigned char index, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_RT_INTERFACE | USB_DIR_IN, + (type << 8) + id, index, buf, size, HZ * GET_TIMEOUT); +} + int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) { return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), @@ -1313,8 +1345,6 @@ USB_REQ_SET_PROTOCOL, USB_RT_HIDD, protocol, 1, NULL, 0, HZ * SET_TIMEOUT); } -/* keyboards want a nonzero duration according to HID spec, but - mice should use infinity (0) -keryan */ int usb_set_idle(struct usb_device *dev, int duration, int report_id) { return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_IDLE, @@ -1446,6 +1476,13 @@ (type << 8) + id, index, buf, size, HZ * GET_TIMEOUT); } +int usb_set_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_SET_REPORT, USB_RT_HIDD, + (type << 8) + id, index, buf, size, HZ); +} + int usb_get_configuration(struct usb_device *dev) { int result; @@ -1683,12 +1720,13 @@ NULL /* release */ }; -void usb_major_init(void) +int usb_major_init(void) { if (register_chrdev(USB_MAJOR,"usb",&usb_fops)) { - printk("unable to get major %d for usb devices\n", - USB_MAJOR); + printk("unable to get major %d for usb devices\n", USB_MAJOR); + return -EBUSY; } + return 0; } void usb_major_cleanup(void) @@ -1737,11 +1775,14 @@ EXPORT_SYMBOL(usb_set_address); EXPORT_SYMBOL(usb_get_descriptor); +EXPORT_SYMBOL(usb_get_class_descriptor); +EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_get_string); EXPORT_SYMBOL(usb_string); EXPORT_SYMBOL(usb_get_protocol); EXPORT_SYMBOL(usb_set_protocol); EXPORT_SYMBOL(usb_get_report); +EXPORT_SYMBOL(usb_set_report); EXPORT_SYMBOL(usb_set_idle); EXPORT_SYMBOL(usb_clear_halt); EXPORT_SYMBOL(usb_set_interface); diff -u --recursive --new-file v2.3.35/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.35/linux/drivers/usb/usb.h Wed Dec 29 13:13:19 1999 +++ linux/drivers/usb/usb.h Tue Jan 4 12:21:38 2000 @@ -44,6 +44,7 @@ #define USB_DT_ENDPOINT_SIZE 7 #define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ #define USB_DT_HUB_NONVAR_SIZE 7 +#define USB_DT_HID_SIZE 9 /* * USB Request Type and Endpoint Directions @@ -168,9 +169,6 @@ #define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface) #define USB_PROC_SETCONFIGURATION _IOR('U', 5, unsigned int) - - - #ifdef __KERNEL__ #include @@ -179,19 +177,10 @@ #define USB_MAJOR 180 -extern int usb_hub_init(void); -extern int usb_kbd_init(void); -extern int usb_cpia_init(void); -extern int usb_dc2xx_init(void); -extern int usb_mouse_init(void); -extern int usb_printer_init(void); - -extern void usb_hub_cleanup(void); -extern void usb_mouse_cleanup(void); - /* for 2.2-kernels */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); @@ -742,18 +731,27 @@ */ int usb_new_device(struct usb_device *dev); int usb_set_address(struct usb_device *dev); -int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned -char descindex, void *buf, int size); +int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, + unsigned char descindex, void *buf, int size); +int usb_get_class_descriptor(struct usb_device *dev, unsigned char desctype, + unsigned char descindex, unsigned char ifnum, void *buf, int size); int usb_get_device_descriptor(struct usb_device *dev); +int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr); int usb_get_status (struct usb_device *dev, int type, int target, void *data); int usb_get_protocol(struct usb_device *dev); int usb_set_protocol(struct usb_device *dev, int protocol); int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_idle(struct usb_device *dev, int duration, int report_id); int usb_set_configuration(struct usb_device *dev, int configuration); -int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size); +int usb_get_report(struct usb_device *dev, unsigned char type, + unsigned char id, unsigned char index, void *buf, int size); +int usb_set_report(struct usb_device *dev, unsigned char type, + unsigned char id, unsigned char index, void *buf, int size); char *usb_string(struct usb_device *dev, int index); int usb_clear_halt(struct usb_device *dev, int endp); + +#define usb_get_extra_descriptor(ifpoint,type,ptr)\ + __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,type,(void**)ptr) /* * Some USB bandwidth allocation constants. diff -u --recursive --new-file v2.3.35/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c --- v2.3.35/linux/drivers/usb/usbkbd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/usbkbd.c Sun Jan 2 12:12:59 2000 @@ -0,0 +1,208 @@ +/* + * usbkbd.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * USB HIDBP Keyboard support + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include "usb.h" + +MODULE_AUTHOR("Vojtech Pavlik "); + +static unsigned char usb_kbd_keycode[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 0, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, + 120,121,122,123, 0,138, 0, 0,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126 +}; + +struct usb_kbd { + struct input_dev dev; + unsigned char new[8]; + unsigned char old[8]; + struct urb irq, led; + devrequest dr; + unsigned char leds; +}; + +static void usb_kbd_irq(struct urb *urb) +{ + struct usb_kbd *kbd = urb->context; + int i; + + if (urb->status) return; + + for (i = 0; i < 8; i++) + input_report_key(&kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1); + + for (i = 2; i < 8; i++) { + + if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) { + if (usb_kbd_keycode[kbd->old[i]]) + input_report_key(&kbd->dev, usb_kbd_keycode[kbd->old[i]], 0); + else + printk(KERN_DEBUG "usbkbd.c: Unknown key (scancode %#x) released.\n", kbd->old[i]); + } + + if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) { + if (usb_kbd_keycode[kbd->new[i]]) + input_report_key(&kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); + else + printk(KERN_DEBUG "usbkbd.c: Unknown key (scancode %#x) pressed.\n", kbd->new[i]); + } + } + + memcpy(kbd->old, kbd->new, 8); +} + +int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct usb_kbd *kbd = dev->private; + + if (type != EV_LED) return -1; + + kbd->leds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | + (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | + (!!test_bit(LED_NUML, dev->led)); + + usb_submit_urb(&kbd->led); + + return -1; +} + +static void usb_kbd_led(struct urb *urb) +{ + if (urb->status) + printk(KERN_DEBUG "nonzero control status received: %d\n", urb->status); +} + +static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_kbd *kbd; + int i; + + if (dev->descriptor.bNumConfigurations != 1) return NULL; + interface = dev->config[0].interface[ifnum].altsetting + 0; + + if (interface->bInterfaceClass != 3) return NULL; + if (interface->bInterfaceSubClass != 1) return NULL; + if (interface->bInterfaceProtocol != 1) return NULL; + if (interface->bNumEndpoints != 1) return NULL; + + endpoint = interface->endpoint + 0; + if (!(endpoint->bEndpointAddress & 0x80)) return NULL; + if ((endpoint->bmAttributes & 3) != 3) return NULL; + + usb_set_protocol(dev, 0); + + if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL; + memset(kbd, 0, sizeof(struct usb_kbd)); + + kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); + + for (i = 0; i < 255; i++) + set_bit(usb_kbd_keycode[i], kbd->dev.keybit); + clear_bit(0, kbd->dev.keybit); + + kbd->dev.private = kbd; + kbd->dev.event = usb_kbd_event; + + kbd->dr.requesttype = USB_RT_HIDD; + kbd->dr.request = USB_REQ_SET_REPORT; + kbd->dr.value = 0x200; + kbd->dr.index = 1; + kbd->dr.length = 1; + + { + int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, + usb_kbd_irq, kbd, endpoint->bInterval); + } + + FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, endpoint->bEndpointAddress), + (void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd); + + if (usb_submit_urb(&kbd->irq)) { + kfree(kbd); + return NULL; + } + + input_register_device(&kbd->dev); + + printk(KERN_INFO "input%d: USB HIDBP keyboard\n", kbd->dev.number); + + + return kbd; +} + +static void usb_kbd_disconnect(struct usb_device *dev, void *ptr) +{ + struct usb_kbd *kbd = ptr; + usb_unlink_urb(&kbd->irq); + input_unregister_device(&kbd->dev); + kfree(kbd); +} + +static struct usb_driver usb_kbd_driver = { + name: "keyboard", + probe: usb_kbd_probe, + disconnect: usb_kbd_disconnect +}; + +#ifdef MODULE +void cleanup_module(void) +{ + usb_deregister(&usb_kbd_driver); +} + +int init_module(void) +#else +int usb_kbd_init(void) +#endif +{ + usb_register(&usb_kbd_driver); + return 0; +} diff -u --recursive --new-file v2.3.35/linux/drivers/usb/usbmouse.c linux/drivers/usb/usbmouse.c --- v2.3.35/linux/drivers/usb/usbmouse.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/usbmouse.c Sun Jan 2 12:12:59 2000 @@ -0,0 +1,148 @@ +/* + * usbmouse.c Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * USB HIDBP Mouse support + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include "usb.h" + +MODULE_AUTHOR("Vojtech Pavlik "); + +#define USBMOUSE_EXTRA + +struct usb_mouse { + signed char data[8]; + struct input_dev dev; + struct urb irq; +}; + +static void usb_mouse_irq(struct urb *urb) +{ + struct usb_mouse *mouse = urb->context; + signed char *data = mouse->data; + struct input_dev *dev = &mouse->dev; + + if (urb->status) return; + + input_report_key(dev, BTN_LEFT, !!(data[0] & 0x01)); + input_report_key(dev, BTN_RIGHT, !!(data[0] & 0x02)); + input_report_key(dev, BTN_MIDDLE, !!(data[0] & 0x04)); + input_report_rel(dev, REL_X, data[1]); + input_report_rel(dev, REL_Y, data[2]); +#ifdef USBMOUSE_EXTRA + input_report_key(dev, BTN_SIDE, !!(data[0] & 0x08)); + input_report_key(dev, BTN_EXTRA, !!(data[0] & 0x10)); + input_report_rel(dev, REL_WHEEL, data[3]); +#endif +} + +static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_mouse *mouse; + + if (dev->descriptor.bNumConfigurations != 1) return NULL; + interface = dev->config[0].interface[ifnum].altsetting + 0; + + if (interface->bInterfaceClass != 3) return NULL; + if (interface->bInterfaceSubClass != 1) return NULL; + if (interface->bInterfaceProtocol != 2) return NULL; + if (interface->bNumEndpoints != 1) return NULL; + + endpoint = interface->endpoint + 0; + if (!(endpoint->bEndpointAddress & 0x80)) return NULL; + if ((endpoint->bmAttributes & 3) != 3) return NULL; + +#ifndef USBMOUSE_EXTRA + usb_set_protocol(dev, 0); +#endif + + if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL; + memset(mouse, 0, sizeof(struct usb_mouse)); + + mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); +#ifdef USBMOUSE_EXTRA + mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); + mouse->dev.relbit[0] |= BIT(REL_WHEEL); +#endif + + { + int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + int maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp, + usb_mouse_irq, mouse, endpoint->bInterval); + } + + if (usb_submit_urb(&mouse->irq)) { + kfree(mouse); + return NULL; + } + + input_register_device(&mouse->dev); + + printk(KERN_INFO "input%d: USB HIDBP mouse\n", mouse->dev.number); + + return mouse; +} + +static void usb_mouse_disconnect(struct usb_device *dev, void *ptr) +{ + struct usb_mouse *mouse = ptr; + usb_unlink_urb(&mouse->irq); + input_unregister_device(&mouse->dev); + kfree(mouse); +} + +static struct usb_driver usb_mouse_driver = { + name: "usb_mouse", + probe: usb_mouse_probe, + disconnect: usb_mouse_disconnect, +}; + +#ifdef MODULE +void cleanup_module(void) +{ + usb_deregister(&usb_mouse_driver); +} + +int init_module(void) +#else +int usb_mouse_init(void) +#endif +{ + usb_register(&usb_mouse_driver); + return 0; +} + diff -u --recursive --new-file v2.3.35/linux/fs/cramfs/Makefile linux/fs/cramfs/Makefile --- v2.3.35/linux/fs/cramfs/Makefile Wed Dec 29 13:13:20 1999 +++ linux/fs/cramfs/Makefile Wed Dec 29 17:29:43 1999 @@ -6,6 +6,8 @@ O_OBJS := inode.o uncompress.o inflate/zlib.o +M_OBJS := $(O_TARGET) + include $(TOPDIR)/Rules.make inflate/zlib.o: diff -u --recursive --new-file v2.3.35/linux/fs/cramfs/inflate/Makefile linux/fs/cramfs/inflate/Makefile --- v2.3.35/linux/fs/cramfs/inflate/Makefile Wed Dec 29 13:13:20 1999 +++ linux/fs/cramfs/inflate/Makefile Mon Jan 3 12:01:31 2000 @@ -26,9 +26,9 @@ # uncompression can be done without blocking on allocation). # -OBJECTFILES=adler32.o infblock.o infcodes.o inffast.o inflate.o inftrees.o infutil.o uncompr.o +O_TARGET := zlib.o -zlib.o: $(OBJECTFILES) - ld -r -o zlib.o $(OBJECTFILES) +O_OBJS := adler32.o infblock.o infcodes.o inffast.o inflate.o \ + inftrees.o infutil.o uncompr.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.35/linux/fs/cramfs/inflate/infblock.c linux/fs/cramfs/inflate/infblock.c --- v2.3.35/linux/fs/cramfs/inflate/infblock.c Wed Dec 29 13:13:20 1999 +++ linux/fs/cramfs/inflate/infblock.c Mon Jan 3 12:01:31 2000 @@ -80,7 +80,6 @@ s->read = s->write = s->window; if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); - Tracev((stderr, "inflate: blocks reset\n")); } @@ -100,7 +99,6 @@ s->end = s->window + w; s->checkfn = c; s->mode = TYPE; - Tracev((stderr, "inflate: blocks allocated\n")); inflate_blocks_reset(s, z, Z_NULL); return s; } @@ -132,16 +130,12 @@ switch (t >> 1) { case 0: /* stored */ - Tracev((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); DUMPBITS(3) t = k & 7; /* go to byte boundary */ DUMPBITS(t) s->mode = LENS; /* get length of stored block */ break; case 1: /* fixed */ - Tracev((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); { uInt bl, bd; inflate_huft *tl, *td; @@ -158,8 +152,6 @@ s->mode = CODES; break; case 2: /* dynamic */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); DUMPBITS(3) s->mode = TABLE; break; @@ -182,7 +174,6 @@ } s->sub.left = (uInt)b & 0xffff; b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); break; case STORED: @@ -197,9 +188,6 @@ q += t; m -= t; if ((s->sub.left -= t) != 0) break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); s->mode = s->last ? DRY : TYPE; break; case TABLE: @@ -220,7 +208,6 @@ } DUMPBITS(14) s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); s->mode = BTREE; case BTREE: while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) @@ -242,7 +229,6 @@ LEAVE } s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); s->mode = DTREE; case DTREE: while (t = s->sub.trees.table, @@ -305,7 +291,6 @@ r = t; LEAVE } - Tracev((stderr, "inflate: trees ok\n")); if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) { r = Z_MEM_ERROR; @@ -321,9 +306,6 @@ r = Z_OK; inflate_codes_free(s->sub.decode.codes, z); LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); if (!s->last) { s->mode = TYPE; @@ -353,7 +335,6 @@ z_streamp z; { inflate_blocks_reset(s, z, Z_NULL); - Tracev((stderr, "inflate: blocks freed\n")); return Z_OK; } diff -u --recursive --new-file v2.3.35/linux/fs/cramfs/inflate/infcodes.c linux/fs/cramfs/inflate/infcodes.c --- v2.3.35/linux/fs/cramfs/inflate/infcodes.c Wed Dec 29 13:13:20 1999 +++ linux/fs/cramfs/inflate/infcodes.c Mon Jan 3 12:01:31 2000 @@ -72,7 +72,6 @@ c->dbits = (Byte)bd; c->ltree = tl; c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); } return c; } @@ -127,9 +126,6 @@ if (e == 0) /* literal */ { c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); c->mode = LIT; break; } @@ -148,7 +144,6 @@ } if (e & 32) /* end of block */ { - Tracevv((stderr, "inflate: end of block\n")); c->mode = WASH; break; } @@ -163,7 +158,6 @@ DUMPBITS(j) c->sub.code.need = c->dbits; c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); c->mode = DIST; case DIST: /* i: get distance next */ j = c->sub.code.need; @@ -193,7 +187,6 @@ NEEDBITS(j) c->sub.copy.dist += (uInt)b & inflate_mask[j]; DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); c->mode = COPY; case COPY: /* o: copying bytes in window, waiting for space */ #ifndef __TURBOC__ /* Turbo C bug for following expression */ @@ -223,7 +216,6 @@ case WASH: /* o: got eob, possibly more output */ if (k > 7) /* return unused byte, if any */ { - Assert(k < 16, "inflate_codes grabbed too many bytes") k -= 8; n++; p--; /* can always return one */ @@ -252,5 +244,4 @@ inflate_codes_statef *c; z_streamp z; { - Tracev((stderr, "inflate: codes free\n")); } diff -u --recursive --new-file v2.3.35/linux/fs/cramfs/inflate/inffast.c linux/fs/cramfs/inflate/inffast.c --- v2.3.35/linux/fs/cramfs/inflate/inffast.c Wed Dec 29 13:13:20 1999 +++ linux/fs/cramfs/inflate/inffast.c Mon Jan 3 12:01:31 2000 @@ -60,9 +60,6 @@ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) { DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; continue; @@ -75,7 +72,6 @@ e &= 15; c = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); /* decode distance base of block to copy */ GRABBITS(15); /* max bits for distance code */ @@ -89,7 +85,6 @@ GRABBITS(e) /* get extra bits (up to 13) */ d = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); /* do the copy */ m -= c; @@ -138,9 +133,6 @@ if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) { DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; break; @@ -148,7 +140,6 @@ } else if (e & 32) { - Tracevv((stderr, "inflate: * end of block\n")); UNGRAB UPDATE return Z_STREAM_END; diff -u --recursive --new-file v2.3.35/linux/fs/cramfs/inflate/inflate.c linux/fs/cramfs/inflate/inflate.c --- v2.3.35/linux/fs/cramfs/inflate/inflate.c Wed Dec 29 13:13:20 1999 +++ linux/fs/cramfs/inflate/inflate.c Mon Jan 3 12:01:31 2000 @@ -59,7 +59,6 @@ z->msg = Z_NULL; z->state->mode = z->state->nowrap ? BLOCKS : METHOD; inflate_blocks_reset(z->state->blocks, z, Z_NULL); - Tracev((stderr, "inflate: reset\n")); return Z_OK; } @@ -72,7 +71,6 @@ if (z->state->blocks != Z_NULL) inflate_blocks_free(z->state->blocks, z); z->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); return Z_OK; } @@ -120,7 +118,6 @@ inflateEnd(z); return Z_MEM_ERROR; } - Tracev((stderr, "inflate: allocated\n")); /* reset state */ inflateReset(z); @@ -180,7 +177,6 @@ z->state->sub.marker = 5; /* can't try inflateSync */ break; } - Tracev((stderr, "inflate: zlib header ok\n")); if (!(b & PRESET_DICT)) { z->state->mode = BLOCKS; @@ -253,7 +249,6 @@ z->state->sub.marker = 5; /* can't try inflateSync */ break; } - Tracev((stderr, "inflate: zlib check ok\n")); z->state->mode = DONE; case DONE: return Z_STREAM_END; diff -u --recursive --new-file v2.3.35/linux/fs/cramfs/inflate/zutil.h linux/fs/cramfs/inflate/zutil.h --- v2.3.35/linux/fs/cramfs/inflate/zutil.h Wed Dec 29 13:13:20 1999 +++ linux/fs/cramfs/inflate/zutil.h Mon Jan 3 12:01:31 2000 @@ -8,23 +8,15 @@ subject to change. Applications should only use zlib.h. */ -/* @(#) $Id$ */ +/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */ #ifndef _Z_UTIL_H #define _Z_UTIL_H #include "zlib.h" -# include -# include - -#ifdef __KERNEL__ -# include -# include -#else -# include -# include -#endif +#include +#include #ifndef local # define local static @@ -37,15 +29,6 @@ typedef ush FAR ushf; typedef unsigned long ulg; -extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = (char*)ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - /* common constants */ #ifndef DEF_WBITS @@ -79,42 +62,9 @@ # define OS_CODE 0x03 /* assume Unix */ #endif -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - /* functions */ -/* Diagnostic functions */ -#ifdef DEBUG -# include - extern int z_verbose; - extern void z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, uInt len)); -voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); -void zcfree OF((voidpf opaque, voidpf ptr)); - -#define ZALLOC(strm, items, size) ({ \ - printf("alloc %d %d at %s:%d\n", items, size, __FILE__, __LINE__); \ - calloc((items), (size)); }) -#define ZFREE(strm, addr) free(addr) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} #endif /* _Z_UTIL_H */ diff -u --recursive --new-file v2.3.35/linux/fs/devices.c linux/fs/devices.c --- v2.3.35/linux/fs/devices.c Tue Dec 7 09:32:47 1999 +++ linux/fs/devices.c Tue Jan 4 13:02:23 2000 @@ -265,7 +265,7 @@ NULL, /* release */ }; -struct inode_operations blkdev_inode_operations = { +static struct inode_operations blkdev_inode_operations = { &def_blk_fops, /* default file operations */ NULL, /* create */ NULL, /* lookup */ @@ -320,7 +320,7 @@ NULL, /* release */ }; -struct inode_operations chrdev_inode_operations = { +static struct inode_operations chrdev_inode_operations = { &def_chr_fops, /* default file operations */ NULL, /* create */ NULL, /* lookup */ diff -u --recursive --new-file v2.3.35/linux/fs/devpts/inode.c linux/fs/devpts/inode.c --- v2.3.35/linux/fs/devpts/inode.c Tue Aug 31 17:29:14 1999 +++ linux/fs/devpts/inode.c Tue Jan 4 13:02:23 2000 @@ -284,10 +284,8 @@ if ( ino >= sbi->max_ptys ) return; /* Bogus */ - inode->i_mode = S_IFCHR; - inode->i_rdev = MKDEV(0,0); /* Gets filled in by devpts_pty_new() */ - - inode->i_op = &chrdev_inode_operations; + /* Gets filled in by devpts_pty_new() */ + init_special_inode(inode,S_IFCHR,0); return; } diff -u --recursive --new-file v2.3.35/linux/fs/efs/inode.c linux/fs/efs/inode.c --- v2.3.35/linux/fs/efs/inode.c Thu May 13 23:50:15 1999 +++ linux/fs/efs/inode.c Tue Jan 4 13:02:23 2000 @@ -131,16 +131,10 @@ inode->i_op = &efs_symlink_inode_operations; break; case S_IFCHR: - inode->i_rdev = device; - inode->i_op = &chrdev_inode_operations; - break; case S_IFBLK: - inode->i_rdev = device; - inode->i_op = &blkdev_inode_operations; - break; case S_IFIFO: - init_fifo(inode); - break; + init_special_inode(inode, inode->i_mode, device); + break; default: printk(KERN_WARNING "EFS: unsupported inode mode %o\n", inode->i_mode); goto read_inode_error; diff -u --recursive --new-file v2.3.35/linux/fs/exec.c linux/fs/exec.c --- v2.3.35/linux/fs/exec.c Mon Dec 20 18:48:22 1999 +++ linux/fs/exec.c Wed Dec 29 11:42:07 1999 @@ -261,6 +261,41 @@ 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; diff -u --recursive --new-file v2.3.35/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.3.35/linux/fs/ext2/super.c Wed Dec 29 13:13:20 1999 +++ linux/fs/ext2/super.c Wed Dec 29 11:44:40 1999 @@ -791,7 +791,7 @@ 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); } diff -u --recursive --new-file v2.3.35/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.3.35/linux/fs/filesystems.c Wed Dec 29 13:13:20 1999 +++ linux/fs/filesystems.c Mon Jan 3 12:01:31 2000 @@ -52,6 +52,10 @@ extern int init_devpts_fs(void); #endif +#ifdef CONFIG_SUN_OPENPROMFS +extern int init_openprom_fs(void); +#endif + void __init filesystem_setup(void) { #ifdef CONFIG_MINIX_FS diff -u --recursive --new-file v2.3.35/linux/fs/namei.c linux/fs/namei.c --- v2.3.35/linux/fs/namei.c Tue Dec 14 01:27:24 1999 +++ linux/fs/namei.c Sun Jan 2 00:48:58 2000 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -549,83 +550,6 @@ return -EEXIST; return permission(dir,MAY_WRITE | MAY_EXEC); } - -static inline struct dentry *get_parent(struct dentry *dentry) -{ - return dget(dentry->d_parent); -} - -static inline void unlock_dir(struct dentry *dir) -{ - up(&dir->d_inode->i_sem); - dput(dir); -} - -/* - * We need to do a check-parent every time - * after we have locked the parent - to verify - * that the parent is still our parent and - * that we are still hashed onto it.. - * - * This is requied in case two processes race - * on removing (or moving) the same entry: the - * parent lock will serialize them, but the - * other process will be too late.. - */ -#define check_parent(dir, dentry) \ - ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash)) - -/* - * Locking the parent is needed to: - * - serialize directory operations - * - make sure the parent doesn't change from - * under us in the middle of an operation. - * - * NOTE! Right now we'd rather use a "struct inode" - * for this, but as I expect things to move toward - * using dentries instead for most things it is - * probably better to start with the conceptually - * better interface of relying on a path of dentries. - */ -static inline struct dentry *lock_parent(struct dentry *dentry) -{ - struct dentry *dir = dget(dentry->d_parent); - - down(&dir->d_inode->i_sem); - return dir; -} - -/* - * Whee.. Deadlock country. Happily there are only two VFS - * operations that do this.. - */ -static inline void double_lock(struct dentry *d1, struct dentry *d2) -{ - struct semaphore *s1 = &d1->d_inode->i_sem; - struct semaphore *s2 = &d2->d_inode->i_sem; - - if (s1 != s2) { - if ((unsigned long) s1 < (unsigned long) s2) { - struct semaphore *tmp = s2; - s2 = s1; s1 = tmp; - } - down(s1); - } - down(s2); -} - -static inline void double_unlock(struct dentry *d1, struct dentry *d2) -{ - struct semaphore *s1 = &d1->d_inode->i_sem; - struct semaphore *s2 = &d2->d_inode->i_sem; - - up(s1); - if (s1 != s2) - up(s2); - dput(d1); - dput(d2); -} - /* * Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security diff -u --recursive --new-file v2.3.35/linux/fs/openpromfs/inode.c linux/fs/openpromfs/inode.c --- v2.3.35/linux/fs/openpromfs/inode.c Wed Dec 29 13:13:20 1999 +++ linux/fs/openpromfs/inode.c Tue Jan 4 11:17:47 2000 @@ -1,4 +1,4 @@ -/* $Id: inode.c,v 1.1 1999/12/20 12:23:44 jj Exp $ +/* $Id: inode.c,v 1.3 2000/01/04 10:02:29 jj Exp $ * openpromfs.c: /proc/openprom handling routines * * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) @@ -1097,6 +1097,7 @@ iput(root_inode); s->s_dev = 0; unlock_super(s); + MOD_DEC_USE_COUNT; return NULL; } @@ -1107,7 +1108,7 @@ NULL }; -static int init_openprom_fs(void) +int init_openprom_fs(void) { nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0); if (!nodes) { diff -u --recursive --new-file v2.3.35/linux/fs/super.c linux/fs/super.c --- v2.3.35/linux/fs/super.c Tue Dec 14 01:27:24 1999 +++ linux/fs/super.c Mon Jan 3 12:56:57 2000 @@ -181,7 +181,6 @@ return 0; } -#ifdef CONFIG_MODULES int unregister_filesystem(struct file_system_type * fs) { struct file_system_type ** tmp; @@ -197,7 +196,6 @@ } return -EINVAL; } -#endif static int fs_index(const char * __name) { diff -u --recursive --new-file v2.3.35/linux/fs/udf/inode.c linux/fs/udf/inode.c --- v2.3.35/linux/fs/udf/inode.c Tue Nov 23 22:42:21 1999 +++ linux/fs/udf/inode.c Tue Jan 4 13:02:23 2000 @@ -1147,19 +1147,18 @@ } case FILE_TYPE_BLOCK: { - inode->i_op = &blkdev_inode_operations; inode->i_mode |= S_IFBLK; break; } case FILE_TYPE_CHAR: { - inode->i_op = &chrdev_inode_operations; inode->i_mode |= S_IFCHR; break; } case FILE_TYPE_FIFO: { - init_fifo(inode); + init_special_inode(inode, inode->i_mode|S_FIFO, 0); + break; } case FILE_TYPE_SYMLINK: { @@ -1185,9 +1184,9 @@ if (dsea) { - inode->i_rdev = to_kdev_t( - (le32_to_cpu(dsea->majorDeviceIdent)) << 8) | - (le32_to_cpu(dsea->minorDeviceIdent) & 0xFF); + init_special_inode(inode, inode->i_mode, + ((le32_to_cpu(dsea->majorDeviceIdent)) << 8) | + (le32_to_cpu(dsea->minorDeviceIdent) & 0xFF)); /* Developer ID ??? */ udf_release_data(tbh); } diff -u --recursive --new-file v2.3.35/linux/fs/udf/namei.c linux/fs/udf/namei.c --- v2.3.35/linux/fs/udf/namei.c Tue Nov 23 22:42:21 1999 +++ linux/fs/udf/namei.c Tue Jan 4 13:02:23 2000 @@ -702,24 +702,7 @@ mark_inode_dirty(dir); dir->i_version = ++event; } - if (S_ISREG(inode->i_mode)) - { - inode->i_op = &udf_file_inode_operations; - } - else if (S_ISCHR(inode->i_mode)) - { - inode->i_op = &chrdev_inode_operations; - } - else if (S_ISBLK(inode->i_mode)) - { - inode->i_op = &blkdev_inode_operations; - } - else if (S_ISFIFO(inode->i_mode)) - { - init_fifo(inode); - } - if (S_ISBLK(mode) || S_ISCHR(mode)) - inode->i_rdev = to_kdev_t(rdev); + init_special_inode(inode, mode, rdev); mark_inode_dirty(inode); if (fibh.sbh != fibh.ebh) diff -u --recursive --new-file v2.3.35/linux/fs/ufs/namei.c linux/fs/ufs/namei.c --- v2.3.35/linux/fs/ufs/namei.c Tue Dec 14 01:27:24 1999 +++ linux/fs/ufs/namei.c Tue Jan 4 11:30:23 2000 @@ -764,7 +764,7 @@ err = -ENAMETOOLONG; l = strlen(symname)+1; - if (l > dir->i_sb->s_blocksize) + if (l > sb->s_blocksize) goto out; err = -EIO; @@ -774,8 +774,7 @@ } inode->i_mode = S_IFLNK | S_IRWXUGO; - /***if (l > sizeof (inode->u.ufs_i.i_data)) {***/ - if (1) { + if (l > sb->u.ufs_sb.s_uspi->s_maxsymlinklen) { /* slow symlink */ inode->i_op = &ufs_symlink_inode_operations; err = block_symlink(inode, symname, l); diff -u --recursive --new-file v2.3.35/linux/fs/ufs/super.c linux/fs/ufs/super.c --- v2.3.35/linux/fs/ufs/super.c Thu Nov 11 20:11:51 1999 +++ linux/fs/ufs/super.c Tue Jan 4 11:30:23 2000 @@ -497,6 +497,7 @@ uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; + uspi->s_maxsymlinklen = 56; flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN; break; @@ -507,6 +508,7 @@ uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; + uspi->s_maxsymlinklen = 56; flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN; break; @@ -760,6 +762,10 @@ uspi->s_bpf = uspi->s_fsize << 3; uspi->s_bpfshift = uspi->s_fshift + 3; uspi->s_bpfmask = uspi->s_bpf - 1; + if ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == + UFS_MOUNT_UFSTYPE_44BSD) + uspi->s_maxsymlinklen = + SWAB32(usb3->fs_u2.fs_44.fs_maxsymlinklen); sb->u.ufs_sb.s_flags = flags; sb->u.ufs_sb.s_swab = swab; diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h --- v2.3.35/linux/include/asm-sparc/dma.h Wed Dec 29 13:13:21 1999 +++ linux/include/asm-sparc/dma.h Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.34 1999/10/24 16:01:21 zaitcev Exp $ +/* $Id: dma.h,v 1.35 1999/12/27 06:37:09 anton Exp $ * include/asm-sparc/dma.h * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) @@ -16,6 +16,7 @@ #include #include #include +#include #include extern spinlock_t dma_spin_lock; diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v2.3.35/linux/include/asm-sparc/fcntl.h Tue Oct 27 09:52:21 1998 +++ linux/include/asm-sparc/fcntl.h Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.11 1998/10/26 20:03:10 davem Exp $ */ +/* $Id: fcntl.h,v 1.12 1999/12/27 06:37:11 anton Exp $ */ #ifndef _SPARC_FCNTL_H #define _SPARC_FCNTL_H @@ -19,6 +19,7 @@ #define O_NOCTTY 0x8000 /* not fcntl */ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ +#define O_LARGEFILE 0x40000 #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/pgalloc.h linux/include/asm-sparc/pgalloc.h --- v2.3.35/linux/include/asm-sparc/pgalloc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/pgalloc.h Mon Jan 3 12:01:31 2000 @@ -0,0 +1,157 @@ +/* $Id: pgalloc.h,v 1.1 1999/12/28 04:13:35 anton Exp $ */ +#ifndef _SPARC_PGALLOC_H +#define _SPARC_PGALLOC_H + +#include +#include + +#include +#include + +/* Fine grained cache/tlb flushing. */ +#ifdef __SMP__ +BTFIXUPDEF_CALL(void, local_flush_cache_all, void) +BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long) + +#define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)() +#define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm) +#define local_flush_cache_range(mm,start,end) BTFIXUP_CALL(local_flush_cache_range)(mm,start,end) +#define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr) + +BTFIXUPDEF_CALL(void, local_flush_tlb_all, void) +BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long) + +#define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)() +#define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm) +#define local_flush_tlb_range(mm,start,end) BTFIXUP_CALL(local_flush_tlb_range)(mm,start,end) +#define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr) + +BTFIXUPDEF_CALL(void, local_flush_page_to_ram, struct page *) +BTFIXUPDEF_CALL(void, local_flush_sig_insns, struct mm_struct *, unsigned long) + +#define local_flush_page_to_ram(page) BTFIXUP_CALL(local_flush_page_to_ram)(page) +#define local_flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(local_flush_sig_insns)(mm,insn_addr) + +extern void smp_flush_cache_all(void); +extern void smp_flush_cache_mm(struct mm_struct *mm); +extern void smp_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end); +extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page); + +extern void smp_flush_tlb_all(void); +extern void smp_flush_tlb_mm(struct mm_struct *mm); +extern void smp_flush_tlb_range(struct mm_struct *mm, + unsigned long start, + unsigned long end); +extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page); +extern void smp_flush_page_to_ram(struct page *page); +extern void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); +#endif + +BTFIXUPDEF_CALL(void, flush_cache_all, void) +BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, flush_cache_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long) + +#define flush_cache_all() BTFIXUP_CALL(flush_cache_all)() +#define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm) +#define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end) +#define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr) +#define flush_icache_range(start, end) do { } while (0) + +BTFIXUPDEF_CALL(void, flush_tlb_all, void) +BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *) +BTFIXUPDEF_CALL(void, flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) +BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long) + +#define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)() +#define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm) +#define flush_tlb_range(mm,start,end) BTFIXUP_CALL(flush_tlb_range)(mm,start,end) +#define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr) + +BTFIXUPDEF_CALL(void, flush_page_to_ram, struct page *) +BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long) + +#define flush_page_to_ram(page) BTFIXUP_CALL(flush_page_to_ram)(page) +#define flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(flush_sig_insns)(mm,insn_addr) + +extern struct pgtable_cache_struct { + unsigned long *pgd_cache; + unsigned long *pte_cache; + unsigned long pgtable_cache_sz; + unsigned long pgd_cache_sz; + spinlock_t pgd_spinlock; + spinlock_t pte_spinlock; +} pgt_quicklists; +#define pgd_quicklist (pgt_quicklists.pgd_cache) +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist (pgt_quicklists.pte_cache) +#define pgd_spinlock (pgt_quicklists.pgd_spinlock) +#define pte_spinlock (pgt_quicklists.pte_spinlock) +#define pgtable_cache_size (pgt_quicklists.pgtable_cache_sz) +#define pgd_cache_size (pgt_quicklists.pgd_cache_sz) + +BTFIXUPDEF_CALL(pte_t *, get_pte_fast, void) +BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void) +BTFIXUPDEF_CALL(void, free_pte_slow, pte_t *) +BTFIXUPDEF_CALL(void, free_pgd_slow, pgd_t *) +BTFIXUPDEF_CALL(int, do_check_pgt_cache, int, int) + +#define get_pte_fast() BTFIXUP_CALL(get_pte_fast)() +extern __inline__ pmd_t *get_pmd_fast(void) +{ + return (pmd_t *)0; +} +#define get_pgd_fast() BTFIXUP_CALL(get_pgd_fast)() +#define free_pte_slow(pte) BTFIXUP_CALL(free_pte_slow)(pte) +extern __inline__ void free_pmd_slow(pmd_t *pmd) +{ +} +#define free_pgd_slow(pgd) BTFIXUP_CALL(free_pgd_slow)(pgd) +#define do_check_pgt_cache(low,high) BTFIXUP_CALL(do_check_pgt_cache)(low,high) + +/* + * Allocate and free page tables. The xxx_kernel() versions are + * used to allocate a kernel page table - this turns on ASN bits + * if any, and marks the page tables reserved. + */ +BTFIXUPDEF_CALL(void, pte_free_kernel, pte_t *) +BTFIXUPDEF_CALL(pte_t *, pte_alloc_kernel, pmd_t *, unsigned long) + +#define pte_free_kernel(pte) BTFIXUP_CALL(pte_free_kernel)(pte) +#define pte_alloc_kernel(pmd,addr) BTFIXUP_CALL(pte_alloc_kernel)(pmd,addr) + +BTFIXUPDEF_CALL(void, pmd_free_kernel, pmd_t *) +BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_kernel, pgd_t *, unsigned long) + +#define pmd_free_kernel(pmd) BTFIXUP_CALL(pmd_free_kernel)(pmd) +#define pmd_alloc_kernel(pgd,addr) BTFIXUP_CALL(pmd_alloc_kernel)(pgd,addr) + +BTFIXUPDEF_CALL(void, pte_free, pte_t *) +BTFIXUPDEF_CALL(pte_t *, pte_alloc, pmd_t *, unsigned long) + +#define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) +#define pte_alloc(pmd,addr) BTFIXUP_CALL(pte_alloc)(pmd,addr) + +BTFIXUPDEF_CALL(void, pmd_free, pmd_t *) +BTFIXUPDEF_CALL(pmd_t *, pmd_alloc, pgd_t *, unsigned long) + +#define pmd_free(pmd) BTFIXUP_CALL(pmd_free)(pmd) +#define pmd_alloc(pgd,addr) BTFIXUP_CALL(pmd_alloc)(pgd,addr) + +BTFIXUPDEF_CALL(void, pgd_free, pgd_t *) +BTFIXUPDEF_CALL(pgd_t *, pgd_alloc, void) + +#define pgd_free(pgd) BTFIXUP_CALL(pgd_free)(pgd) +#define pgd_alloc() BTFIXUP_CALL(pgd_alloc)() + +BTFIXUPDEF_CALL(void, set_pgdir, unsigned long, pgd_t) + +#define set_pgdir(address,entry) BTFIXUP_CALL(set_pgdir)(address,entry) + +#endif /* _SPARC64_PGALLOC_H */ diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h --- v2.3.35/linux/include/asm-sparc/pgtable.h Wed Dec 29 13:13:21 1999 +++ linux/include/asm-sparc/pgtable.h Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.86 1999/12/16 14:41:19 anton Exp $ */ +/* $Id: pgtable.h,v 1.87 1999/12/27 06:37:14 anton Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -9,7 +9,6 @@ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include #include #include #include @@ -23,10 +22,11 @@ #include #include #include +#include + +#ifndef __ASSEMBLY__ extern void load_mmu(void); -extern int io_remap_page_range(unsigned long from, unsigned long to, - unsigned long size, pgprot_t prot, int space); BTFIXUPDEF_CALL(void, quick_kernel_fault, unsigned long) @@ -120,10 +120,6 @@ #define PAGE_READONLY __pgprot(BTFIXUP_INT(page_readonly)) #define PAGE_KERNEL __pgprot(BTFIXUP_INT(page_kernel)) -BTFIXUPDEF_CALL(void, set_pgdir, unsigned long, pgd_t) - -#define set_pgdir(address,entry) BTFIXUP_CALL(set_pgdir)(address,entry) - /* Top-level page directory */ extern pgd_t swapper_pg_dir[1024]; @@ -297,7 +293,7 @@ #define page_pte(page) page_pte_prot(page, __pgprot(0)) /* Permanent address of a page. */ -#define page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT)) +#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; }) #define pte_page(x) (mem_map+pte_pagenr(x)) /* @@ -342,149 +338,6 @@ /* Find an entry in the third-level page table.. */ #define pte_offset(dir,addr) BTFIXUP_CALL(pte_offset)(dir,addr) -extern struct pgtable_cache_struct { - unsigned long *pgd_cache; - unsigned long *pte_cache; - unsigned long pgtable_cache_sz; - unsigned long pgd_cache_sz; - spinlock_t pgd_spinlock; - spinlock_t pte_spinlock; -} pgt_quicklists; -#define pgd_quicklist (pgt_quicklists.pgd_cache) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist (pgt_quicklists.pte_cache) -#define pgd_spinlock (pgt_quicklists.pgd_spinlock) -#define pte_spinlock (pgt_quicklists.pte_spinlock) -#define pgtable_cache_size (pgt_quicklists.pgtable_cache_sz) -#define pgd_cache_size (pgt_quicklists.pgd_cache_sz) - -BTFIXUPDEF_CALL(pte_t *, get_pte_fast, void) -BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void) -BTFIXUPDEF_CALL(void, free_pte_slow, pte_t *) -BTFIXUPDEF_CALL(void, free_pgd_slow, pgd_t *) -BTFIXUPDEF_CALL(int, do_check_pgt_cache, int, int) - -#define get_pte_fast() BTFIXUP_CALL(get_pte_fast)() -extern __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} -#define get_pgd_fast() BTFIXUP_CALL(get_pgd_fast)() -#define free_pte_slow(pte) BTFIXUP_CALL(free_pte_slow)(pte) -extern __inline__ void free_pmd_slow(pmd_t *pmd) -{ -} -#define free_pgd_slow(pgd) BTFIXUP_CALL(free_pgd_slow)(pgd) -#define do_check_pgt_cache(low,high) BTFIXUP_CALL(do_check_pgt_cache)(low,high) - -/* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any, and marks the page tables reserved. - */ -BTFIXUPDEF_CALL(void, pte_free_kernel, pte_t *) -BTFIXUPDEF_CALL(pte_t *, pte_alloc_kernel, pmd_t *, unsigned long) - -#define pte_free_kernel(pte) BTFIXUP_CALL(pte_free_kernel)(pte) -#define pte_alloc_kernel(pmd,addr) BTFIXUP_CALL(pte_alloc_kernel)(pmd,addr) - -BTFIXUPDEF_CALL(void, pmd_free_kernel, pmd_t *) -BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_kernel, pgd_t *, unsigned long) - -#define pmd_free_kernel(pmd) BTFIXUP_CALL(pmd_free_kernel)(pmd) -#define pmd_alloc_kernel(pgd,addr) BTFIXUP_CALL(pmd_alloc_kernel)(pgd,addr) - -BTFIXUPDEF_CALL(void, pte_free, pte_t *) -BTFIXUPDEF_CALL(pte_t *, pte_alloc, pmd_t *, unsigned long) - -#define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) -#define pte_alloc(pmd,addr) BTFIXUP_CALL(pte_alloc)(pmd,addr) - -BTFIXUPDEF_CALL(void, pmd_free, pmd_t *) -BTFIXUPDEF_CALL(pmd_t *, pmd_alloc, pgd_t *, unsigned long) - -#define pmd_free(pmd) BTFIXUP_CALL(pmd_free)(pmd) -#define pmd_alloc(pgd,addr) BTFIXUP_CALL(pmd_alloc)(pgd,addr) - -BTFIXUPDEF_CALL(void, pgd_free, pgd_t *) -BTFIXUPDEF_CALL(pgd_t *, pgd_alloc, void) - -#define pgd_free(pgd) BTFIXUP_CALL(pgd_free)(pgd) -#define pgd_alloc() BTFIXUP_CALL(pgd_alloc)() - -/* Fine grained cache/tlb flushing. */ - -#ifdef __SMP__ -BTFIXUPDEF_CALL(void, local_flush_cache_all, void) -BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long) - -#define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)() -#define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm) -#define local_flush_cache_range(mm,start,end) BTFIXUP_CALL(local_flush_cache_range)(mm,start,end) -#define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr) - -BTFIXUPDEF_CALL(void, local_flush_tlb_all, void) -BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long) - -#define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)() -#define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm) -#define local_flush_tlb_range(mm,start,end) BTFIXUP_CALL(local_flush_tlb_range)(mm,start,end) -#define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr) - -BTFIXUPDEF_CALL(void, local_flush_page_to_ram, struct page *) -BTFIXUPDEF_CALL(void, local_flush_sig_insns, struct mm_struct *, unsigned long) - -#define local_flush_page_to_ram(page) BTFIXUP_CALL(local_flush_page_to_ram)(page) -#define local_flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(local_flush_sig_insns)(mm,insn_addr) - -extern void smp_flush_cache_all(void); -extern void smp_flush_cache_mm(struct mm_struct *mm); -extern void smp_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end); -extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page); - -extern void smp_flush_tlb_all(void); -extern void smp_flush_tlb_mm(struct mm_struct *mm); -extern void smp_flush_tlb_range(struct mm_struct *mm, - unsigned long start, - unsigned long end); -extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page); -extern void smp_flush_page_to_ram(struct page *page); -extern void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); -#endif - -BTFIXUPDEF_CALL(void, flush_cache_all, void) -BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, flush_cache_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long) - -#define flush_cache_all() BTFIXUP_CALL(flush_cache_all)() -#define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm) -#define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end) -#define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr) -#define flush_icache_range(start, end) do { } while (0) - -BTFIXUPDEF_CALL(void, flush_tlb_all, void) -BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *) -BTFIXUPDEF_CALL(void, flush_tlb_range, struct mm_struct *, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long) - -#define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)() -#define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm) -#define flush_tlb_range(mm,start,end) BTFIXUP_CALL(flush_tlb_range)(mm,start,end) -#define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr) - -BTFIXUPDEF_CALL(void, flush_page_to_ram, struct page *) -BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long) - -#define flush_page_to_ram(page) BTFIXUP_CALL(flush_page_to_ram)(page) -#define flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(flush_sig_insns)(mm,insn_addr) - /* The permissions for pgprot_val to make a page mapped on the obio space */ extern unsigned int pg_iobits; @@ -512,9 +365,12 @@ extern int invalid_segment; -#define SWP_TYPE(entry) (((entry) >> 2) & 0x7f) -#define SWP_OFFSET(entry) (((entry) >> 9) & 0x3ffff) -#define SWP_ENTRY(type,offset) ((((type) & 0x7f) << 2) | (((offset) & 0x3ffff) << 9)) +/* Encode and de-code a swap entry */ +#define SWP_TYPE(x) (((x).val >> 2) & 0x7f) +#define SWP_OFFSET(x) (((x).val >> 9) & 0x3ffff) +#define SWP_ENTRY(type,offset) ((swp_entry_t) { (((type) & 0x7f) << 2) | (((offset) & 0x3ffff) << 9) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) struct ctx_list { struct ctx_list *next; @@ -579,6 +435,12 @@ extern unsigned long *sparc_valid_addr_bitmap; /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ -#define kern_addr_valid(addr) (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap)) +#define kern_addr_valid(addr) \ + (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap)) + +extern int io_remap_page_range(unsigned long from, unsigned long to, + unsigned long size, pgprot_t prot, int space); + +#endif /* !(__ASSEMBLY__) */ #endif /* !(_SPARC_PGTABLE_H) */ diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h --- v2.3.35/linux/include/asm-sparc/sbus.h Wed Dec 29 13:13:21 1999 +++ linux/include/asm-sparc/sbus.h Mon Jan 3 12:01:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sbus.h,v 1.19 1999/10/25 06:17:56 zaitcev Exp $ +/* $Id: sbus.h,v 1.20 1999/12/27 06:37:17 anton Exp $ * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -108,7 +108,7 @@ /* All the rest use streaming mode mappings. */ extern u32 sbus_map_single(struct sbus_dev *, void *, long); extern void sbus_unmap_single(struct sbus_dev *, u32, long); -extern void sbus_map_sg(struct sbus_dev *, struct scatterlist *, int); +extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int); extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int); /* Finally, allow explicit synchronization of streamable mappings. */ diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/scatterlist.h linux/include/asm-sparc/scatterlist.h --- v2.3.35/linux/include/asm-sparc/scatterlist.h Wed Dec 29 13:13:21 1999 +++ linux/include/asm-sparc/scatterlist.h Mon Jan 3 12:01:31 2000 @@ -1,6 +1,8 @@ -/* $Id: scatterlist.h,v 1.3 1999/10/18 01:47:13 zaitcev Exp $ */ +/* $Id: scatterlist.h,v 1.4 1999/12/27 06:37:20 anton Exp $ */ #ifndef _SPARC_SCATTERLIST_H #define _SPARC_SCATTERLIST_H + +#include struct scatterlist { char * address; /* Location data is to be transferred to */ diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h --- v2.3.35/linux/include/asm-sparc/semaphore.h Wed May 12 08:41:15 1999 +++ linux/include/asm-sparc/semaphore.h Mon Jan 3 12:01:31 2000 @@ -208,6 +208,194 @@ : "g3", "g4", "g7", "memory", "cc"); } +/* rw mutexes (should that be mutices? =) -- throw rw + * spinlocks and semaphores together, and this is what we + * end up with... + * + * The lock is initialized to BIAS. This way, a writer + * subtracts BIAS ands gets 0 for the case of an uncontended + * lock. Readers decrement by 1 and see a positive value + * when uncontended, negative if there are writers waiting + * (in which case it goes to sleep). + * + * The value 0x01000000 supports up to 128 processors and + * lots of processes. BIAS must be chosen such that subtracting + * BIAS once per CPU will result in the int remaining + * negative. + * In terms of fairness, this should result in the lock + * flopping back and forth between readers and writers + * under heavy use. + * + * -ben + */ +#define RW_LOCK_BIAS 0x01000000 + +struct rw_semaphore { + int count; + unsigned char lock; + unsigned char read_not_granted; + unsigned char write_not_granted; + wait_queue_head_t wait; + wait_queue_head_t write_bias_wait; +#if WAITQUEUE_DEBUG + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +#if WAITQUEUE_DEBUG +#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif + +#define __RWSEM_INITIALIZER(name) \ +{ RW_LOCK_BIAS, 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ + __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } + +extern inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RW_LOCK_BIAS; + sem->lock = 0; + sem->read_not_granted = 0xff; + sem->write_not_granted = 0xff; + init_waitqueue_head(&sem->wait); + init_waitqueue_head(&sem->write_bias_wait); +#if WAITQUEUE_DEBUG + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +extern void ___down_read(/* Special calling convention */ void); +extern void ___down_write(/* Special calling convention */ void); +extern void ___up_read(/* Special calling convention */ void); +extern void ___up_write(/* Special calling convention */ void); + +extern inline void down_read(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___down_read) + : "g2", "g3", "g4", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (!sem->write_not_granted) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_inc(&sem->readers); +#endif +} + +extern inline void down_write(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___down_write) + : "g2", "g3", "g4", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (atomic_read(&sem->writers)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (!sem->read_not_granted) + BUG(); + if (!sem->write_not_granted) + BUG(); + atomic_inc(&sem->writers); +#endif +} + +/* When a reader does a release, the only significant + * case is when there was a writer waiting, and we've + * bumped the count to 0: we must wake the writer up. + */ +extern inline void __up_read(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___up_read) + : "g2", "g3", "g4", "g7", "memory", "cc"); +} + +/* releasing the writer is easy -- just release it and + * wake up any sleepers. + */ +extern inline void __up_write(struct rw_semaphore *sem) +{ + register atomic_t *ptr asm("g1"); + + ptr = (atomic_t *) __atomic_fool_gcc(sem); + + __asm__ __volatile__(" + mov %%o7, %%g4 + call %1 + add %%o7, 8, %%o7 + " + :: "r" (ptr), "i" (___up_write) + : "g2", "g3", "g4", "g7", "memory", "cc"); +} + +extern inline void up_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (!sem->write_not_granted) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_dec(&sem->readers); +#endif + __up_read(sem); +} + +extern inline void up_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (!sem->read_not_granted) + BUG(); + if (!sem->write_not_granted) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (atomic_read(&sem->writers) != 1) + BUG(); + atomic_dec(&sem->writers); +#endif + __up_write(sem); +} + #endif /* __KERNEL__ */ #endif /* !(_SPARC_SEMAPHORE_H) */ diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc/sfp-machine.h linux/include/asm-sparc/sfp-machine.h --- v2.3.35/linux/include/asm-sparc/sfp-machine.h Tue Dec 7 09:32:51 1999 +++ linux/include/asm-sparc/sfp-machine.h Mon Jan 3 12:01:31 2000 @@ -35,7 +35,7 @@ #define _FP_MUL_MEAT_D(R,X,Y) \ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) #define _FP_MUL_MEAT_Q(R,X,Y) \ - _FP_MUL_MEAT_5_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) + _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h --- v2.3.35/linux/include/asm-sparc64/semaphore.h Wed May 12 08:41:15 1999 +++ linux/include/asm-sparc64/semaphore.h Tue Jan 4 11:17:47 2000 @@ -5,6 +5,7 @@ #ifdef __KERNEL__ #include +#include #include struct semaphore { @@ -66,7 +67,7 @@ #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" + __asm__ __volatile__(" 1: lduw [%0], %%g5 sub %%g5, 1, %%g7 cas [%0], %%g5, %%g7 @@ -100,7 +101,7 @@ #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" + __asm__ __volatile__(" 1: lduw [%2], %%g5 sub %%g5, 1, %%g7 cas [%2], %%g5, %%g7 @@ -136,7 +137,7 @@ #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" + __asm__ __volatile__(" 1: lduw [%2], %%g5 sub %%g5, 1, %%g7 cas [%2], %%g5, %%g7 @@ -197,7 +198,262 @@ .previous\n" : : "r" (__atomic_fool_gcc(sem)), "i" (__up) : "g5", "g7", "memory", "cc"); -} +} + +/* rw mutexes (should that be mutices? =) -- throw rw + * spinlocks and semaphores together, and this is what we + * end up with... + * + * The lock is initialized to BIAS. This way, a writer + * subtracts BIAS ands gets 0 for the case of an uncontended + * lock. Readers decrement by 1 and see a positive value + * when uncontended, negative if there are writers waiting + * (in which case it goes to sleep). + * + * The value 0x01000000 supports up to 128 processors and + * lots of processes. BIAS must be chosen such that subtracting + * BIAS once per CPU will result in the int remaining + * negative. + * In terms of fairness, this should result in the lock + * flopping back and forth between readers and writers + * under heavy use. + * + * -ben + * + * Once we start supporting machines with more than 128 CPUs, + * we should go for using a 64bit atomic type instead of 32bit + * as counter. We shall probably go for bias 0x80000000 then, + * so that single sethi can set it. + * + * -jj + */ +#define RW_LOCK_BIAS 0x01000000 +#define RW_LOCK_BIAS_STR "0x01000000" + +struct rw_semaphore { + int count; + /* So that this does not have to be 64bit type, + * we'll use le bitops on it which use casa instead of casx. + * bit 0 means read bias granted + * bit 1 means write bias granted + */ + unsigned granted; + wait_queue_head_t wait; + wait_queue_head_t write_bias_wait; +#if WAITQUEUE_DEBUG + long __magic; + atomic_t readers; + atomic_t writers; +#endif +}; + +#if WAITQUEUE_DEBUG +#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0) +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif + +#define __RWSEM_INITIALIZER(name) \ +{ RW_LOCK_BIAS, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \ + __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT } + +extern inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RW_LOCK_BIAS; + sem->granted = 0; + init_waitqueue_head(&sem->wait); + init_waitqueue_head(&sem->write_bias_wait); +#if WAITQUEUE_DEBUG + sem->__magic = (long)&sem->__magic; + atomic_set(&sem->readers, 0); + atomic_set(&sem->writers, 0); +#endif +} + +extern void __down_read_failed(/* Special calling convention */ void); +extern void __down_write_failed(/* Special calling convention */ void); +extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers); + +extern inline void down_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + __asm__ __volatile__(" + 1: lduw [%0], %%g5 + subcc %%g5, 1, %%g7 + cas [%0], %%g5, %%g7 + bneg,pn %%icc, 3f + cmp %%g5, %%g7 + bne,pn %%icc, 1b + membar #StoreStore + 2: + .subsection 2 + 3: bne,pn %%icc, 1b + mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__down_read_failed) + : "g5", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (test_le_bit(1, &sem->granted)) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_inc(&sem->readers); +#endif +} + +extern inline void down_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + __asm__ __volatile__(" + 1: lduw [%0], %%g5 + sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 + subcc %%g5, %%g7, %%g7 + cas [%0], %%g5, %%g7 + bne,pn %%icc, 3f + cmp %%g5, %%g7 + bne,pn %%icc, 1b + membar #StoreStore + 2: + .subsection 2 + 3: bne,pn %%icc, 1b + mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__down_write_failed) + : "g5", "g7", "memory", "cc"); +#if WAITQUEUE_DEBUG + if (atomic_read(&sem->writers)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (test_le_bit(0, &sem->granted)) + BUG(); + if (test_le_bit(1, &sem->granted)) + BUG(); + atomic_inc(&sem->writers); +#endif +} + +/* When a reader does a release, the only significant + * case is when there was a writer waiting, and we've + * bumped the count to 0: we must wake the writer up. + */ +extern inline void __up_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__(" + membar #StoreLoad | #LoadLoad + 1: lduw [%0], %%g5 + addcc %%g5, 1, %%g7 + cas [%0], %%g5, %%g7 + be,pn %%icc, 3f + cmp %%g5, %%g7 + bne,pn %%icc, 1b + nop + 2: + .subsection 2 + 3: bne,pn %%icc, 1b + mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + clr %%o1 + mov %%g7, %%o0 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__rwsem_wake) + : "g5", "g7", "memory", "cc"); +} + +/* releasing the writer is easy -- just release it and + * wake up any sleepers. + */ +extern inline void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__(" + membar #StoreLoad | #LoadLoad + 1: lduw [%0], %%g5 + sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 + add %%g5, %%g7, %%g7 + cas [%0], %%g5, %%g7 + cmp %%g5, %%g7 + bne,pn %%icc, 1b + sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7 + addcc %%g5, %%g7, %%g5 + bcs,pn %%icc, 3f + nop + 2: + .subsection 2 + 3: mov %0, %%g7 + save %%sp, -160, %%sp + mov %%g1, %%l1 + mov %%g2, %%l2 + srl %%g5, 0, %%o1 + mov %%g7, %%o0 + call %1 + mov %%g3, %%l3 + mov %%l1, %%g1 + mov %%l2, %%g2 + ba,pt %%xcc, 2b + restore %%l3, %%g0, %%g3 + .previous\n" + : : "r" (__atomic_fool_gcc(sem)), "i" (__rwsem_wake) + : "g5", "g7", "memory", "cc"); +} + +extern inline void up_read(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (test_le_bit(1, &sem->granted)) + BUG(); + if (atomic_read(&sem->writers)) + BUG(); + atomic_dec(&sem->readers); +#endif + __up_read(sem); +} + +extern inline void up_write(struct rw_semaphore *sem) +{ +#if WAITQUEUE_DEBUG + if (test_le_bit(0, &sem->granted)) + BUG(); + if (test_le_bit(1, &sem->granted)) + BUG(); + if (atomic_read(&sem->readers)) + BUG(); + if (atomic_read(&sem->writers) != 1) + BUG(); + atomic_dec(&sem->writers); +#endif + __up_write(sem); +} #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.35/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h --- v2.3.35/linux/include/asm-sparc64/string.h Tue Oct 27 09:52:21 1998 +++ linux/include/asm-sparc64/string.h Mon Jan 3 12:01:31 2000 @@ -1,9 +1,9 @@ -/* $Id: string.h,v 1.14 1998/10/20 03:09:18 jj Exp $ +/* $Id: string.h,v 1.15 1999/12/23 17:02:20 jj Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997,1999 Jakub Jelinek (jakub@redhat.com) */ #ifndef __SPARC64_STRING_H__ @@ -21,7 +21,9 @@ extern __kernel_size_t __memcpy_entry(void *,const void *,__kernel_size_t,long,long); extern __kernel_size_t __memcpy_16plus(void *,const void *,__kernel_size_t,long,long); extern __kernel_size_t __memcpy_384plus(void *,const void *,__kernel_size_t,long,long); -extern __kernel_size_t __memset(void *,int,__kernel_size_t); +extern void *__memset(void *,int,__kernel_size_t); +extern void *__builtin_memcpy(void *,const void *,__kernel_size_t); +extern void *__builtin_memset(void *,int,__kernel_size_t); #ifndef EXPORT_SYMTAB_STROPS @@ -65,28 +67,24 @@ #define __HAVE_ARCH_MEMSET -extern inline void *__constant_memset(void *s, char c, __kernel_size_t count) +extern inline void *__constant_memset(void *s, int c, __kernel_size_t count) { extern __kernel_size_t __bzero(void *, __kernel_size_t); - if(!c) + if(!c) { __bzero(s, count); - else - __memset(s, c, count); - return s; -} - -extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count) -{ - __memset(s, c, count); - return s; + return s; + } else + return __memset(s, c, count); } #undef memset #define memset(s, c, count) \ -(__builtin_constant_p(c) ? \ - __constant_memset((s), (c), (count)) : \ - __nonconstant_memset((s), (c), (count))) +((__builtin_constant_p(count) && (count) <= 32) ? \ + __builtin_memset((s), (c), (count)) : \ + (__builtin_constant_p(c) ? \ + __constant_memset((s), (c), (count)) : \ + __memset((s), (c), (count)))) #define __HAVE_ARCH_MEMSCAN diff -u --recursive --new-file v2.3.35/linux/include/linux/arcdevice.h linux/include/linux/arcdevice.h --- v2.3.35/linux/include/linux/arcdevice.h Wed Aug 18 11:38:46 1999 +++ linux/include/linux/arcdevice.h Sun Jan 2 00:46:32 2000 @@ -1,59 +1,35 @@ /* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. NET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the ARCnet handlers. - * - * Version: $Id: arcdevice.h,v 1.3 1997/11/09 11:05:05 mj Exp $ - * - * Authors: Avery Pennarun - * David Woodhouse - * - * 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. + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions used by the ARCnet driver. + * + * Authors: Avery Pennarun and David Woodhouse + * + * 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. * */ #ifndef _LINUX_ARCDEVICE_H #define _LINUX_ARCDEVICE_H -#include +#include #include #ifdef __KERNEL__ -#define ARC_20020 1 -#define ARC_RIM_I 2 -#define ARC_90xx 3 -#define ARC_90xx_IO 4 - -#define MAX_ARCNET_DEVS 8 - - -/* The card sends the reconfiguration signal when it loses the connection to - * the rest of its network. It is a 'Hello, is anybody there?' cry. This - * usually happens when a new computer on the network is powered on or when - * the cable is broken. - * - * Define DETECT_RECONFIGS if you want to detect network reconfigurations. - * Recons may be a real nuisance on a larger ARCnet network; if you are a - * network administrator you probably would like to count them. - * Reconfigurations will be recorded in stats.tx_carrier_errors (the last - * field of the /proc/net/dev file). - * - * Define SHOW_RECONFIGS if you really want to see a log message whenever - * a RECON occurs. - */ -#define DETECT_RECONFIGS -#undef SHOW_RECONFIGS +#ifndef bool +#define bool int +#endif -/* RECON_THRESHOLD is the maximum number of RECON messages to receive within - * one minute before printing a "cabling problem" warning. You must have - * DETECT_RECONFIGS enabled if you want to use this. The default value - * should be fine. +/* + * RECON_THRESHOLD is the maximum number of RECON messages to receive + * within one minute before printing a "cabling problem" warning. The + * default value should be fine. * * After that, a "cabling restored" message will be printed on the next IRQ * if no RECON messages have been received for 10 seconds. @@ -63,47 +39,43 @@ #define RECON_THRESHOLD 30 -/* Define this to the minimum "timeout" value. If a transmit takes longer +/* + * Define this to the minimum "timeout" value. If a transmit takes longer * than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large * network, or one with heavy network traffic, this timeout may need to be * increased. The larger it is, though, the longer it will be between - * necessary transmits - don't set this too large. + * necessary transmits - don't set this too high. */ -#define TX_TIMEOUT (20*HZ/100) +#define TX_TIMEOUT (HZ * 200 / 1000) -/* Display warnings about the driver being an ALPHA version. - */ +/* Display warnings about the driver being an ALPHA version. */ #undef ALPHA_WARNING -/* New debugging bitflags: each option can be enabled individually. - * - * These can be set while the driver is running by typing: - * ifconfig arc0 down metric 1xxx HOSTNAME - * where 1xxx is 1000 + the debug level you want - * and HOSTNAME is your hostname/ip address - * and then resetting your routes. - * - * An ioctl() should be used for this instead, someday. - * +/* + * Debugging bitflags: each option can be enabled individually. + * * Note: only debug flags included in the ARCNET_DEBUG_MAX define will * actually be available. GCC will (at least, GCC 2.7.0 will) notice * lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize * them out. */ -#define D_NORMAL 1 /* important operational info */ -#define D_EXTRA 2 /* useful, but non-vital information */ -#define D_INIT 4 /* show init/probe messages */ -#define D_INIT_REASONS 8 /* show reasons for discarding probes */ +#define D_NORMAL 1 /* important operational info */ +#define D_EXTRA 2 /* useful, but non-vital information */ +#define D_INIT 4 /* show init/probe messages */ +#define D_INIT_REASONS 8 /* show reasons for discarding probes */ +#define D_RECON 32 /* print a message whenever token is lost */ +#define D_PROTO 64 /* debug auto-protocol support */ /* debug levels below give LOTS of output during normal operation! */ -#define D_DURING 16 /* trace operations (including irq's) */ -#define D_TX 32 /* show tx packets */ -#define D_RX 64 /* show rx packets */ -#define D_SKB 128 /* show skb's */ +#define D_DURING 128 /* trace operations (including irq's) */ +#define D_TX 256 /* show tx packets */ +#define D_RX 512 /* show rx packets */ +#define D_SKB 1024 /* show skb's */ +#define D_TIMING 2048 /* show time needed to copy buffers to card */ #ifndef ARCNET_DEBUG_MAX -#define ARCNET_DEBUG_MAX (~0) /* enable ALL debug messages */ +#define ARCNET_DEBUG_MAX (~0) /* enable ALL debug messages */ #endif #ifndef ARCNET_DEBUG @@ -115,240 +87,248 @@ #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x)) #define BUGMSG2(x,msg,args...) do { BUGLVL(x) printk(msg, ## args); } while (0) #define BUGMSG(x,msg,args...) \ - BUGMSG2(x,"%s%6s: " msg, \ - x==D_NORMAL ? KERN_WARNING : \ - x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \ - dev->name , ## args) - - -#define SETMASK AINTMASK(lp->intmask) - - /* Time needed to resetthe card - in jiffies. This works on my SMC - * PC100. I can't find a reference that tells me just how long I - * should wait. - */ -#define RESETtime (HZ * 3 / 10) /* reset */ - - /* these are the max/min lengths of packet data. (including - * ClientData header) - * note: packet sizes 250, 251, 252 are impossible (God knows why) - * so exception packets become necessary. - * - * These numbers are compared with the length of the full packet, - * including ClientData header. - */ -#define MTU 253 /* normal packet max size */ -#define MinTU 257 /* extended packet min size */ -#define XMTU 508 /* extended packet max size */ - - /* status/interrupt mask bit fields */ -#define TXFREEflag 0x01 /* transmitter available */ -#define TXACKflag 0x02 /* transmitted msg. ackd */ -#define RECONflag 0x04 /* system reconfigured */ -#define TESTflag 0x08 /* test flag */ -#define RESETflag 0x10 /* power-on-reset */ -#define RES1flag 0x20 /* reserved - usually set by jumper */ -#define RES2flag 0x40 /* reserved - usually set by jumper */ -#define NORXflag 0x80 /* receiver inhibited */ - - /* Flags used for IO-mapped memory operations */ -#define AUTOINCflag 0x40 /* Increase location with each access */ -#define IOMAPflag 0x02 /* (for 90xx) Use IO mapped memory, not mmap */ -#define ENABLE16flag 0x80 /* (for 90xx) Enable 16-bit mode */ - - /* in the command register, the following bits have these meanings: - * 0-2 command - * 3-4 page number (for enable rcv/xmt command) - * 7 receive broadcasts - */ -#define NOTXcmd 0x01 /* disable transmitter */ -#define NORXcmd 0x02 /* disable receiver */ -#define TXcmd 0x03 /* enable transmitter */ -#define RXcmd 0x04 /* enable receiver */ -#define CONFIGcmd 0x05 /* define configuration */ -#define CFLAGScmd 0x06 /* clear flags */ -#define TESTcmd 0x07 /* load test flags */ - - /* flags for "clear flags" command */ -#define RESETclear 0x08 /* power-on-reset */ -#define CONFIGclear 0x10 /* system reconfigured */ - - /* flags for "load test flags" command */ -#define TESTload 0x08 /* test flag (diagnostic) */ - - /* byte deposited into first address of buffers on reset */ -#define TESTvalue 0321 /* that's octal for 0xD1 :) */ - - /* for "enable receiver" command */ -#define RXbcasts 0x80 /* receive broadcasts */ - - /* flags for "define configuration" command */ -#define NORMALconf 0x00 /* 1-249 byte packets */ -#define EXTconf 0x08 /* 250-504 byte packets */ - - /* Starts receiving packets into recbuf. - */ -#define EnableReceiver() ACOMMAND(RXcmd|(recbuf<<3)|RXbcasts) + BUGMSG2(x, "%s%6s: " msg, \ + x==D_NORMAL ? KERN_WARNING \ + : x < D_DURING ? KERN_INFO : KERN_DEBUG, \ + dev->name , ## args) + +/* see how long a function call takes to run, expressed in CPU cycles */ +#define TIME(name, bytes, call) BUGLVL(D_TIMING) { \ + cycles_t _x, _y; \ + _x = get_cycles(); \ + call; \ + _y = get_cycles(); \ + BUGMSG(D_TIMING, \ + "%s: %d bytes in %lu cycles == " \ + "%lu Kbytes/100Mcycle\n",\ + name, bytes, _y - _x, \ + 100000000 / 1024 * bytes / (_y - _x + 1));\ + } \ + else { \ + call;\ + } + + +/* + * Time needed to reset the card - in ms (milliseconds). This works on my + * SMC PC100. I can't find a reference that tells me just how long I + * should wait. + */ +#define RESETtime (300) +/* + * These are the max/min lengths of packet payload, not including the + * arc_hardware header, but definitely including the soft header. + * + * Note: packet sizes 254, 255, 256 are impossible because of the way + * ARCnet registers work That's why RFC1201 defines "exception" packets. + * In non-RFC1201 protocols, we have to just tack some extra bytes on the + * end. + */ +#define MTU 253 /* normal packet max size */ +#define MinTU 257 /* extended packet min size */ +#define XMTU 508 /* extended packet max size */ + +/* status/interrupt mask bit fields */ +#define TXFREEflag 0x01 /* transmitter available */ +#define TXACKflag 0x02 /* transmitted msg. ackd */ +#define RECONflag 0x04 /* network reconfigured */ +#define TESTflag 0x08 /* test flag */ +#define RESETflag 0x10 /* power-on-reset */ +#define RES1flag 0x20 /* reserved - usually set by jumper */ +#define RES2flag 0x40 /* reserved - usually set by jumper */ +#define NORXflag 0x80 /* receiver inhibited */ + +/* Flags used for IO-mapped memory operations */ +#define AUTOINCflag 0x40 /* Increase location with each access */ +#define IOMAPflag 0x02 /* (for 90xx) Use IO mapped memory, not mmap */ +#define ENABLE16flag 0x80 /* (for 90xx) Enable 16-bit mode */ + +/* in the command register, the following bits have these meanings: + * 0-2 command + * 3-4 page number (for enable rcv/xmt command) + * 7 receive broadcasts + */ +#define NOTXcmd 0x01 /* disable transmitter */ +#define NORXcmd 0x02 /* disable receiver */ +#define TXcmd 0x03 /* enable transmitter */ +#define RXcmd 0x04 /* enable receiver */ +#define CONFIGcmd 0x05 /* define configuration */ +#define CFLAGScmd 0x06 /* clear flags */ +#define TESTcmd 0x07 /* load test flags */ + +/* flags for "clear flags" command */ +#define RESETclear 0x08 /* power-on-reset */ +#define CONFIGclear 0x10 /* system reconfigured */ + +/* flags for "load test flags" command */ +#define TESTload 0x08 /* test flag (diagnostic) */ + +/* byte deposited into first address of buffers on reset */ +#define TESTvalue 0321 /* that's octal for 0xD1 :) */ + +/* for "enable receiver" command */ +#define RXbcasts 0x80 /* receive broadcasts */ + +/* flags for "define configuration" command */ +#define NORMALconf 0x00 /* 1-249 byte packets */ +#define EXTconf 0x08 /* 250-504 byte packets */ + + +/* information needed to define an encapsulation driver */ +struct ArcProto { + char suffix; /* a for RFC1201, e for ether-encap, etc. */ + int mtu; /* largest possible packet */ + + void (*rx) (struct net_device * dev, int bufnum, + struct archdr * pkthdr, int length); + int (*build_header) (struct sk_buff * skb, unsigned short ethproto, + uint8_t daddr); + + /* these functions return '1' if the skb can now be freed */ + int (*prepare_tx) (struct net_device * dev, struct archdr * pkt, int length, + int bufnum); + int (*continue_tx) (struct net_device * dev, int bufnum); +}; +extern struct ArcProto *arc_proto_map[256], *arc_proto_default, *arc_bcast_proto; +extern struct ArcProto arc_proto_null; -#define JIFFER(time) for (delayval=jiffies+time; time_before(jiffies,delayval);) ; - /* a complete ARCnet packet */ -union ArcPacket -{ - struct archdr hardheader; /* the hardware header */ - u_char raw[512]; /* raw packet info, incl ClientData */ +/* + * "Incoming" is information needed for each address that could be sending + * to us. Mostly for partially-received split packets. + */ +struct Incoming { + struct sk_buff *skb; /* packet data buffer */ + uint16_t sequence; /* sequence number of assembly */ + uint8_t lastpacket, /* number of last packet (from 1) */ + numpackets; /* number of packets in split */ }; - /* the "client data" header - RFC1201 information - * notice that this screws up if it's not an even number of bytes - * - */ -struct ClientData -{ - /* data that's NOT part of real packet - we MUST get rid of it before - * actually sending!! - */ - u_char saddr, /* Source address - needed for IPX */ - daddr; /* Destination address */ - - /* data that IS part of real packet */ - u_char protocol_id, /* ARC_P_IP, ARC_P_ARP, etc */ - split_flag; /* for use with split packets */ - u_short sequence; /* sequence number */ +/* only needed for RFC1201 */ +struct Outgoing { + struct ArcProto *proto; /* protocol driver that owns this: + * if NULL, no packet is pending. + */ + struct sk_buff *skb; /* buffer from upper levels */ + struct archdr *pkt; /* a pointer into the skb */ + uint16_t length, /* bytes total */ + dataleft, /* bytes left */ + segnum, /* segment being sent */ + numsegs; /* number of segments */ }; -#define EXTRA_CLIENTDATA (sizeof(struct ClientData)-4) - /* the "client data" header - RFC1051 information - * this also screws up if it's not an even number of bytes - * - */ -struct S_ClientData -{ - /* data that's NOT part of real packet - we MUST get rid of it before - * actually sending!! - */ - u_char saddr, /* Source address - needed for IPX */ - daddr, /* Destination address */ - junk; /* padding to make an even length */ - - /* data that IS part of real packet */ - u_char protocol_id; /* ARC_P_IP, ARC_P_ARP, etc */ -}; -#define S_EXTRA_CLIENTDATA (sizeof(struct S_ClientData)-1) +struct arcnet_local { + struct net_device_stats stats; + uint8_t config, /* current value of CONFIG register */ + timeout, /* Extended timeout for COM20020 */ + backplane, /* Backplane flag for COM20020 */ + clock, /* COM20020 clock speed flag */ + setup, /* Contents of setup register */ + intmask; /* current value of INTMASK register */ + uint8_t default_proto[256]; /* default encap to use for each host */ + int cur_tx, /* buffer used by current transmit, or -1 */ + next_tx, /* buffer where a packet is ready to send */ + cur_rx; /* current receive buffer */ + int lastload_dest, /* can last loaded packet be acked? */ + lasttrans_dest; /* can last TX'd packet be acked? */ + int basename_len; /* name length without suffix ('arc0e' -> 4) */ + + /* + * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of + * which can be used for either sending or receiving. The new dynamic + * buffer management routines use a simple circular queue of available + * buffers, and take them as they're needed. This way, we simplify + * situations in which we (for example) want to pre-load a transmit + * buffer, or start receiving while we copy a received packet to + * memory. + * + * The rules: only the interrupt handler is allowed to _add_ buffers to + * the queue; thus, this doesn't require a lock. Both the interrupt + * handler and the transmit function will want to _remove_ buffers, so + * we need to handle the situation where they try to do it at the same + * time. + * + * If next_buf == first_free_buf, the queue is empty. Since there are + * only four possible buffers, the queue should never be full. + */ + atomic_t buf_lock; + int buf_queue[5]; + int next_buf, first_free_buf; + + /* network "reconfiguration" handling */ + time_t first_recon, /* time of "first" RECON message to count */ + last_recon; /* time of most recent RECON */ + int num_recons; /* number of RECONs between first and last. */ + bool network_down; /* do we think the network is down? */ + + struct { + uint16_t sequence; /* sequence number (incs with each packet) */ + uint16_t aborted_seq; + + struct Incoming incoming[256]; /* one from each address */ + } rfc1201; + + /* really only used by rfc1201, but we'll pretend it's not */ + struct Outgoing outgoing; /* packet currently being sent */ + + /* hardware-specific functions */ + struct { + void (*command) (struct net_device * dev, int cmd); + int (*status) (struct net_device * dev); + void (*intmask) (struct net_device * dev, int mask); + bool (*reset) (struct net_device * dev, bool really_reset); + void (*open_close) (struct net_device * dev, bool open); + void (*open_close_ll) (struct net_device * dev, bool open); + + void (*copy_to_card) (struct net_device * dev, int bufnum, int offset, + void *buf, int count); + void (*copy_from_card) (struct net_device * dev, int bufnum, int offset, + void *buf, int count); + } hw; -/* "Incoming" is information needed for each address that could be sending - * to us. Mostly for partially-received split packets. - */ -struct Incoming -{ - struct sk_buff *skb; /* packet data buffer */ - unsigned char lastpacket, /* number of last packet (from 1) */ - numpackets; /* number of packets in split */ - u_short sequence; /* sequence number of assembly */ + void *mem_start; /* pointer to ioremap'ed MMIO */ }; -struct Outgoing -{ - struct sk_buff *skb; /* buffer from upper levels */ - struct ClientData *hdr; /* clientdata of last packet */ - u_char *data; /* pointer to data in packet */ - short length, /* bytes total */ - dataleft, /* bytes left */ - segnum, /* segment being sent */ - numsegs, /* number of segments */ - seglen; /* length of segment */ -}; +#define ARCRESET(x) (lp->hw.reset(dev, (x))) +#define ACOMMAND(x) (lp->hw.command(dev, (x))) +#define ASTATUS() (lp->hw.status(dev)) +#define AINTMASK(x) (lp->hw.intmask(dev, (x))) +#define ARCOPEN(x) (lp->hw.open_close(dev, (x))) -struct arcnet_local { - struct net_device_stats stats; - u_short sequence; /* sequence number (incs with each packet) */ - u_short aborted_seq; - u_char stationid, /* our 8-bit station address */ - recbuf, /* receive buffer # (0 or 1) */ - txbuf, /* transmit buffer # (2 or 3) */ - txready, /* buffer where a packet is ready to send */ - config, /* current value of CONFIG register */ - timeout, /* Extended timeout for COM20020 */ - backplane, /* Backplane flag for COM20020 */ - setup, /* Contents of setup register */ - intmask; /* current value of INTMASK register */ - short intx, /* in TX routine? */ - in_txhandler, /* in TX_IRQ handler? */ - sending, /* transmit in progress? */ - lastload_dest, /* can last loaded packet be acked? */ - lasttrans_dest; /* can last TX'd packet be acked? */ - -#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD) - time_t first_recon, /* time of "first" RECON message to count */ - last_recon; /* time of most recent RECON */ - int num_recons, /* number of RECONs between first and last. */ - network_down; /* do we think the network is down? */ -#endif - - struct timer_list timer; /* the timer interrupt struct */ - struct Incoming incoming[256]; /* one from each address */ - struct Outgoing outgoing; /* packet currently being sent */ - - int card_type; - char *card_type_str; - - void (*inthandler) (struct net_device *dev); - int (*arcnet_reset) (struct net_device *dev, int reset_delay); - void (*asetmask) (struct net_device *dev, u_char mask); - void (*acommand) (struct net_device *dev, u_char command); - u_char (*astatus) (struct net_device *dev); - void (*en_dis_able_TX) (struct net_device *dev, int enable); - void (*prepare_tx)(struct net_device *dev,u_char *hdr,int hdrlen, - char *data,int length,int daddr,int exceptA, int offset); - void (*openclose_device)(int open); - - struct net_device *adev; /* RFC1201 protocol device */ - - /* These are last to ensure that the chipset drivers don't depend on the - * CONFIG_ARCNET_ETH and CONFIG_ARCNET_1051 options. - */ - -#ifdef CONFIG_ARCNET_ETH - struct net_device *edev; /* Ethernet-Encap device */ -#endif - -#ifdef CONFIG_ARCNET_1051 - struct net_device *sdev; /* RFC1051 protocol device */ -#endif -}; -/* Functions exported by arcnet.c - */ #if ARCNET_DEBUG_MAX & D_SKB -extern void arcnet_dump_skb(struct net_device *dev,struct sk_buff *skb, - char *desc); +void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); #else #define arcnet_dump_skb(dev,skb,desc) ; #endif #if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX) -extern void arcnet_dump_packet(struct net_device *dev,u_char *buffer,int ext, - char *desc); +void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc); #else -#define arcnet_dump_packet(dev,buffer,ext,desc) ; +#define arcnet_dump_packet(dev, bufnum, desc) ; #endif -extern void arcnet_tx_done(struct net_device *dev, struct arcnet_local *lp); -extern void arcnet_makename(char *device); -extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs); -extern void arcnet_setup(struct net_device *dev); -extern int arcnet_go_tx(struct net_device *dev,int enable_irq); -extern void arcnetA_continue_tx(struct net_device *dev); -extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr); -extern void arcnet_use_count(int open); +void arcnet_unregister_proto(struct ArcProto *proto); +void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); +void arcdev_setup(struct net_device *dev); +void arcnet_rx(struct net_device *dev, int bufnum); + +void arcnet_init(void); + +void arcnet_rfc1201_init(void); +void arcnet_rfc1051_init(void); +void arcnet_raw_init(void); + +int com90xx_probe(struct net_device *dev); +void com20020pci_probe_all(void); +#endif /* __KERNEL__ */ -#endif /* __KERNEL__ */ -#endif /* _LINUX_ARCDEVICE_H */ +#endif /* _LINUX_ARCDEVICE_H */ diff -u --recursive --new-file v2.3.35/linux/include/linux/com20020.h linux/include/linux/com20020.h --- v2.3.35/linux/include/linux/com20020.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/com20020.h Thu Dec 30 11:51:26 1999 @@ -0,0 +1,85 @@ +/* + * Linux ARCnet driver - COM20020 chipset support - function declarations + * + * Written 1997 by David Woodhouse. + * Written 1994-1999 by Avery Pennarun. + * Derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#ifndef __COM20020_H +#define __COM20020_H + +int com20020_check(struct net_device *dev); +int com20020_found(struct net_device *dev, int shared); + +/* The number of low I/O ports used by the card. */ +#define ARCNET_TOTAL_SIZE 9 + +/* various register addresses */ +#define _INTMASK (ioaddr+0) /* writable */ +#define _STATUS (ioaddr+0) /* readable */ +#define _COMMAND (ioaddr+1) /* standard arcnet commands */ +#define _DIAGSTAT (ioaddr+1) /* diagnostic status register */ +#define _ADDR_HI (ioaddr+2) /* control registers for IO-mapped memory */ +#define _ADDR_LO (ioaddr+3) +#define _MEMDATA (ioaddr+4) /* data port for IO-mapped memory */ +#define _CONFIG (ioaddr+6) /* configuration register */ +#define _SETUP (ioaddr+7) /* setup register */ + +/* in the ADDR_HI register */ +#define RDDATAflag 0x80 /* next access is a read (not a write) */ + +/* in the DIAGSTAT register */ +#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */ + +/* in the CONFIG register */ +#define RESETcfg 0x80 /* put card in reset state */ +#define TXENcfg 0x20 /* enable TX */ + +/* in SETUP register */ +#define PROMISCset 0x10 /* enable RCV_ALL */ + +#define REGTENTID (lp->config &= ~3); +#define REGNID (lp->config = (lp->config&~2)|1); +#define REGSETUP (lp->config = (lp->config&~1)|2); +#define REGNXTID (lp->config |= 3); + +#undef ARCRESET +#undef ASTATUS +#undef ACOMMAND +#undef AINTMASK + +#define ARCRESET { outb(lp->config | 0x80, _CONFIG); \ + udelay(5); \ + outb(lp->config , _CONFIG); \ + } +#define ARCRESET0 { outb(0x18 | 0x80, _CONFIG); \ + udelay(5); \ + outb(0x18 , _CONFIG); \ + } + +#define ASTATUS() inb(_STATUS) +#define ACOMMAND(cmd) outb((cmd),_COMMAND) +#define AINTMASK(msk) outb((msk),_INTMASK) + +#define SETCONF(cfg) outb(cfg, _CONFIG) + +#endif /* __COM20020_H */ diff -u --recursive --new-file v2.3.35/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v2.3.35/linux/include/linux/ext2_fs.h Tue Dec 14 01:27:24 1999 +++ linux/include/linux/ext2_fs.h Wed Dec 29 11:46:00 1999 @@ -597,7 +597,6 @@ 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 */ diff -u --recursive --new-file v2.3.35/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.3.35/linux/include/linux/fs.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/fs.h Tue Jan 4 13:33:20 2000 @@ -749,14 +749,12 @@ extern int blkdev_open(struct inode *, struct file *); extern int blkdev_release (struct inode *); extern struct file_operations def_blk_fops; -extern struct inode_operations blkdev_inode_operations; /* fs/devices.c */ extern int register_chrdev(unsigned int, const char *, struct file_operations *); extern int unregister_chrdev(unsigned int, const char *); extern int chrdev_open(struct inode *, struct file *); extern struct file_operations def_chr_fops; -extern struct inode_operations chrdev_inode_operations; extern char * bdevname(kdev_t); extern char * cdevname(kdev_t); extern char * kdevname(kdev_t); @@ -995,6 +993,91 @@ extern int inode_change_ok(struct inode *, struct iattr *); extern void inode_setattr(struct inode *, struct iattr *); + +/* + * Common dentry functions for inclusion in the VFS + * or in other stackable file systems. Some of these + * functions were in linux/fs/ C (VFS) files. + * + */ + +/* + * We need to do a check-parent every time + * after we have locked the parent - to verify + * that the parent is still our parent and + * that we are still hashed onto it.. + * + * This is required in case two processes race + * on removing (or moving) the same entry: the + * parent lock will serialize them, but the + * other process will be too late.. + */ +#define check_parent(dir, dentry) \ + ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash)) + +/* + * Locking the parent is needed to: + * - serialize directory operations + * - make sure the parent doesn't change from + * under us in the middle of an operation. + * + * NOTE! Right now we'd rather use a "struct inode" + * for this, but as I expect things to move toward + * using dentries instead for most things it is + * probably better to start with the conceptually + * better interface of relying on a path of dentries. + */ +static inline struct dentry *lock_parent(struct dentry *dentry) +{ + struct dentry *dir = dget(dentry->d_parent); + + down(&dir->d_inode->i_sem); + return dir; +} + +static inline struct dentry *get_parent(struct dentry *dentry) +{ + return dget(dentry->d_parent); +} + +static inline void unlock_dir(struct dentry *dir) +{ + up(&dir->d_inode->i_sem); + dput(dir); +} + +/* + * Whee.. Deadlock country. Happily there are only two VFS + * operations that does this.. + */ +static inline void double_lock(struct dentry *d1, struct dentry *d2) +{ + struct semaphore *s1 = &d1->d_inode->i_sem; + struct semaphore *s2 = &d2->d_inode->i_sem; + + if (s1 != s2) { + if ((unsigned long) s1 < (unsigned long) s2) { + struct semaphore *tmp = s2; + s2 = s1; s1 = tmp; + } + down(s1); + } + down(s2); +} + +static inline void double_unlock(struct dentry *d1, struct dentry *d2) +{ + struct semaphore *s1 = &d1->d_inode->i_sem; + struct semaphore *s2 = &d2->d_inode->i_sem; + + up(s1); + if (s1 != s2) + up(s2); + dput(d1); + dput(d2); +} + + #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.35/linux/include/linux/i2c-algo-bit.h linux/include/linux/i2c-algo-bit.h --- v2.3.35/linux/include/linux/i2c-algo-bit.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/i2c-algo-bit.h Wed Dec 29 17:08:55 1999 @@ -21,6 +21,8 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ +/* $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 diff -u --recursive --new-file v2.3.35/linux/include/linux/i2c-algo-pcf.h linux/include/linux/i2c-algo-pcf.h --- v2.3.35/linux/include/linux/i2c-algo-pcf.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/i2c-algo-pcf.h Wed Dec 29 17:08:55 1999 @@ -22,6 +22,8 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ +/* $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 diff -u --recursive --new-file v2.3.35/linux/include/linux/i2c-dev.h linux/include/linux/i2c-dev.h --- v2.3.35/linux/include/linux/i2c-dev.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/i2c-dev.h Wed Dec 29 17:08:55 1999 @@ -19,6 +19,8 @@ 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 diff -u --recursive --new-file v2.3.35/linux/include/linux/i2c-elektor.h linux/include/linux/i2c-elektor.h --- v2.3.35/linux/include/linux/i2c-elektor.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/i2c-elektor.h Wed Dec 29 17:08:55 1999 @@ -22,6 +22,8 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ +/* $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 diff -u --recursive --new-file v2.3.35/linux/include/linux/i2c-id.h linux/include/linux/i2c-id.h --- v2.3.35/linux/include/linux/i2c-id.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/i2c-id.h Wed Dec 29 17:08:55 1999 @@ -19,8 +19,8 @@ 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 @@ -71,6 +71,8 @@ #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 @@ -113,6 +115,7 @@ #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 */ diff -u --recursive --new-file v2.3.35/linux/include/linux/i2c.h linux/include/linux/i2c.h --- v2.3.35/linux/include/linux/i2c.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/i2c.h Wed Dec 29 17:08:55 1999 @@ -19,12 +19,12 @@ 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 and Frodo Looijaard */ +/* $Id: i2c.h,v 1.32 1999/12/21 23:45:58 frodo Exp $ */ + #ifndef I2C_H #define I2C_H @@ -324,6 +324,10 @@ 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 @@ -427,6 +431,10 @@ /* 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 */ diff -u --recursive --new-file v2.3.35/linux/include/linux/if_arcnet.h linux/include/linux/if_arcnet.h --- v2.3.35/linux/include/linux/if_arcnet.h Sat Sep 6 10:05:42 1997 +++ linux/include/linux/if_arcnet.h Thu Dec 30 11:51:26 1999 @@ -1,63 +1,119 @@ /* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. * - * Global definitions for the ARCnet interface. + * Global definitions for the ARCnet interface. * - * Version: $Id: if_arcnet.h,v 1.2 1997/09/05 08:57:54 mj Exp $ + * Authors: David Woodhouse and Avery Pennarun * - * Author: David Woodhouse - * Avery Pennarun - * - * 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. */ - + #ifndef _LINUX_IF_ARCNET_H #define _LINUX_IF_ARCNET_H +#include + /* - * These are the defined ARCnet Protocol ID's. + * These are the defined ARCnet Protocol ID's. */ - /* RFC1201 Protocol ID's */ -#define ARC_P_IP 212 /* 0xD4 */ -#define ARC_P_ARP 213 /* 0xD5 */ -#define ARC_P_RARP 214 /* 0xD6 */ -#define ARC_P_IPX 250 /* 0xFA */ -#define ARC_P_NOVELL_EC 236 /* 0xEC */ - - /* Old RFC1051 Protocol ID's */ -#define ARC_P_IP_RFC1051 240 /* 0xF0 */ -#define ARC_P_ARP_RFC1051 241 /* 0xF1 */ +/* RFC1201 Protocol ID's */ +#define ARC_P_IP 212 /* 0xD4 */ +#define ARC_P_ARP 213 /* 0xD5 */ +#define ARC_P_RARP 214 /* 0xD6 */ +#define ARC_P_IPX 250 /* 0xFA */ +#define ARC_P_NOVELL_EC 236 /* 0xEC */ + +/* Old RFC1051 Protocol ID's */ +#define ARC_P_IP_RFC1051 240 /* 0xF0 */ +#define ARC_P_ARP_RFC1051 241 /* 0xF1 */ - /* MS LanMan/WfWg protocol */ -#define ARC_P_ETHER 0xE8 +/* MS LanMan/WfWg "NDIS" encapsulation */ +#define ARC_P_ETHER 232 /* 0xE8 */ - /* Unsupported/indirectly supported protocols */ +/* Unsupported/indirectly supported protocols */ #define ARC_P_DATAPOINT_BOOT 0 /* very old Datapoint equipment */ #define ARC_P_DATAPOINT_MOUNT 1 #define ARC_P_POWERLAN_BEACON 8 /* Probably ATA-Netbios related */ -#define ARC_P_POWERLAN_BEACON2 243 -#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */ -#define ARC_P_ATALK 0xDD +#define ARC_P_POWERLAN_BEACON2 243 /* 0xF3 */ +#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */ +#define ARC_P_ATALK 0xDD + +/* + * The RFC1201-specific components of an arcnet packet header. + */ +struct arc_rfc1201 +{ + uint8_t proto; /* protocol ID field - varies */ + uint8_t split_flag; /* for use with split packets */ + uint16_t sequence; /* sequence number */ + uint8_t payload[0]; /* space remaining in packet (504 bytes)*/ +}; +#define RFC1201_HDR_SIZE 4 /* - * This is an ARCnet frame header. + * The RFC1051-specific components. */ +struct arc_rfc1051 +{ + uint8_t proto; /* ARC_P_RFC1051_ARP/RFC1051_IP */ + uint8_t payload[0]; /* 507 bytes */ +}; +#define RFC1051_HDR_SIZE 1 + -struct archdr /* was struct HardHeader */ +/* + * The ethernet-encap-specific components. We have a real ethernet header + * and some data. + */ +struct arc_eth_encap +{ + uint8_t proto; /* Always ARC_P_ETHER */ + struct ethhdr eth; /* standard ethernet header (yuck!) */ + uint8_t payload[0]; /* 493 bytes */ +}; +#define ETH_ENCAP_HDR_SIZE 14 + + +/* + * The data needed by the actual arcnet hardware. + * + * Now, in the real arcnet hardware, the third and fourth bytes are the + * 'offset' specification instead of the length, and the soft data is at + * the _end_ of the 512-byte buffer. We hide this complexity inside the + * driver. + */ +struct arc_hardware { - u_char source, /* source ARCnet - filled in automagically */ - destination, /* destination ARCnet - 0 for broadcast */ - offset1, /* offset of ClientData (256-byte packets) */ - offset2; /* offset of ClientData (512-byte packets) */ + uint8_t source, /* source ARCnet - filled in automagically */ + dest, /* destination ARCnet - 0 for broadcast */ + offset[2]; /* offset bytes (some weird semantics) */ +}; +#define ARC_HDR_SIZE 4 +/* + * This is an ARCnet frame header, as seen by the kernel (and userspace, + * when you do a raw packet capture). + */ +struct archdr +{ + /* hardware requirements */ + struct arc_hardware hard; + + /* arcnet encapsulation-specific bits */ + union { + struct arc_rfc1201 rfc1201; + struct arc_rfc1051 rfc1051; + struct arc_eth_encap eth_encap; + uint8_t raw[0]; /* 508 bytes */ + } soft; }; -#endif /* _LINUX_IF_ARCNET_H */ +#endif /* _LINUX_IF_ARCNET_H */ diff -u --recursive --new-file v2.3.35/linux/include/linux/init.h linux/include/linux/init.h --- v2.3.35/linux/include/linux/init.h Sun Nov 7 16:37:34 1999 +++ linux/include/linux/init.h Thu Dec 30 10:13:01 1999 @@ -94,8 +94,8 @@ #define __FINIT #define __INITDATA -/* Not sure what version aliases were introduced in, but certainly in 2.95. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +/* Not sure what version aliases were introduced in, but certainly in 2.91.66. */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91) #define module_init(x) int init_module(void) __attribute__((alias(#x))); #define module_exit(x) void cleanup_module(void) __attribute__((alias(#x))); #else diff -u --recursive --new-file v2.3.35/linux/include/linux/input.h linux/include/linux/input.h --- v2.3.35/linux/include/linux/input.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/input.h Tue Jan 4 12:21:40 2000 @@ -0,0 +1,443 @@ +#ifndef _INPUT_H +#define _INPUT_H + +/* + * input.h Version 0.1 + * + * Copyright (c) 1999 Vojtech Pavlik + * + * Sponsored by SuSE + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + */ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +/* + * The event structure itself + */ + +struct input_event { + struct timeval time; + unsigned short type; + unsigned short code; + unsigned int value; +}; + +/* + * Event types + */ + +#define EV_RST 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_MAX 0x1f + +/* + * Keys and buttons + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 + +#define KEY_F13 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_F14 89 +#define KEY_F15 90 +#define KEY_F16 91 +#define KEY_F17 92 +#define KEY_F18 93 +#define KEY_F19 94 +#define KEY_F20 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_F21 120 +#define KEY_F22 121 +#define KEY_F23 122 +#define KEY_F24 123 +#define KEY_JPN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 +#define KEY_AGAIN 129 +#define KEY_PROPS 130 +#define KEY_UNDO 131 +#define KEY_FRONT 132 +#define KEY_COPY 133 +#define KEY_OPEN 134 +#define KEY_PASTE 135 +#define KEY_FIND 136 +#define KEY_CUT 137 +#define KEY_HELP 138 +#define KEY_MENU 139 +#define KEY_CALC 140 +#define KEY_SETUP 141 +#define KEY_SLEEP 142 + +#define KEY_WAKEUP 143 +#define KEY_FILE 144 +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 + +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 + +#define KEY_UNKNOWN 192 + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_BASE 0x125 +#define BTN_BASE2 0x126 +#define BTN_BASE3 0x127 +#define BTN_BASE4 0x128 +#define BTN_BASE5 0x129 + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c + +#define KEY_MAX 0x1ff + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_MISC 0x18 +#define ABS_MAX 0x1f + +/* + * LEDs + */ + +#define LED_SCROLLL 0x00 +#define LED_NUML 0x01 +#define LED_CAPSL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_MAX 0x0f + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_MAX 0x07 + +#ifdef __KERNEL__ + +/* + * In-kernel definitions. + */ + +#include + +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define BIT(x) (1<<((x)%BITS_PER_LONG)) +#define LONG(x) ((x)/BITS_PER_LONG) + +struct input_dev { + + void *private; + + int number; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + + unsigned char *keycode; + unsigned int repeat_key; + struct timer_list timer; + + int abs[ABS_MAX + 1]; + int rep[REP_MAX + 1]; + + unsigned long key[NBITS(KEY_MAX)]; + unsigned long led[NBITS(LED_MAX)]; + unsigned long snd[NBITS(SND_MAX)]; + + int absmax[ABS_MAX + 1]; + int absmin[ABS_MAX + 1]; + int absfuzz[ABS_MAX + 1]; + int absflat[ABS_MAX + 1]; + + int (*open)(struct input_dev *dev); + void (*close)(struct input_dev *dev); + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + + struct input_handle *handle; + struct input_dev *next; +}; + +struct input_handler { + + void *private; + + void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); + int (*connect)(struct input_handler *handler, struct input_dev *dev); + void (*disconnect)(struct input_handle *handle); + + struct input_handle *handle; + + struct input_handler *next; +}; + +struct input_handle { + + void *private; + + struct input_dev *dev; + struct input_handler *handler; + + struct input_handle *dnext; + struct input_handle *hnext; +}; + +int keybdev_init(void); +int mousedev_init(void); +int joydev_init(void); +int evdev_init(void); + +void input_register_device(struct input_dev *); +void input_unregister_device(struct input_dev *); + +void input_register_handler(struct input_handler *); +void input_unregister_handler(struct input_handler *); + +void input_open_device(struct input_handle *); +void input_close_device(struct input_handle *); + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); + +#define input_report_key(a,b,c) input_event(a, EV_KEY, b, c) +#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) +#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) + +#endif +#endif diff -u --recursive --new-file v2.3.35/linux/include/linux/irda.h linux/include/linux/irda.h --- v2.3.35/linux/include/linux/irda.h Wed Dec 29 13:13:21 1999 +++ linux/include/linux/irda.h Wed Dec 29 17:08:55 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * 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 * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -83,20 +83,21 @@ #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 IRTTP_QOS_SET 6 -#define IRTTP_QOS_GET 7 -#define IRTTP_MAX_SDU_SIZE 8 +#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_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 */ diff -u --recursive --new-file v2.3.35/linux/include/linux/ixjuser.h linux/include/linux/ixjuser.h --- v2.3.35/linux/include/linux/ixjuser.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/ixjuser.h Wed Dec 29 17:13:02 1999 @@ -0,0 +1,629 @@ +/* + * 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, + * + * Contributors: Greg Herlein, + * David W. Erhart, + * John Sellers, + * Mike Preston, + * + * 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 + +/*************************************************************************** + + 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) diff -u --recursive --new-file v2.3.35/linux/include/linux/major.h linux/include/linux/major.h --- v2.3.35/linux/include/linux/major.h Sun Nov 7 16:37:34 1999 +++ linux/include/linux/major.h Wed Dec 29 17:13:02 1999 @@ -117,6 +117,8 @@ #define AURORA_MAJOR 79 +#define PHONE_MAJOR 100 + #define RTF_MAJOR 150 #define RAW_MAJOR 162 diff -u --recursive --new-file v2.3.35/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.3.35/linux/include/linux/mm.h Tue Dec 14 01:27:24 1999 +++ linux/include/linux/mm.h Tue Jan 4 13:33:29 2000 @@ -376,8 +376,6 @@ 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); @@ -439,6 +437,15 @@ extern unsigned long page_unuse(struct page *); extern int shrink_mmap(int, int); extern void truncate_inode_pages(struct inode *, loff_t); + +/* generic vm_area_ops exported for stackable file systems */ +extern int filemap_swapout(struct page * page, struct file *file); +extern pte_t filemap_swapin(struct vm_area_struct * vma, + unsigned long offset, unsigned long entry); +extern int filemap_sync(struct vm_area_struct * vma, unsigned long address, + size_t size, unsigned int flags); +extern struct page *filemap_nopage(struct vm_area_struct * area, + unsigned long address, int no_share); /* * GFP bitmasks.. diff -u --recursive --new-file v2.3.35/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.3.35/linux/include/linux/pci.h Wed Dec 29 13:13:21 1999 +++ linux/include/linux/pci.h Tue Jan 4 13:33:19 2000 @@ -478,6 +478,7 @@ int pci_write_config_word(struct pci_dev *dev, int where, u16 val); int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); +int pci_setup_device(struct pci_dev * dev); int pci_enable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); int pci_set_power_state(struct pci_dev *dev, int state); diff -u --recursive --new-file v2.3.35/linux/include/linux/phonedev.h linux/include/linux/phonedev.h --- v2.3.35/linux/include/linux/phonedev.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/phonedev.h Wed Dec 29 17:13:02 1999 @@ -0,0 +1,26 @@ +#ifndef __LINUX_PHONEDEV_H +#define __LINUX_PHONEDEV_H + +#include +#include + +#ifdef __KERNEL__ + +#include + +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 diff -u --recursive --new-file v2.3.35/linux/include/linux/telephony.h linux/include/linux/telephony.h --- v2.3.35/linux/include/linux/telephony.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/telephony.h Wed Dec 29 17:13:02 1999 @@ -0,0 +1,200 @@ +/* + * 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, + * Greg Herlein, + * + * Contributors: Alan Cox, + * David Erhart, + * + * 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 */ diff -u --recursive --new-file v2.3.35/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.3.35/linux/include/linux/tty.h Wed Oct 27 16:34:12 1999 +++ linux/include/linux/tty.h Tue Jan 4 13:33:23 2000 @@ -117,6 +117,9 @@ #define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */ +#define VIDEO_TYPE_SGI 0x70 /* Various SGI graphics hardware */ +#define VIDEO_TYPE_MIPS_G364 0x71 /* MIPS Magnum 4000 G364 video */ + /* * This character is the same as _POSIX_VDISABLE: it cannot be used as * a c_cc[] character, but indicates that a particular special character diff -u --recursive --new-file v2.3.35/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h --- v2.3.35/linux/include/linux/ufs_fs_sb.h Sat Aug 7 11:17:08 1999 +++ linux/include/linux/ufs_fs_sb.h Tue Jan 4 11:30:23 2000 @@ -107,6 +107,8 @@ __u32 s_bpf; /* bits per fragment */ __u32 s_bpfshift; /* bits per fragment shift*/ __u32 s_bpfmask; /* bits per fragment mask */ + + __u32 s_maxsymlinklen;/* upper limit on fast symlinks' size */ }; diff -u --recursive --new-file v2.3.35/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.3.35/linux/include/linux/videodev.h Tue Dec 7 09:32:51 1999 +++ linux/include/linux/videodev.h Wed Dec 29 17:08:55 1999 @@ -235,6 +235,17 @@ 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 @@ -284,14 +295,17 @@ #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 */ diff -u --recursive --new-file v2.3.35/linux/include/net/br.h linux/include/net/br.h --- v2.3.35/linux/include/net/br.h Wed Dec 29 13:13:21 1999 +++ linux/include/net/br.h Tue Jan 4 09:41:45 2000 @@ -1,3 +1,4 @@ +#include /* * Constants and structure definitions for the bridging code */ diff -u --recursive --new-file v2.3.35/linux/include/net/irda/irlap_event.h linux/include/net/irda/irlap_event.h --- v2.3.35/linux/include/net/irda/irlap_event.h Wed Dec 29 13:13:21 1999 +++ linux/include/net/irda/irlap_event.h Tue Jan 4 13:33:15 2000 @@ -7,7 +7,7 @@ * Status: Experimental. * Author: Dag Brattli * 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 * * Copyright (c) 1998-1999 Dag Brattli , @@ -80,14 +80,20 @@ 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, diff -u --recursive --new-file v2.3.35/linux/include/net/irda/irlap_frame.h linux/include/net/irda/irlap_frame.h --- v2.3.35/linux/include/net/irda/irlap_frame.h Wed Dec 29 13:13:21 1999 +++ linux/include/net/irda/irlap_frame.h Tue Jan 4 13:33:15 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * 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 * * Copyright (c) 1997-1999 Dag Brattli , @@ -116,15 +116,17 @@ 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, diff -u --recursive --new-file v2.3.35/linux/include/net/irda/irlmp_frame.h linux/include/net/irda/irlmp_frame.h --- v2.3.35/linux/include/net/irda/irlmp_frame.h Wed Dec 29 13:13:21 1999 +++ linux/include/net/irda/irlmp_frame.h Tue Jan 4 09:41:45 2000 @@ -26,6 +26,7 @@ #ifndef IRMLP_FRAME_H #define IRMLP_FRAME_H +#include #include #include diff -u --recursive --new-file v2.3.35/linux/include/pcmcia/ss.h linux/include/pcmcia/ss.h --- v2.3.35/linux/include/pcmcia/ss.h Wed Dec 29 13:13:21 1999 +++ linux/include/pcmcia/ss.h Mon Jan 3 16:34:39 2000 @@ -52,8 +52,7 @@ u_int irq_mask; u_int map_size; u_char pci_irq; - u_char cardbus; - struct pci_bus *cb_bus; + struct pci_dev *cb_dev; struct bus_operations *bus; } socket_cap_t; @@ -72,6 +71,8 @@ u_char io_irq; } socket_state_t; +extern socket_state_t dead_socket; + /* Socket configuration flags */ #define SS_PWR_AUTO 0x0010 #define SS_IOCARD 0x0020 @@ -118,6 +119,8 @@ * Socket operations. */ struct pccard_operations { + int (*init)(unsigned int sock); + int (*suspend)(unsigned int sock); int (*register_callback)(unsigned int sock, void (*handler)(void *, unsigned int), void * info); int (*inquire_socket)(unsigned int sock, socket_cap_t *cap); int (*get_status)(unsigned int sock, u_int *value); @@ -127,8 +130,6 @@ int (*set_io_map)(unsigned int sock, struct pccard_io_map *io); int (*get_mem_map)(unsigned int sock, struct pccard_mem_map *mem); int (*set_mem_map)(unsigned int sock, struct pccard_mem_map *mem); - int (*get_bridge)(unsigned int sock, struct cb_bridge_map *m); - int (*set_bridge)(unsigned int sock, struct cb_bridge_map *m); void (*proc_setup)(unsigned int sock, struct proc_dir_entry *base); }; diff -u --recursive --new-file v2.3.35/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.3.35/linux/kernel/ksyms.c Tue Dec 14 01:27:24 1999 +++ linux/kernel/ksyms.c Tue Jan 4 13:02:23 2000 @@ -225,6 +225,13 @@ EXPORT_SYMBOL(page_follow_link); EXPORT_SYMBOL(block_symlink); +/* for stackable file systems (lofs, wrapfs, etc.) */ +EXPORT_SYMBOL(add_to_page_cache); +EXPORT_SYMBOL(filemap_nopage); +EXPORT_SYMBOL(filemap_swapout); +EXPORT_SYMBOL(filemap_sync); +EXPORT_SYMBOL(remove_inode_page); + #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) EXPORT_SYMBOL(do_nfsservctl); #endif @@ -410,10 +417,7 @@ EXPORT_SYMBOL(nr_async_pages); EXPORT_SYMBOL(___strtok); EXPORT_SYMBOL(init_special_inode); -EXPORT_SYMBOL(init_fifo); EXPORT_SYMBOL(fifo_inode_operations); -EXPORT_SYMBOL(chrdev_inode_operations); -EXPORT_SYMBOL(blkdev_inode_operations); EXPORT_SYMBOL(read_ahead); EXPORT_SYMBOL(get_hash_table); EXPORT_SYMBOL(get_empty_inode); @@ -450,4 +454,5 @@ /* library functions */ EXPORT_SYMBOL(strnicmp); +/* init task, for moving kthread roots - ought to export a function ?? */ EXPORT_SYMBOL(init_task_union); diff -u --recursive --new-file v2.3.35/linux/kernel/sched.c linux/kernel/sched.c --- v2.3.35/linux/kernel/sched.c Tue Dec 14 01:27:24 1999 +++ linux/kernel/sched.c Wed Dec 29 10:34:44 1999 @@ -273,6 +273,7 @@ tsk = cpu_curr(this_cpu); if (preemption_goodness(tsk, p, this_cpu) > 0) tsk->need_resched = 1; + spin_unlock_irqrestore(&runqueue_lock, flags); #endif } diff -u --recursive --new-file v2.3.35/linux/mm/filemap.c linux/mm/filemap.c --- v2.3.35/linux/mm/filemap.c Mon Dec 20 18:48:22 1999 +++ linux/mm/filemap.c Sun Jan 2 00:48:58 2000 @@ -1298,7 +1298,7 @@ * it in the page cache, and handles the special cases reasonably without * having a lot of duplicated code. */ -static struct page * filemap_nopage(struct vm_area_struct * area, +struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address, int no_share) { int error; @@ -1595,7 +1595,7 @@ return error; } -static int filemap_sync(struct vm_area_struct * vma, unsigned long address, +int filemap_sync(struct vm_area_struct * vma, unsigned long address, size_t size, unsigned int flags) { pgd_t * dir; diff -u --recursive --new-file v2.3.35/linux/mm/highmem.c linux/mm/highmem.c --- v2.3.35/linux/mm/highmem.c Tue Dec 7 09:32:52 1999 +++ linux/mm/highmem.c Wed Dec 29 10:35:35 1999 @@ -331,7 +331,7 @@ } 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; diff -u --recursive --new-file v2.3.35/linux/mm/memory.c linux/mm/memory.c --- v2.3.35/linux/mm/memory.c Tue Dec 14 01:27:24 1999 +++ linux/mm/memory.c Wed Dec 29 11:42:07 1999 @@ -712,43 +712,6 @@ } /* - * 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 * and decrementing the shared-page counter for the old page. diff -u --recursive --new-file v2.3.35/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.3.35/linux/net/bridge/br.c Wed Dec 29 13:13:21 1999 +++ linux/net/bridge/br.c Sun Jan 2 00:48:58 2000 @@ -87,6 +87,7 @@ #include #include #include +#include #ifndef min #define min(a, b) (((a) <= (b)) ? (a) : (b)) @@ -2425,7 +2426,7 @@ /* 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! */ diff -u --recursive --new-file v2.3.35/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.3.35/linux/net/core/skbuff.c Wed Dec 29 13:13:21 1999 +++ linux/net/core/skbuff.c Mon Jan 3 12:01:31 2000 @@ -4,7 +4,7 @@ * Authors: Alan Cox * Florian La Roche * - * Version: $Id: skbuff.c,v 1.62 1999/12/23 02:13:42 davem Exp $ + * Version: $Id: skbuff.c,v 1.63 2000/01/02 09:15:17 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -358,8 +358,9 @@ /* Set the tail pointer and length */ skb_put(n,skb->len); - /* Copy the bytes: data pointers must point to same data. */ - memcpy(n->data - skb_headroom(skb), skb->head, skb->end-skb->head); + + /* Copy the data only. */ + memcpy(n->data, skb->data, skb->len); copy_skb_header(n, skb); return n; diff -u --recursive --new-file v2.3.35/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.3.35/linux/net/ipv6/tcp_ipv6.c Wed Dec 29 13:13:21 1999 +++ linux/net/ipv6/tcp_ipv6.c Mon Jan 3 12:01:31 2000 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.113 1999/12/15 22:39:58 davem Exp $ + * $Id: tcp_ipv6.c,v 1.114 2000/01/03 17:19:17 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -273,8 +273,8 @@ } } } - if (sk) - sock_hold(sk); + if (result) + sock_hold(result); read_unlock(&tcp_lhash_lock); return result; } @@ -730,7 +730,6 @@ if (dst == NULL) { struct flowi fl; - struct dst_entry *dst; /* BUGGG_FUTURE: Again, it is not clear how to handle rthdr case. Ignore this complexity diff -u --recursive --new-file v2.3.35/linux/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.3.35/linux/net/irda/af_irda.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/af_irda.c Tue Jan 4 09:41:45 2000 @@ -42,6 +42,7 @@ * ********************************************************************/ +#include #include #include #include @@ -1604,7 +1605,7 @@ 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; @@ -1676,7 +1677,7 @@ 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; @@ -1904,7 +1905,7 @@ 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)) diff -u --recursive --new-file v2.3.35/linux/net/irda/ircomm/ircomm_core.c linux/net/irda/ircomm/ircomm_core.c --- v2.3.35/linux/net/irda/ircomm/ircomm_core.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/ircomm/ircomm_core.c Wed Dec 29 17:08:55 1999 @@ -148,9 +148,10 @@ 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) { diff -u --recursive --new-file v2.3.35/linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c --- v2.3.35/linux/net/irda/ircomm/ircomm_tty.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/ircomm/ircomm_tty.c Wed Dec 29 17:08:55 1999 @@ -1115,10 +1115,16 @@ /* * 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); } /* diff -u --recursive --new-file v2.3.35/linux/net/irda/irda_device.c linux/net/irda/irda_device.c --- v2.3.35/linux/net/irda/irda_device.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/irda_device.c Wed Dec 29 17:08:55 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Oct 9 09:22:27 1999 - * Modified at: Sun Dec 12 12:24:32 1999 + * Modified at: Tue Dec 21 21:53:45 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -419,7 +419,7 @@ 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; diff -u --recursive --new-file v2.3.35/linux/net/irda/iriap.c linux/net/irda/iriap.c --- v2.3.35/linux/net/irda/iriap.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/iriap.c Wed Dec 29 17:08:55 1999 @@ -150,7 +150,7 @@ { struct iriap_cb *self; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, __FUNCTION__ "()\n"); self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC); if (!self) { @@ -199,6 +199,9 @@ del_timer(&self->watchdog_timer); + if (self->skb) + dev_kfree_skb(self->skb); + self->magic = 0; kfree(self); @@ -213,7 +216,7 @@ { struct iriap_cb *entry; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); @@ -233,7 +236,7 @@ { notify_t notify; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, __FUNCTION__ "()\n"); irda_notify_init(¬ify); notify.connect_confirm = iriap_connect_confirm; @@ -296,6 +299,7 @@ IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as server\n"); iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, NULL); + iriap_close(self); } if (userdata) @@ -609,8 +613,6 @@ break; } iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb); - - iriap_close(self); } /* @@ -648,16 +650,14 @@ 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; @@ -666,20 +666,16 @@ 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; } diff -u --recursive --new-file v2.3.35/linux/net/irda/iriap_event.c linux/net/irda/iriap_event.c --- v2.3.35/linux/net/irda/iriap_event.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/iriap_event.c Wed Dec 29 17:08:55 1999 @@ -176,6 +176,7 @@ 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, diff -u --recursive --new-file v2.3.35/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c --- v2.3.35/linux/net/irda/irlap_event.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/irlap_event.c Wed Dec 29 17:08:55 1999 @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: irlap_event.c - * Version: 0.8 + * Version: 0.9 * Description: IrLAP state machine implementation * Status: Experimental. * Author: Dag Brattli * 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 * * Copyright (c) 1998-1999 Dag Brattli , @@ -93,14 +93,20 @@ "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", @@ -348,9 +354,8 @@ 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; @@ -792,14 +797,14 @@ 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]); @@ -949,7 +954,8 @@ 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); @@ -970,9 +976,7 @@ } 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); @@ -1268,12 +1272,7 @@ } 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 */ @@ -1302,7 +1301,9 @@ * 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)); @@ -1348,28 +1349,38 @@ 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); @@ -1446,7 +1457,7 @@ 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); @@ -1510,7 +1521,6 @@ } else { IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame contained an I field!\n"); - } dev_kfree_skb(skb); break; @@ -1594,6 +1604,12 @@ 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]); @@ -1655,8 +1671,9 @@ * 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); @@ -1870,6 +1887,26 @@ } 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/ @@ -1896,7 +1933,7 @@ 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); @@ -1951,10 +1988,50 @@ 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; } @@ -1980,14 +2057,14 @@ 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); diff -u --recursive --new-file v2.3.35/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c --- v2.3.35/linux/net/irda/irlap_frame.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/irlap_frame.c Wed Dec 29 17:08:55 1999 @@ -6,7 +6,7 @@ * Status: Stable * Author: Dag Brattli * 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 * * Copyright (c) 1998-1999 Dag Brattli , @@ -66,7 +66,7 @@ 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; @@ -571,6 +571,29 @@ } /* + * 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) * * Received RR (Receive Ready) frame from peer station, no harm in @@ -625,16 +648,56 @@ * */ 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); } /* @@ -643,8 +706,9 @@ * 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); } @@ -691,7 +755,7 @@ 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; } @@ -872,13 +936,11 @@ /* * 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; @@ -890,10 +952,9 @@ /* 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); @@ -903,13 +964,9 @@ */ /* 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; @@ -938,16 +995,15 @@ * 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"); @@ -969,6 +1025,52 @@ } } } +#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); + } } /* @@ -1069,7 +1171,7 @@ 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; @@ -1145,8 +1247,8 @@ * 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; @@ -1243,15 +1345,13 @@ 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__ @@ -1276,12 +1376,10 @@ 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); diff -u --recursive --new-file v2.3.35/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c --- v2.3.35/linux/net/irda/irlmp_event.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/irlmp_event.c Tue Jan 4 09:41:45 2000 @@ -23,6 +23,7 @@ * ********************************************************************/ +#include #include #include diff -u --recursive --new-file v2.3.35/linux/net/irda/irmod.c linux/net/irda/irmod.c --- v2.3.35/linux/net/irda/irmod.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/irmod.c Wed Dec 29 17:08:55 1999 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * 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 * * Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved. @@ -212,7 +212,7 @@ 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(); diff -u --recursive --new-file v2.3.35/linux/net/irda/irttp.c linux/net/irda/irttp.c --- v2.3.35/linux/net/irda/irttp.c Wed Dec 29 13:13:21 1999 +++ linux/net/irda/irttp.c Wed Dec 29 17:08:55 1999 @@ -1111,13 +1111,22 @@ 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); - } } /* @@ -1130,6 +1139,12 @@ void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *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); diff -u --recursive --new-file v2.3.35/linux/net/netsyms.c linux/net/netsyms.c --- v2.3.35/linux/net/netsyms.c Wed Dec 29 13:13:21 1999 +++ linux/net/netsyms.c Mon Jan 3 12:01:31 2000 @@ -580,6 +580,7 @@ EXPORT_SYMBOL(nf_register_interest); EXPORT_SYMBOL(nf_unregister_interest); EXPORT_SYMBOL(nf_hook_slow); +EXPORT_SYMBOL(nf_hooks); #endif EXPORT_SYMBOL(register_gifconf);